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

Compare commits

...

59 Commits

Author SHA1 Message Date
Junyoung Choi
d015b18c66 Revert flickering fix 2018-09-01 16:50:52 +09:00
Junyoung Choi
039f73711a Update yarn.lock 2018-08-20 15:22:28 +09:00
Junyoung Choi (Sai)
6e885acf8c Merge pull request #2311 from BoostIO/update-build-document
Update build documents
2018-08-20 15:20:31 +09:00
Junyoung Choi
9ef07cea7a Update build documents 2018-08-20 15:19:40 +09:00
Junyoung Choi (Sai)
9e3b321aaf Merge pull request #2216 from ZeroX-DG/improve-dev-script
Improved dev script
2018-08-20 15:05:21 +09:00
Junyoung Choi (Sai)
21560701ea Merge pull request #2303 from daiyam/update-electron
update electron version
2018-08-20 14:58:49 +09:00
Junyoung Choi (Sai)
4556375174 Merge pull request #2284 from mikaoelitiana/feat-933
Add per-folder sort
2018-08-20 13:46:03 +09:00
Junyoung Choi (Sai)
91b5398b5a Merge pull request #2307 from modmod24/fix-todo-percentage
update todo percentage correctly #2267
2018-08-20 12:00:42 +09:00
Junyoung Choi (Sai)
eeb8016992 Merge pull request #2302 from daiyam/window-position
restore window position
2018-08-20 11:57:47 +09:00
Junyoung Choi (Sai)
736106be3a Merge pull request #2283 from ZeroX-DG/fix-snippet-list-bug
Fixed snippet list bug
2018-08-20 10:35:06 +09:00
Junyoung Choi (Sai)
f400568dc0 Merge pull request #2272 from ZeroX-DG/improve-theme
Improve sideNav scroll bar color
2018-08-20 10:24:48 +09:00
Junyoung Choi (Sai)
0ca96cba6e Merge pull request #2074 from max-buranbaev/blinking-markdown-crunch-fix
Blinking markdown crunch fix
2018-08-20 10:05:06 +09:00
Unknown
df4d837026 add todo status test 2018-08-18 14:38:07 +01:00
Unknown
760f84d7fa fix for 2267
todo percentage not updated correctly
2018-08-18 14:30:23 +01:00
Baptiste Augrain
174a315e3f update electron version 2018-08-16 01:23:35 +02:00
Baptiste Augrain
0834313456 restore window position 2018-08-16 01:06:13 +02:00
Unknown
df931e10c0 Merge remote-tracking branch 'BoostIO/master' 2018-08-12 17:53:03 +01:00
Mika Andrianarijaona
9572cb2d33 Fix default value of config.sortBy 2018-08-12 09:21:46 +02:00
Max Buranbaev
51e836f32a code style 2018-08-11 16:17:56 +05:00
Max Buranbaev
7fefbd88d0 Resolving conflict 2018-08-11 11:13:04 +00:00
Mika Andrianarijaona
cb956c5508 Use default value config.sortBy
- for new folders
- for folders with no config set
2018-08-11 11:44:22 +02:00
Mika Andrianarijaona
47b0086bf8 Add per-folder sort
- save sort configuration in `config.[folderKey].sortBy`
- use lodash ` _.get(config, [folderKey, 'sortBy'])` to avoid error
2018-08-11 11:36:36 +02:00
Nguyễn Việt Hưng
b8d66e4a95 fixed snippet list bug 2018-08-11 09:20:04 +07:00
Max Buranbaev
bfc1c93153 Merge branch 'master' into blinking-markdown-crunch-fix 2018-08-10 19:02:43 +05:00
Nguyễn Việt Hưng
404faf8a0b limited style for just side nav 2018-08-09 22:59:40 +07:00
Nguyễn Việt Hưng
4a7b0f4711 improved scroll bar color for default theme 2018-08-09 22:57:16 +07:00
Nguyen Viet Hung
dd62fca45d change dev-start to dev 2018-08-09 16:21:27 +07:00
Junyoung Choi (Sai)
79fb04126c Merge pull request #2214 from cdayjr/master
Fix for BoostIO/Boostnote#2204
2018-08-09 18:15:20 +09:00
Junyoung Choi (Sai)
39c9574ae3 Merge pull request #2257 from ehhc/Attachments_in_markdown_export_#1786
might fixes #1786 --> export attachments for markdown notes
2018-08-09 18:10:48 +09:00
Junyoung Choi (Sai)
38af257adf Merge pull request #2253 from mbarczak/master
Fix for issue #2088 :  snippet notes are not displaying in markdown
2018-08-09 18:07:29 +09:00
Junyoung Choi (Sai)
5aae9a4722 Merge pull request #2231 from yougotwill/mermaid_dark_theme_fix
Mermaid dark theme rendering fix
2018-08-09 17:54:54 +09:00
Junyoung Choi (Sai)
cfe3cae88d Merge pull request #2226 from sklein12/addSnippetToSearchScope
Add code snippets to search scope
2018-08-09 17:54:28 +09:00
Junyoung Choi (Sai)
612de84ac6 Merge pull request #2208 from enyaxu/feature/2132
New Feature: Shortcuts for focusing tag editor(CmdOrControl+Shift+T)(#2132)
2018-08-09 17:53:54 +09:00
Nguyen Viet Hung
33be597ef0 Delete package-lock.json 2018-08-09 15:50:07 +07:00
Junyoung Choi (Sai)
cc26fd80d7 Merge pull request #2235 from amedora/feature/1454-ditaa
add Ditaa support
2018-08-09 17:47:37 +09:00
Junyoung Choi (Sai)
c227a1ffec Merge pull request #2171 from yamash723/fixbug-html-export
Fix search value for html export path
2018-08-09 17:43:56 +09:00
Nguyen Viet Hung
f0df787bbe Fix escape codeblock (#2230)
* updated package-lock

* added fix and test for escape html in code block

* fixed markdown preview render bug

* updated comment in escape function

* improved escape function

* Delete package-lock.json
2018-08-09 17:08:52 +09:00
ehhc
09188bed48 might fixes #1786 --> export attachments for markdown notes 2018-07-30 18:09:02 +02:00
Maciek
4a3bcaba06 BUG FIX: Change the way of checking for empty array
The original condition : attachments !== [] always returns true,
for empty array, as well as for array with elements.
2018-07-28 22:25:10 +02:00
Maciek
1d1ab65edd BUG FIX: snippet notes are not displaying in markdown #2088
Fix for issue https://github.com/BoostIo/Boostnote/issues/2088.
In specific situation, when all below conditions are met :
- one of the snippets notes tabs is a Markdown tab,
- the migrateAttachments code is called on a snippet note,
- historical attachments location '/images' exists in snippet storage
  folder

Following exception is being thrown :
path.js:28 Uncaught TypeError: Path must be a string. Received undefined
The exception is a result of an undefined noteKey variable
(which is defined only for Markdown notes).
The solution is to skip migration of attachments for notes without
noteKey (which wouldn't be possible anyway, since noteKey is a
necessary for creating folder for attachments).
2018-07-28 22:23:14 +02:00
Junyoung Choi (Sai)
7330cdaf1c Merge pull request #2209 from yougotwill/info_box_fix
Trash infoPanel Fix
2018-07-28 23:34:46 +09:00
Junyoung Choi (Sai)
050a1fb6cf Merge pull request #2239 from narukami894/improve_jp_build_md
add and improve translation, fix typo
2018-07-28 23:33:56 +09:00
narukami894
1e8397cf17 add and improve translation, fix typo 2018-07-24 16:01:41 +09:00
amedora
59b53ece2b add Ditaa support (resolve #1454) 2018-07-23 11:16:20 +09:00
William Grant
16c62cd46f changed double quotes to single quotes 2018-07-21 19:31:40 +10:00
William Grant
eff56c2514 mermaid diagram rendering for dark themes is now fixed 2018-07-21 19:20:20 +10:00
yamash723
ee6b9a223f Change output path format of html file by platform 2018-07-21 15:25:09 +09:00
Chad Wade Day, Jr
acc6ea434a Merge remote-tracking branch 'upstream/master' 2018-07-20 11:45:36 -07:00
Steve Klein
1e5a7356f4 Add code snippets to search scope 2018-07-20 02:00:11 -07:00
Nguyễn Việt Hưng
4c8342c19d updated dev script 2018-07-19 17:04:55 +07:00
Nguyễn Việt Hưng
dad5232ecb updated package-lock 2018-07-19 16:55:19 +07:00
Chad Wade Day, Jr
be972781ee Fix for BoostIO/Boostnote#2204 2018-07-18 11:58:54 -07:00
William Grant
58fbc298b1 Merge branch 'master' into info_box_fix 2018-07-17 14:41:45 +02:00
William Grant
7de7772339 Fixed infoButton panel in trash positioning 2018-07-17 14:41:22 +02:00
JianXu
ad847a2f5d New Feature: Shortcuts for focusing tag editor(CmdOrControl+T) 2018-07-17 17:19:03 +08:00
yamash723
4f79f52524 Fix search value for html export path 2018-07-03 10:03:31 +09:00
Max Buranbaev
2c7f24cb8c Debouncing of rendering due to flickering fix 2018-06-28 13:03:12 +05:00
Max Buranbaev
398ebae2ba Merge branch 'master' into blinking-markdown-crunch-fix 2018-06-27 14:21:34 +00:00
Max Buranbaev
5de176757d Fixing flickering in both cases 2018-06-27 13:07:38 +05:00
40 changed files with 1240 additions and 746 deletions

View File

@@ -22,7 +22,9 @@
"fontSize": "14", "fontSize": "14",
"lineNumber": true "lineNumber": true
}, },
"sortBy": "UPDATED_AT", "sortBy": {
"default": "UPDATED_AT"
},
"sortTagsBy": "ALPHABETICAL", "sortTagsBy": "ALPHABETICAL",
"ui": { "ui": {
"defaultNote": "ALWAYS_ASK", "defaultNote": "ALWAYS_ASK",

View File

@@ -18,14 +18,17 @@ import normalizeEditorFontFamily from 'browser/lib/normalizeEditorFontFamily'
CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js' CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js'
const buildCMRulers = (rulers, enableRulers) => const buildCMRulers = (rulers, enableRulers) =>
enableRulers ? rulers.map(ruler => ({column: ruler})) : [] (enableRulers ? rulers.map(ruler => ({ column: ruler })) : [])
export default class CodeEditor extends React.Component { export default class CodeEditor extends React.Component {
constructor (props) { constructor (props) {
super(props) super(props)
this.scrollHandler = _.debounce(this.handleScroll.bind(this), 100, {leading: false, trailing: true}) this.scrollHandler = _.debounce(this.handleScroll.bind(this), 100, {
this.changeHandler = (e) => this.handleChange(e) leading: false,
trailing: true
})
this.changeHandler = e => this.handleChange(e)
this.focusHandler = () => { this.focusHandler = () => {
ipcRenderer.send('editor:focused', true) ipcRenderer.send('editor:focused', true)
} }
@@ -41,11 +44,15 @@ export default class CodeEditor extends React.Component {
} }
this.props.onBlur != null && this.props.onBlur(e) this.props.onBlur != null && this.props.onBlur(e)
const {storageKey, noteKey} = this.props const { storageKey, noteKey } = this.props
attachmentManagement.deleteAttachmentsNotPresentInNote(this.editor.getValue(), storageKey, noteKey) attachmentManagement.deleteAttachmentsNotPresentInNote(
this.editor.getValue(),
storageKey,
noteKey
)
} }
this.pasteHandler = (editor, e) => this.handlePaste(editor, e) this.pasteHandler = (editor, e) => this.handlePaste(editor, e)
this.loadStyleHandler = (e) => { this.loadStyleHandler = e => {
this.editor.refresh() this.editor.refresh()
} }
this.searchHandler = (e, msg) => this.handleSearch(msg) this.searchHandler = (e, msg) => this.handleSearch(msg)
@@ -66,7 +73,10 @@ export default class CodeEditor extends React.Component {
cm.addOverlay(component.searchState) cm.addOverlay(component.searchState)
function makeOverlay (query, style) { function makeOverlay (query, style) {
query = new RegExp(query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'), 'gi') query = new RegExp(
query.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, '\\$&'),
'gi'
)
return { return {
token: function (stream) { token: function (stream) {
query.lastIndex = stream.pos query.lastIndex = stream.pos
@@ -102,7 +112,11 @@ export default class CodeEditor extends React.Component {
} }
] ]
if (!fs.existsSync(consts.SNIPPET_FILE)) { if (!fs.existsSync(consts.SNIPPET_FILE)) {
fs.writeFileSync(consts.SNIPPET_FILE, JSON.stringify(defaultSnippet, null, 4), 'utf8') fs.writeFileSync(
consts.SNIPPET_FILE,
JSON.stringify(defaultSnippet, null, 4),
'utf8'
)
} }
this.value = this.props.value this.value = this.props.value
@@ -144,9 +158,14 @@ export default class CodeEditor extends React.Component {
cm.execCommand('insertSoftTab') cm.execCommand('insertSoftTab')
} }
cm.execCommand('goLineEnd') cm.execCommand('goLineEnd')
} else if (!charBeforeCursor.match(/\t|\s|\r|\n/) && cursor.ch > 1) { } else if (
!charBeforeCursor.match(/\t|\s|\r|\n/) &&
cursor.ch > 1
) {
// text expansion on tab key if the char before is alphabet // text expansion on tab key if the char before is alphabet
const snippets = JSON.parse(fs.readFileSync(consts.SNIPPET_FILE, 'utf8')) const snippets = JSON.parse(
fs.readFileSync(consts.SNIPPET_FILE, 'utf8')
)
if (expandSnippet(line, cursor, cm, snippets) === false) { if (expandSnippet(line, cursor, cm, snippets) === false) {
if (tabs) { if (tabs) {
cm.execCommand('insertTab') cm.execCommand('insertTab')
@@ -167,7 +186,7 @@ export default class CodeEditor extends React.Component {
// Do nothing // Do nothing
}, },
Enter: 'boostNewLineAndIndentContinueMarkdownList', Enter: 'boostNewLineAndIndentContinueMarkdownList',
'Ctrl-C': (cm) => { 'Ctrl-C': cm => {
if (cm.getOption('keyMap').substr(0, 3) === 'vim') { if (cm.getOption('keyMap').substr(0, 3) === 'vim') {
document.execCommand('copy') document.execCommand('copy')
} }
@@ -201,7 +220,11 @@ export default class CodeEditor extends React.Component {
} }
expandSnippet (line, cursor, cm, snippets) { expandSnippet (line, cursor, cm, snippets) {
const wordBeforeCursor = this.getWordBeforeCursor(line, cursor.line, cursor.ch) const wordBeforeCursor = this.getWordBeforeCursor(
line,
cursor.line,
cursor.ch
)
const templateCursorString = ':{}' const templateCursorString = ':{}'
for (let i = 0; i < snippets.length; i++) { for (let i = 0; i < snippets.length; i++) {
if (snippets[i].prefix.indexOf(wordBeforeCursor.text) !== -1) { if (snippets[i].prefix.indexOf(wordBeforeCursor.text) !== -1) {
@@ -219,7 +242,10 @@ export default class CodeEditor extends React.Component {
wordBeforeCursor.range.from, wordBeforeCursor.range.from,
wordBeforeCursor.range.to wordBeforeCursor.range.to
) )
cm.setCursor({ line: cursor.line + cursorLineNumber, ch: cursorLinePosition }) cm.setCursor({
line: cursor.line + cursorLineNumber,
ch: cursorLinePosition
})
} }
} }
} else { } else {
@@ -261,8 +287,8 @@ export default class CodeEditor extends React.Component {
return { return {
text: wordBeforeCursor, text: wordBeforeCursor,
range: { range: {
from: {line: lineNumber, ch: originCursorPosition}, from: { line: lineNumber, ch: originCursorPosition },
to: {line: lineNumber, ch: cursorPosition} to: { line: lineNumber, ch: cursorPosition }
} }
} }
} }
@@ -286,7 +312,7 @@ export default class CodeEditor extends React.Component {
componentDidUpdate (prevProps, prevState) { componentDidUpdate (prevProps, prevState) {
let needRefresh = false let needRefresh = false
const {rulers, enableRulers} = this.props const { rulers, enableRulers } = this.props
if (prevProps.mode !== this.props.mode) { if (prevProps.mode !== this.props.mode) {
this.setMode(this.props.mode) this.setMode(this.props.mode)
} }
@@ -304,7 +330,10 @@ export default class CodeEditor extends React.Component {
needRefresh = true needRefresh = true
} }
if (prevProps.enableRulers !== enableRulers || prevProps.rulers !== rulers) { if (
prevProps.enableRulers !== enableRulers ||
prevProps.rulers !== rulers
) {
this.editor.setOption('rulers', buildCMRulers(rulers, enableRulers)) this.editor.setOption('rulers', buildCMRulers(rulers, enableRulers))
} }
@@ -344,11 +373,9 @@ export default class CodeEditor extends React.Component {
} }
} }
moveCursorTo (row, col) { moveCursorTo (row, col) {}
}
scrollToLine (num) { scrollToLine (num) {}
}
focus () { focus () {
this.editor.focus() this.editor.focus()
@@ -376,8 +403,13 @@ export default class CodeEditor extends React.Component {
handleDropImage (dropEvent) { handleDropImage (dropEvent) {
dropEvent.preventDefault() dropEvent.preventDefault()
const {storageKey, noteKey} = this.props const { storageKey, noteKey } = this.props
attachmentManagement.handleAttachmentDrop(this, storageKey, noteKey, dropEvent) attachmentManagement.handleAttachmentDrop(
this,
storageKey,
noteKey,
dropEvent
)
} }
insertAttachmentMd (imageMd) { insertAttachmentMd (imageMd) {
@@ -386,34 +418,44 @@ export default class CodeEditor extends React.Component {
handlePaste (editor, e) { handlePaste (editor, e) {
const clipboardData = e.clipboardData const clipboardData = e.clipboardData
const {storageKey, noteKey} = this.props const { storageKey, noteKey } = this.props
const dataTransferItem = clipboardData.items[0] const dataTransferItem = clipboardData.items[0]
const pastedTxt = clipboardData.getData('text') const pastedTxt = clipboardData.getData('text')
const isURL = (str) => { const isURL = str => {
const matcher = /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/ const matcher = /^(?:\w+:)?\/\/([^\s\.]+\.\S{2}|localhost[\:?\d]*)\S*$/
return matcher.test(str) return matcher.test(str)
} }
const isInLinkTag = (editor) => { const isInLinkTag = editor => {
const startCursor = editor.getCursor('start') const startCursor = editor.getCursor('start')
const prevChar = editor.getRange( const prevChar = editor.getRange(
{line: startCursor.line, ch: startCursor.ch - 2}, { line: startCursor.line, ch: startCursor.ch - 2 },
{line: startCursor.line, ch: startCursor.ch} { line: startCursor.line, ch: startCursor.ch }
) )
const endCursor = editor.getCursor('end') const endCursor = editor.getCursor('end')
const nextChar = editor.getRange( const nextChar = editor.getRange(
{line: endCursor.line, ch: endCursor.ch}, { line: endCursor.line, ch: endCursor.ch },
{line: endCursor.line, ch: endCursor.ch + 1} { line: endCursor.line, ch: endCursor.ch + 1 }
) )
return prevChar === '](' && nextChar === ')' return prevChar === '](' && nextChar === ')'
} }
if (dataTransferItem.type.match('image')) { if (dataTransferItem.type.match('image')) {
attachmentManagement.handlePastImageEvent(this, storageKey, noteKey, dataTransferItem) attachmentManagement.handlePastImageEvent(
} else if (this.props.fetchUrlTitle && isURL(pastedTxt) && !isInLinkTag(editor)) { this,
storageKey,
noteKey,
dataTransferItem
)
} else if (
this.props.fetchUrlTitle &&
isURL(pastedTxt) &&
!isInLinkTag(editor)
) {
this.handlePasteUrl(e, editor, pastedTxt) this.handlePasteUrl(e, editor, pastedTxt)
} }
if (attachmentManagement.isAttachmentLink(pastedTxt)) { if (attachmentManagement.isAttachmentLink(pastedTxt)) {
attachmentManagement.handleAttachmentLinkPaste(storageKey, noteKey, pastedTxt) attachmentManagement
.then((modifiedText) => { .handleAttachmentLinkPaste(storageKey, noteKey, pastedTxt)
.then(modifiedText => {
this.editor.replaceSelection(modifiedText) this.editor.replaceSelection(modifiedText)
}) })
e.preventDefault() e.preventDefault()
@@ -431,39 +473,49 @@ export default class CodeEditor extends React.Component {
const taggedUrl = `<${pastedTxt}>` const taggedUrl = `<${pastedTxt}>`
editor.replaceSelection(taggedUrl) editor.replaceSelection(taggedUrl)
const isImageReponse = (response) => { const isImageReponse = response => {
return response.headers.has('content-type') && return (
response.headers.has('content-type') &&
response.headers.get('content-type').match(/^image\/.+$/) response.headers.get('content-type').match(/^image\/.+$/)
)
} }
const replaceTaggedUrl = (replacement) => { const replaceTaggedUrl = replacement => {
const value = editor.getValue() const value = editor.getValue()
const cursor = editor.getCursor() const cursor = editor.getCursor()
const newValue = value.replace(taggedUrl, replacement) const newValue = value.replace(taggedUrl, replacement)
const newCursor = Object.assign({}, cursor, { ch: cursor.ch + newValue.length - value.length }) const newCursor = Object.assign({}, cursor, {
ch: cursor.ch + newValue.length - value.length
})
editor.setValue(newValue) editor.setValue(newValue)
editor.setCursor(newCursor) editor.setCursor(newCursor)
} }
fetch(pastedTxt, { fetch(pastedTxt, {
method: 'get' method: 'get'
}).then((response) => {
if (isImageReponse(response)) {
return this.mapImageResponse(response, pastedTxt)
} else {
return this.mapNormalResponse(response, pastedTxt)
}
}).then((replacement) => {
replaceTaggedUrl(replacement)
}).catch((e) => {
replaceTaggedUrl(pastedTxt)
}) })
.then(response => {
if (isImageReponse(response)) {
return this.mapImageResponse(response, pastedTxt)
} else {
return this.mapNormalResponse(response, pastedTxt)
}
})
.then(replacement => {
replaceTaggedUrl(replacement)
})
.catch(e => {
replaceTaggedUrl(pastedTxt)
})
} }
mapNormalResponse (response, pastedTxt) { mapNormalResponse (response, pastedTxt) {
return this.decodeResponse(response).then((body) => { return this.decodeResponse(response).then(body => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
try { try {
const parsedBody = (new window.DOMParser()).parseFromString(body, 'text/html') const parsedBody = new window.DOMParser().parseFromString(
body,
'text/html'
)
const linkWithTitle = `[${parsedBody.title}](${pastedTxt})` const linkWithTitle = `[${parsedBody.title}](${pastedTxt})`
resolve(linkWithTitle) resolve(linkWithTitle)
} catch (e) { } catch (e) {
@@ -491,10 +543,13 @@ export default class CodeEditor extends React.Component {
const _charset = headers.has('content-type') const _charset = headers.has('content-type')
? this.extractContentTypeCharset(headers.get('content-type')) ? this.extractContentTypeCharset(headers.get('content-type'))
: undefined : undefined
return response.arrayBuffer().then((buff) => { return response.arrayBuffer().then(buff => {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
try { try {
const charset = _charset !== undefined && iconv.encodingExists(_charset) ? _charset : 'utf-8' const charset = _charset !== undefined &&
iconv.encodingExists(_charset)
? _charset
: 'utf-8'
resolve(iconv.decode(new Buffer(buff), charset).toString()) resolve(iconv.decode(new Buffer(buff), charset).toString())
} catch (e) { } catch (e) {
reject(e) reject(e)
@@ -504,11 +559,14 @@ export default class CodeEditor extends React.Component {
} }
extractContentTypeCharset (contentType) { extractContentTypeCharset (contentType) {
return contentType.split(';').filter((str) => { return contentType
return str.trim().toLowerCase().startsWith('charset') .split(';')
}).map((str) => { .filter(str => {
return str.replace(/['"]/g, '').split('=')[1] return str.trim().toLowerCase().startsWith('charset')
})[0] })
.map(str => {
return str.replace(/['"]/g, '').split('=')[1]
})[0]
} }
render () { render () {
@@ -517,10 +575,7 @@ export default class CodeEditor extends React.Component {
const width = this.props.width const width = this.props.width
return ( return (
<div <div
className={className == null className={className == null ? 'CodeEditor' : `CodeEditor ${className}`}
? 'CodeEditor'
: `CodeEditor ${className}`
}
ref='root' ref='root'
tabIndex='-1' tabIndex='-1'
style={{ style={{
@@ -528,7 +583,7 @@ export default class CodeEditor extends React.Component {
fontSize: fontSize, fontSize: fontSize,
width: width width: width
}} }}
onDrop={(e) => this.handleDropImage(e)} onDrop={e => this.handleDropImage(e)}
/> />
) )
} }

View File

@@ -28,15 +28,24 @@ const fileUrl = require('file-url')
const dialog = remote.dialog const dialog = remote.dialog
const markdownStyle = require('!!css!stylus?sourceMap!./markdown.styl')[0][1] const markdownStyle = require('!!css!stylus?sourceMap!./markdown.styl')[0][1]
const appPath = fileUrl(process.env.NODE_ENV === 'production' const appPath = fileUrl(
? app.getAppPath() process.env.NODE_ENV === 'production' ? app.getAppPath() : path.resolve()
: path.resolve()) )
const CSS_FILES = [ const CSS_FILES = [
`${appPath}/node_modules/katex/dist/katex.min.css`, `${appPath}/node_modules/katex/dist/katex.min.css`,
`${appPath}/node_modules/codemirror/lib/codemirror.css` `${appPath}/node_modules/codemirror/lib/codemirror.css`
] ]
function buildStyle (fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd, theme, allowCustomCSS, customCSS) { function buildStyle (
fontFamily,
fontSize,
codeBlockFontFamily,
lineNumber,
scrollPastEnd,
theme,
allowCustomCSS,
customCSS
) {
return ` return `
@font-face { @font-face {
font-family: 'Lato'; font-family: 'Lato';
@@ -160,17 +169,27 @@ if (!OSX) {
defaultFontFamily.unshift('Microsoft YaHei') defaultFontFamily.unshift('Microsoft YaHei')
defaultFontFamily.unshift('meiryo') defaultFontFamily.unshift('meiryo')
} }
const defaultCodeBlockFontFamily = ['Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'monospace'] const defaultCodeBlockFontFamily = [
'Monaco',
'Menlo',
'Ubuntu Mono',
'Consolas',
'source-code-pro',
'monospace'
]
export default class MarkdownPreview extends React.Component { export default class MarkdownPreview extends React.Component {
constructor (props) { constructor (props) {
super(props) super(props)
this.contextMenuHandler = (e) => this.handleContextMenu(e) this.contextMenuHandler = e => this.handleContextMenu(e)
this.mouseDownHandler = (e) => this.handleMouseDown(e) this.mouseDownHandler = e => this.handleMouseDown(e)
this.mouseUpHandler = (e) => this.handleMouseUp(e) this.mouseUpHandler = e => this.handleMouseUp(e)
this.DoubleClickHandler = (e) => this.handleDoubleClick(e) this.DoubleClickHandler = e => this.handleDoubleClick(e)
this.scrollHandler = _.debounce(this.handleScroll.bind(this), 100, {leading: false, trailing: true}) this.scrollHandler = _.debounce(this.handleScroll.bind(this), 100, {
this.checkboxClickHandler = (e) => this.handleCheckboxClick(e) leading: false,
trailing: true
})
this.checkboxClickHandler = e => this.handleCheckboxClick(e)
this.saveAsTextHandler = () => this.handleSaveAsText() this.saveAsTextHandler = () => this.handleSaveAsText()
this.saveAsMdHandler = () => this.handleSaveAsMd() this.saveAsMdHandler = () => this.handleSaveAsMd()
this.saveAsHtmlHandler = () => this.handleSaveAsHtml() this.saveAsHtmlHandler = () => this.handleSaveAsHtml()
@@ -232,36 +251,85 @@ export default class MarkdownPreview extends React.Component {
} }
handleSaveAsMd () { handleSaveAsMd () {
this.exportAsDocument('md') this.exportAsDocument('md', (noteContent, exportTasks) => {
let result = noteContent
if (this.props && this.props.storagePath && this.props.noteKey) {
const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent(
noteContent,
this.props.storagePath
)
attachmentsAbsolutePaths.forEach(attachment => {
exportTasks.push({
src: attachment,
dst: attachmentManagement.DESTINATION_FOLDER
})
})
result = attachmentManagement.removeStorageAndNoteReferences(
noteContent,
this.props.noteKey
)
}
return result
})
} }
handleSaveAsHtml () { handleSaveAsHtml () {
this.exportAsDocument('html', (noteContent, exportTasks) => { this.exportAsDocument('html', (noteContent, exportTasks) => {
const {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, scrollPastEnd, theme, allowCustomCSS, customCSS} = this.getStyleParams() const {
fontFamily,
const inlineStyles = buildStyle(fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd, theme, allowCustomCSS, customCSS) fontSize,
let body = this.markdown.render(escapeHtmlCharacters(noteContent, { detectCodeBlock: true })) codeBlockFontFamily,
lineNumber,
codeBlockTheme,
scrollPastEnd,
theme,
allowCustomCSS,
customCSS
} = this.getStyleParams()
const inlineStyles = buildStyle(
fontFamily,
fontSize,
codeBlockFontFamily,
lineNumber,
scrollPastEnd,
theme,
allowCustomCSS,
customCSS
)
let body = this.markdown.render(
escapeHtmlCharacters(noteContent, { detectCodeBlock: true })
)
const files = [this.GetCodeThemeLink(codeBlockTheme), ...CSS_FILES] const files = [this.GetCodeThemeLink(codeBlockTheme), ...CSS_FILES]
const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent(noteContent, this.props.storagePath) const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent(
noteContent,
this.props.storagePath
)
files.forEach((file) => { files.forEach(file => {
file = file.replace('file://', '') if (global.process.platform === 'win32') {
file = file.replace('file:///', '')
} else {
file = file.replace('file://', '')
}
exportTasks.push({ exportTasks.push({
src: file, src: file,
dst: 'css' dst: 'css'
}) })
}) })
attachmentsAbsolutePaths.forEach((attachment) => { attachmentsAbsolutePaths.forEach(attachment => {
exportTasks.push({ exportTasks.push({
src: attachment, src: attachment,
dst: attachmentManagement.DESTINATION_FOLDER dst: attachmentManagement.DESTINATION_FOLDER
}) })
}) })
body = attachmentManagement.removeStorageAndNoteReferences(body, this.props.noteKey) body = attachmentManagement.removeStorageAndNoteReferences(
body,
this.props.noteKey
)
let styles = '' let styles = ''
files.forEach((file) => { files.forEach(file => {
styles += `<link rel="stylesheet" href="css/${path.basename(file)}">` styles += `<link rel="stylesheet" href="css/${path.basename(file)}">`
}) })
@@ -283,43 +351,47 @@ export default class MarkdownPreview extends React.Component {
exportAsDocument (fileType, contentFormatter) { exportAsDocument (fileType, contentFormatter) {
const options = { const options = {
filters: [ filters: [{ name: 'Documents', extensions: [fileType] }],
{name: 'Documents', extensions: [fileType]}
],
properties: ['openFile', 'createDirectory'] properties: ['openFile', 'createDirectory']
} }
dialog.showSaveDialog(remote.getCurrentWindow(), options, dialog.showSaveDialog(remote.getCurrentWindow(), options, filename => {
(filename) => { if (filename) {
if (filename) { const content = this.props.value
const content = this.props.value const storage = this.props.storagePath
const storage = this.props.storagePath
exportNote(storage, content, filename, contentFormatter) exportNote(storage, content, filename, contentFormatter)
.then((res) => { .then(res => {
dialog.showMessageBox(remote.getCurrentWindow(), {type: 'info', message: `Exported to ${filename}`}) dialog.showMessageBox(remote.getCurrentWindow(), {
}).catch((err) => { type: 'info',
dialog.showErrorBox('Export error', err ? err.message || err : 'Unexpected error during export') message: `Exported to ${filename}`
throw err })
}) })
} .catch(err => {
}) dialog.showErrorBox(
'Export error',
err ? err.message || err : 'Unexpected error during export'
)
throw err
})
}
})
} }
fixDecodedURI (node) { fixDecodedURI (node) {
if (node && node.children.length === 1 && typeof node.children[0] === 'string') { if (
node &&
node.children.length === 1 &&
typeof node.children[0] === 'string'
) {
const { innerText, href } = node const { innerText, href } = node
node.innerText = mdurl.decode(href) === innerText node.innerText = mdurl.decode(href) === innerText ? href : innerText
? href
: innerText
} }
} }
getScrollBarStyle () { getScrollBarStyle () {
const { const { theme } = this.props
theme
} = this.props
switch (theme) { switch (theme) {
case 'dark': case 'dark':
@@ -333,7 +405,10 @@ export default class MarkdownPreview extends React.Component {
componentDidMount () { componentDidMount () {
this.refs.root.setAttribute('sandbox', 'allow-scripts') this.refs.root.setAttribute('sandbox', 'allow-scripts')
this.refs.root.contentWindow.document.body.addEventListener('contextmenu', this.contextMenuHandler) this.refs.root.contentWindow.document.body.addEventListener(
'contextmenu',
this.contextMenuHandler
)
let styles = ` let styles = `
<style id='style'></style> <style id='style'></style>
@@ -344,7 +419,7 @@ export default class MarkdownPreview extends React.Component {
</style> </style>
` `
CSS_FILES.forEach((file) => { CSS_FILES.forEach(file => {
styles += `<link rel="stylesheet" href="${file}">` styles += `<link rel="stylesheet" href="${file}">`
}) })
@@ -352,12 +427,30 @@ export default class MarkdownPreview extends React.Component {
this.rewriteIframe() this.rewriteIframe()
this.applyStyle() this.applyStyle()
this.refs.root.contentWindow.document.addEventListener('mousedown', this.mouseDownHandler) this.refs.root.contentWindow.document.addEventListener(
this.refs.root.contentWindow.document.addEventListener('mouseup', this.mouseUpHandler) 'mousedown',
this.refs.root.contentWindow.document.addEventListener('dblclick', this.DoubleClickHandler) this.mouseDownHandler
this.refs.root.contentWindow.document.addEventListener('drop', this.preventImageDroppedHandler) )
this.refs.root.contentWindow.document.addEventListener('dragover', this.preventImageDroppedHandler) this.refs.root.contentWindow.document.addEventListener(
this.refs.root.contentWindow.document.addEventListener('scroll', this.scrollHandler) 'mouseup',
this.mouseUpHandler
)
this.refs.root.contentWindow.document.addEventListener(
'dblclick',
this.DoubleClickHandler
)
this.refs.root.contentWindow.document.addEventListener(
'drop',
this.preventImageDroppedHandler
)
this.refs.root.contentWindow.document.addEventListener(
'dragover',
this.preventImageDroppedHandler
)
this.refs.root.contentWindow.document.addEventListener(
'scroll',
this.scrollHandler
)
eventEmitter.on('export:save-text', this.saveAsTextHandler) eventEmitter.on('export:save-text', this.saveAsTextHandler)
eventEmitter.on('export:save-md', this.saveAsMdHandler) eventEmitter.on('export:save-md', this.saveAsMdHandler)
eventEmitter.on('export:save-html', this.saveAsHtmlHandler) eventEmitter.on('export:save-html', this.saveAsHtmlHandler)
@@ -365,13 +458,34 @@ export default class MarkdownPreview extends React.Component {
} }
componentWillUnmount () { componentWillUnmount () {
this.refs.root.contentWindow.document.body.removeEventListener('contextmenu', this.contextMenuHandler) this.refs.root.contentWindow.document.body.removeEventListener(
this.refs.root.contentWindow.document.removeEventListener('mousedown', this.mouseDownHandler) 'contextmenu',
this.refs.root.contentWindow.document.removeEventListener('mouseup', this.mouseUpHandler) this.contextMenuHandler
this.refs.root.contentWindow.document.removeEventListener('dblclick', this.DoubleClickHandler) )
this.refs.root.contentWindow.document.removeEventListener('drop', this.preventImageDroppedHandler) this.refs.root.contentWindow.document.removeEventListener(
this.refs.root.contentWindow.document.removeEventListener('dragover', this.preventImageDroppedHandler) 'mousedown',
this.refs.root.contentWindow.document.removeEventListener('scroll', this.scrollHandler) this.mouseDownHandler
)
this.refs.root.contentWindow.document.removeEventListener(
'mouseup',
this.mouseUpHandler
)
this.refs.root.contentWindow.document.removeEventListener(
'dblclick',
this.DoubleClickHandler
)
this.refs.root.contentWindow.document.removeEventListener(
'drop',
this.preventImageDroppedHandler
)
this.refs.root.contentWindow.document.removeEventListener(
'dragover',
this.preventImageDroppedHandler
)
this.refs.root.contentWindow.document.removeEventListener(
'scroll',
this.scrollHandler
)
eventEmitter.off('export:save-text', this.saveAsTextHandler) eventEmitter.off('export:save-text', this.saveAsTextHandler)
eventEmitter.off('export:save-md', this.saveAsMdHandler) eventEmitter.off('export:save-md', this.saveAsMdHandler)
eventEmitter.off('export:save-html', this.saveAsHtmlHandler) eventEmitter.off('export:save-html', this.saveAsHtmlHandler)
@@ -380,14 +494,17 @@ export default class MarkdownPreview extends React.Component {
componentDidUpdate (prevProps) { componentDidUpdate (prevProps) {
if (prevProps.value !== this.props.value) this.rewriteIframe() if (prevProps.value !== this.props.value) this.rewriteIframe()
if (prevProps.smartQuotes !== this.props.smartQuotes || if (
prevProps.sanitize !== this.props.sanitize || prevProps.smartQuotes !== this.props.smartQuotes ||
prevProps.smartArrows !== this.props.smartArrows || prevProps.sanitize !== this.props.sanitize ||
prevProps.breaks !== this.props.breaks) { prevProps.smartArrows !== this.props.smartArrows ||
prevProps.breaks !== this.props.breaks
) {
this.initMarkdown() this.initMarkdown()
this.rewriteIframe() this.rewriteIframe()
} }
if (prevProps.fontFamily !== this.props.fontFamily || if (
prevProps.fontFamily !== this.props.fontFamily ||
prevProps.fontSize !== this.props.fontSize || prevProps.fontSize !== this.props.fontSize ||
prevProps.codeBlockFontFamily !== this.props.codeBlockFontFamily || prevProps.codeBlockFontFamily !== this.props.codeBlockFontFamily ||
prevProps.codeBlockTheme !== this.props.codeBlockTheme || prevProps.codeBlockTheme !== this.props.codeBlockTheme ||
@@ -396,34 +513,82 @@ export default class MarkdownPreview extends React.Component {
prevProps.theme !== this.props.theme || prevProps.theme !== this.props.theme ||
prevProps.scrollPastEnd !== this.props.scrollPastEnd || prevProps.scrollPastEnd !== this.props.scrollPastEnd ||
prevProps.allowCustomCSS !== this.props.allowCustomCSS || prevProps.allowCustomCSS !== this.props.allowCustomCSS ||
prevProps.customCSS !== this.props.customCSS) { prevProps.customCSS !== this.props.customCSS
) {
this.applyStyle() this.applyStyle()
this.rewriteIframe() this.rewriteIframe()
} }
} }
getStyleParams () { getStyleParams () {
const { fontSize, lineNumber, codeBlockTheme, scrollPastEnd, theme, allowCustomCSS, customCSS } = this.props const {
fontSize,
lineNumber,
codeBlockTheme,
scrollPastEnd,
theme,
allowCustomCSS,
customCSS
} = this.props
let { fontFamily, codeBlockFontFamily } = this.props let { fontFamily, codeBlockFontFamily } = this.props
fontFamily = _.isString(fontFamily) && fontFamily.trim().length > 0 fontFamily = _.isString(fontFamily) && fontFamily.trim().length > 0
? fontFamily.split(',').map(fontName => fontName.trim()).concat(defaultFontFamily) ? fontFamily
: defaultFontFamily .split(',')
codeBlockFontFamily = _.isString(codeBlockFontFamily) && codeBlockFontFamily.trim().length > 0 .map(fontName => fontName.trim())
? codeBlockFontFamily.split(',').map(fontName => fontName.trim()).concat(defaultCodeBlockFontFamily) .concat(defaultFontFamily)
: defaultCodeBlockFontFamily : defaultFontFamily
codeBlockFontFamily = _.isString(codeBlockFontFamily) &&
codeBlockFontFamily.trim().length > 0
? codeBlockFontFamily
.split(',')
.map(fontName => fontName.trim())
.concat(defaultCodeBlockFontFamily)
: defaultCodeBlockFontFamily
return {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, scrollPastEnd, theme, allowCustomCSS, customCSS} return {
fontFamily,
fontSize,
codeBlockFontFamily,
lineNumber,
codeBlockTheme,
scrollPastEnd,
theme,
allowCustomCSS,
customCSS
}
} }
applyStyle () { applyStyle () {
const {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, scrollPastEnd, theme, allowCustomCSS, customCSS} = 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(
this.getWindow().document.getElementById('style').innerHTML = buildStyle(fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd, theme, allowCustomCSS, customCSS) 'codeTheme'
).href = this.GetCodeThemeLink(codeBlockTheme)
this.getWindow().document.getElementById('style').innerHTML = buildStyle(
fontFamily,
fontSize,
codeBlockFontFamily,
lineNumber,
scrollPastEnd,
theme,
allowCustomCSS,
customCSS
)
} }
GetCodeThemeLink (theme) { GetCodeThemeLink (theme) {
theme = consts.THEMES.some((_theme) => _theme === theme) && theme !== 'default' theme = consts.THEMES.some(_theme => _theme === theme) &&
theme !== 'default'
? theme ? theme
: 'elegant' : 'elegant'
return theme.startsWith('solarized') return theme.startsWith('solarized')
@@ -432,71 +597,92 @@ export default class MarkdownPreview extends React.Component {
} }
rewriteIframe () { rewriteIframe () {
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('input[type="checkbox"]'), (el) => { _.forEach(
el.removeEventListener('click', this.checkboxClickHandler) this.refs.root.contentWindow.document.querySelectorAll(
}) 'input[type="checkbox"]'
),
el => {
el.removeEventListener('click', this.checkboxClickHandler)
}
)
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => { _.forEach(
el.removeEventListener('click', this.linkClickHandler) this.refs.root.contentWindow.document.querySelectorAll('a'),
}) el => {
el.removeEventListener('click', this.linkClickHandler)
}
)
const { theme, indentSize, showCopyNotification, storagePath, noteKey } = this.props const {
theme,
indentSize,
showCopyNotification,
storagePath,
noteKey
} = this.props
let { value, codeBlockTheme } = this.props let { value, codeBlockTheme } = this.props
this.refs.root.contentWindow.document.body.setAttribute('data-theme', theme) this.refs.root.contentWindow.document.body.setAttribute('data-theme', theme)
const codeBlocks = value.match(/(```)(.|[\n])*?(```)/g)
if (codeBlocks !== null) {
codeBlocks.forEach((codeBlock) => {
value = value.replace(codeBlock, htmlTextHelper.encodeEntities(codeBlock))
})
}
const renderedHTML = this.markdown.render(value) const renderedHTML = this.markdown.render(value)
attachmentManagement.migrateAttachments(value, storagePath, noteKey) attachmentManagement.migrateAttachments(value, storagePath, noteKey)
this.refs.root.contentWindow.document.body.innerHTML = attachmentManagement.fixLocalURLS(renderedHTML, storagePath) this.refs.root.contentWindow.document.body.innerHTML = attachmentManagement.fixLocalURLS(
renderedHTML,
storagePath
)
_.forEach(
this.refs.root.contentWindow.document.querySelectorAll(
'input[type="checkbox"]'
),
el => {
el.addEventListener('click', this.checkboxClickHandler)
}
)
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('input[type="checkbox"]'), (el) => { _.forEach(
el.addEventListener('click', this.checkboxClickHandler) this.refs.root.contentWindow.document.querySelectorAll('a'),
}) el => {
this.fixDecodedURI(el)
el.addEventListener('click', this.linkClickHandler)
}
)
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => { codeBlockTheme = consts.THEMES.some(_theme => _theme === codeBlockTheme)
this.fixDecodedURI(el)
el.addEventListener('click', this.linkClickHandler)
})
codeBlockTheme = consts.THEMES.some((_theme) => _theme === codeBlockTheme)
? codeBlockTheme ? codeBlockTheme
: 'default' : 'default'
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('.code code'), (el) => { _.forEach(
let syntax = CodeMirror.findModeByName(convertModeName(el.className)) this.refs.root.contentWindow.document.querySelectorAll('.code code'),
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text') el => {
CodeMirror.requireMode(syntax.mode, () => { let syntax = CodeMirror.findModeByName(convertModeName(el.className))
const content = htmlTextHelper.decodeEntities(el.innerHTML) if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
const copyIcon = document.createElement('i') CodeMirror.requireMode(syntax.mode, () => {
copyIcon.innerHTML = '<button class="clipboardButton"><svg width="13" height="13" viewBox="0 0 1792 1792" ><path d="M768 1664h896v-640h-416q-40 0-68-28t-28-68v-416h-384v1152zm256-1440v-64q0-13-9.5-22.5t-22.5-9.5h-704q-13 0-22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h704q13 0 22.5-9.5t9.5-22.5zm256 672h299l-299-299v299zm512 128v672q0 40-28 68t-68 28h-960q-40 0-68-28t-28-68v-160h-544q-40 0-68-28t-28-68v-1344q0-40 28-68t68-28h1088q40 0 68 28t28 68v328q21 13 36 28l408 408q28 28 48 76t20 88z"/></svg></button>' const content = htmlTextHelper.decodeEntities(el.innerHTML)
copyIcon.onclick = (e) => { const copyIcon = document.createElement('i')
copy(content) copyIcon.innerHTML =
if (showCopyNotification) { '<button class="clipboardButton"><svg width="13" height="13" viewBox="0 0 1792 1792" ><path d="M768 1664h896v-640h-416q-40 0-68-28t-28-68v-416h-384v1152zm256-1440v-64q0-13-9.5-22.5t-22.5-9.5h-704q-13 0-22.5 9.5t-9.5 22.5v64q0 13 9.5 22.5t22.5 9.5h704q13 0 22.5-9.5t9.5-22.5zm256 672h299l-299-299v299zm512 128v672q0 40-28 68t-68 28h-960q-40 0-68-28t-28-68v-160h-544q-40 0-68-28t-28-68v-1344q0-40 28-68t68-28h1088q40 0 68 28t28 68v328q21 13 36 28l408 408q28 28 48 76t20 88z"/></svg></button>'
this.notify('Saved to Clipboard!', { copyIcon.onclick = e => {
body: 'Paste it wherever you want!', copy(content)
silent: true if (showCopyNotification) {
}) this.notify('Saved to Clipboard!', {
body: 'Paste it wherever you want!',
silent: true
})
}
} }
} el.parentNode.appendChild(copyIcon)
el.parentNode.appendChild(copyIcon) el.innerHTML = ''
el.innerHTML = '' if (codeBlockTheme.indexOf('solarized') === 0) {
if (codeBlockTheme.indexOf('solarized') === 0) { const [refThema, color] = codeBlockTheme.split(' ')
const [refThema, color] = codeBlockTheme.split(' ') el.parentNode.className += ` cm-s-${refThema} cm-s-${color}`
el.parentNode.className += ` cm-s-${refThema} cm-s-${color}` } else {
} else { el.parentNode.className += ` cm-s-${codeBlockTheme}`
el.parentNode.className += ` cm-s-${codeBlockTheme}` }
} CodeMirror.runMode(content, syntax.mime, el, {
CodeMirror.runMode(content, syntax.mime, el, { tabSize: indentSize
tabSize: indentSize })
}) })
}) }
}) )
const opts = {} const opts = {}
// if (this.props.theme === 'dark') { // if (this.props.theme === 'dark') {
// opts['font-color'] = '#DDD' // opts['font-color'] = '#DDD'
@@ -504,41 +690,51 @@ export default class MarkdownPreview extends React.Component {
// opts['element-color'] = '#DDD' // opts['element-color'] = '#DDD'
// opts['fill'] = '#3A404C' // opts['fill'] = '#3A404C'
// } // }
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('.flowchart'), (el) => { _.forEach(
Raphael.setWindow(this.getWindow()) this.refs.root.contentWindow.document.querySelectorAll('.flowchart'),
try { el => {
const diagram = flowchart.parse(htmlTextHelper.decodeEntities(el.innerHTML)) Raphael.setWindow(this.getWindow())
el.innerHTML = '' try {
diagram.drawSVG(el, opts) const diagram = flowchart.parse(
_.forEach(el.querySelectorAll('a'), (el) => { htmlTextHelper.decodeEntities(el.innerHTML)
el.addEventListener('click', this.linkClickHandler) )
}) el.innerHTML = ''
} catch (e) { diagram.drawSVG(el, opts)
console.error(e) _.forEach(el.querySelectorAll('a'), el => {
el.className = 'flowchart-error' el.addEventListener('click', this.linkClickHandler)
el.innerHTML = 'Flowchart parse error: ' + e.message })
} catch (e) {
console.error(e)
el.className = 'flowchart-error'
el.innerHTML = 'Flowchart parse error: ' + e.message
}
} }
}) )
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('.sequence'), (el) => { _.forEach(
Raphael.setWindow(this.getWindow()) this.refs.root.contentWindow.document.querySelectorAll('.sequence'),
try { el => {
const diagram = SequenceDiagram.parse(htmlTextHelper.decodeEntities(el.innerHTML)) Raphael.setWindow(this.getWindow())
el.innerHTML = '' try {
diagram.drawSVG(el, {theme: 'simple'}) const diagram = SequenceDiagram.parse(
_.forEach(el.querySelectorAll('a'), (el) => { htmlTextHelper.decodeEntities(el.innerHTML)
el.addEventListener('click', this.linkClickHandler) )
}) el.innerHTML = ''
} catch (e) { diagram.drawSVG(el, { theme: 'simple' })
console.error(e) _.forEach(el.querySelectorAll('a'), el => {
el.className = 'sequence-error' el.addEventListener('click', this.linkClickHandler)
el.innerHTML = 'Sequence diagram parse error: ' + e.message })
} catch (e) {
console.error(e)
el.className = 'sequence-error'
el.innerHTML = 'Sequence diagram parse error: ' + e.message
}
} }
}) )
_.forEach( _.forEach(
this.refs.root.contentWindow.document.querySelectorAll('.chart'), this.refs.root.contentWindow.document.querySelectorAll('.chart'),
(el) => { el => {
try { try {
const chartConfig = JSON.parse(el.innerHTML) const chartConfig = JSON.parse(el.innerHTML)
el.innerHTML = '' el.innerHTML = ''
@@ -555,8 +751,8 @@ export default class MarkdownPreview extends React.Component {
) )
_.forEach( _.forEach(
this.refs.root.contentWindow.document.querySelectorAll('.mermaid'), this.refs.root.contentWindow.document.querySelectorAll('.mermaid'),
(el) => { el => {
mermaidRender(el, htmlTextHelper.decodeEntities(el.innerHTML)) mermaidRender(el, htmlTextHelper.decodeEntities(el.innerHTML), theme)
} }
) )
} }
@@ -570,7 +766,9 @@ export default class MarkdownPreview extends React.Component {
} }
scrollTo (targetRow) { scrollTo (targetRow) {
const blocks = this.getWindow().document.querySelectorAll('body>[data-line]') const blocks = this.getWindow().document.querySelectorAll(
'body>[data-line]'
)
for (let index = 0; index < blocks.length; index++) { for (let index = 0; index < blocks.length; index++) {
let block = blocks[index] let block = blocks[index]
@@ -590,7 +788,11 @@ export default class MarkdownPreview extends React.Component {
notify (title, options) { notify (title, options) {
if (global.process.platform === 'win32') { if (global.process.platform === 'win32') {
options.icon = path.join('file://', global.__dirname, '../../resources/app.png') options.icon = path.join(
'file://',
global.__dirname,
'../../resources/app.png'
)
} }
return new window.Notification(title, options) return new window.Notification(title, options)
} }
@@ -605,7 +807,9 @@ export default class MarkdownPreview extends React.Component {
const regexNoteInternalLink = /main.html#(.+)/ const regexNoteInternalLink = /main.html#(.+)/
if (regexNoteInternalLink.test(linkHash)) { if (regexNoteInternalLink.test(linkHash)) {
const targetId = mdurl.encode(linkHash.match(regexNoteInternalLink)[1]) const targetId = mdurl.encode(linkHash.match(regexNoteInternalLink)[1])
const targetElement = this.refs.root.contentWindow.document.getElementById(targetId) const targetElement = this.refs.root.contentWindow.document.getElementById(
targetId
)
if (targetElement != null) { if (targetElement != null) {
this.getWindow().scrollTo(0, targetElement.offsetTop) this.getWindow().scrollTo(0, targetElement.offsetTop)
@@ -639,9 +843,9 @@ export default class MarkdownPreview extends React.Component {
render () { render () {
const { className, style, tabIndex } = this.props const { className, style, tabIndex } = this.props
return ( return (
<iframe className={className != null <iframe
? 'MarkdownPreview ' + className className={
: 'MarkdownPreview' className != null ? 'MarkdownPreview ' + className : 'MarkdownPreview'
} }
style={style} style={style}
tabIndex={tabIndex} tabIndex={tabIndex}

View File

@@ -26,14 +26,12 @@ const TagElement = ({ tagName }) => (
* @param {Array|null} tags * @param {Array|null} tags
* @return {React.Component} * @return {React.Component}
*/ */
const TagElementList = (tags) => { const TagElementList = tags => {
if (!isArray(tags)) { if (!isArray(tags)) {
return [] return []
} }
const tagElements = tags.map(tag => ( const tagElements = tags.map(tag => TagElement({ tagName: tag }))
TagElement({tagName: tag})
))
return tagElements return tagElements
} }
@@ -59,10 +57,8 @@ const NoteItem = ({
folderName, folderName,
viewType viewType
}) => ( }) => (
<div styleName={isActive <div
? 'item--active' styleName={isActive ? 'item--active' : 'item'}
: 'item'
}
key={note.key} key={note.key}
onClick={e => handleNoteClick(e, note.key)} onClick={e => handleNoteClick(e, note.key)}
onContextMenu={e => handleNoteContextMenu(e, note.key)} onContextMenu={e => handleNoteContextMenu(e, note.key)}
@@ -72,42 +68,54 @@ const NoteItem = ({
<div styleName='item-wrapper'> <div styleName='item-wrapper'>
{note.type === 'SNIPPET_NOTE' {note.type === 'SNIPPET_NOTE'
? <i styleName='item-title-icon' className='fa fa-fw fa-code' /> ? <i styleName='item-title-icon' className='fa fa-fw fa-code' />
: <i styleName='item-title-icon' className='fa fa-fw fa-file-text-o' /> : <i styleName='item-title-icon' className='fa fa-fw fa-file-text-o' />}
}
<div styleName='item-title'> <div styleName='item-title'>
{note.title.trim().length > 0 {note.title.trim().length > 0
? note.title ? note.title
: <span styleName='item-title-empty'>{i18n.__('Empty note')}</span> : <span styleName='item-title-empty'>{i18n.__('Empty note')}</span>}
}
</div> </div>
{['ALL', 'STORAGE'].includes(viewType) && <div styleName='item-middle'> {['ALL', 'STORAGE'].includes(viewType) &&
<div styleName='item-middle-time'>{dateDisplay}</div> <div styleName='item-middle'>
<div styleName='item-middle-app-meta'> <div styleName='item-middle-time'>{dateDisplay}</div>
<div title={viewType === 'ALL' ? storageName : viewType === 'STORAGE' ? folderName : null} styleName='item-middle-app-meta-label'> <div styleName='item-middle-app-meta'>
{viewType === 'ALL' && storageName} <div
{viewType === 'STORAGE' && folderName} title={
viewType === 'ALL'
? storageName
: viewType === 'STORAGE' ? folderName : null
}
styleName='item-middle-app-meta-label'
>
{viewType === 'ALL' && storageName}
{viewType === 'STORAGE' && folderName}
</div>
</div> </div>
</div> </div>}
</div>}
<div styleName='item-bottom'> <div styleName='item-bottom'>
<div styleName='item-bottom-tagList'> <div styleName='item-bottom-tagList'>
{note.tags.length > 0 {note.tags.length > 0
? TagElementList(note.tags) ? TagElementList(note.tags)
: <span style={{ fontStyle: 'italic', opacity: 0.5 }} styleName='item-bottom-tagList-empty'>{i18n.__('No tags')}</span> : <span
} style={{ fontStyle: 'italic', opacity: 0.5 }}
styleName='item-bottom-tagList-empty'
>
{i18n.__('No tags')}
</span>}
</div> </div>
<div> <div>
{note.isStarred {note.isStarred
? <img styleName='item-star' src='../resources/icon/icon-starred.svg' /> : '' ? <img
} styleName='item-star'
src='../resources/icon/icon-starred.svg'
/>
: ''}
{note.isPinned && !pathname.match(/\/starred|\/trash/) {note.isPinned && !pathname.match(/\/starred|\/trash/)
? <i styleName='item-pin' className='fa fa-thumb-tack' /> : '' ? <i styleName='item-pin' className='fa fa-thumb-tack' />
} : ''}
{note.type === 'MARKDOWN_NOTE' {note.type === 'MARKDOWN_NOTE'
? <TodoProcess todoStatus={getTodoStatus(note.content)} /> ? <TodoProcess todoStatus={getTodoStatus(note.content)} />
: '' : ''}
}
</div> </div>
</div> </div>
</div> </div>

View File

@@ -54,9 +54,8 @@ const StorageItem = ({
onDragEnter={handleDragEnter} onDragEnter={handleDragEnter}
onDragLeave={handleDragLeave} onDragLeave={handleDragLeave}
> >
{!isFolded && ( {!isFolded &&
<DraggableIcon className={styles['folderList-item-reorder']} /> <DraggableIcon className={styles['folderList-item-reorder']} />}
)}
<span <span
styleName={ styleName={
isFolded ? 'folderList-item-name--folded' : 'folderList-item-name' isFolded ? 'folderList-item-name--folded' : 'folderList-item-name'
@@ -72,12 +71,10 @@ const StorageItem = ({
: folderName} : folderName}
</span> </span>
{!isFolded && {!isFolded &&
_.isNumber(noteCount) && ( _.isNumber(noteCount) &&
<span styleName='folderList-item-noteCount'>{noteCount}</span> <span styleName='folderList-item-noteCount'>{noteCount}</span>}
)} {isFolded &&
{isFolded && ( <span styleName='folderList-item-tooltip'>{folderName}</span>}
<span styleName='folderList-item-tooltip'>{folderName}</span>
)}
</button> </button>
) )
} }

View File

@@ -1,5 +1,11 @@
import mermaidAPI from 'mermaid' import mermaidAPI from 'mermaid'
// fixes bad styling in the mermaid dark theme
const darkThemeStyling = `
.loopText tspan {
fill: white;
}`
function getRandomInt (min, max) { function getRandomInt (min, max) {
return Math.floor(Math.random() * (max - min)) + min return Math.floor(Math.random() * (max - min)) + min
} }
@@ -13,8 +19,13 @@ function getId () {
return id return id
} }
function render (element, content) { function render (element, content, theme) {
try { try {
let isDarkTheme = theme === 'dark' || theme === 'solarized-dark' || theme === 'monokai'
mermaidAPI.initialize({
theme: isDarkTheme ? 'dark' : 'default',
themeCSS: isDarkTheme ? darkThemeStyling : ''
})
mermaidAPI.render(getId(), content, (svgGraph) => { mermaidAPI.render(getId(), content, (svgGraph) => {
element.innerHTML = svgGraph element.innerHTML = svgGraph
}) })

View File

@@ -5,10 +5,10 @@ export function getTodoStatus (content) {
splitted.forEach((line) => { splitted.forEach((line) => {
const trimmedLine = line.trim() const trimmedLine = line.trim()
if (trimmedLine.match(/^[\+\-\*] \[(\s|x)\] ./)) { if (trimmedLine.match(/^[\+\-\*] \[(\s|x)\] ./i)) {
numberOfTodo++ numberOfTodo++
} }
if (trimmedLine.match(/^[\+\-\*] \[x\] ./)) { if (trimmedLine.match(/^[\+\-\*] \[x\] ./i)) {
numberOfCompletedTodo++ numberOfCompletedTodo++
} }
}) })

View File

@@ -1,6 +1,7 @@
'use strict' 'use strict'
import sanitizeHtml from 'sanitize-html' import sanitizeHtml from 'sanitize-html'
import { escapeHtmlCharacters } from './utils'
module.exports = function sanitizePlugin (md, options) { module.exports = function sanitizePlugin (md, options) {
options = options || {} options = options || {}
@@ -8,16 +9,26 @@ module.exports = function sanitizePlugin (md, options) {
md.core.ruler.after('linkify', 'sanitize_inline', state => { md.core.ruler.after('linkify', 'sanitize_inline', state => {
for (let tokenIdx = 0; tokenIdx < state.tokens.length; tokenIdx++) { for (let tokenIdx = 0; tokenIdx < state.tokens.length; tokenIdx++) {
if (state.tokens[tokenIdx].type === 'html_block') { if (state.tokens[tokenIdx].type === 'html_block') {
state.tokens[tokenIdx].content = sanitizeHtml(state.tokens[tokenIdx].content, options) state.tokens[tokenIdx].content = sanitizeHtml(
state.tokens[tokenIdx].content,
options
)
} }
if (state.tokens[tokenIdx].type === 'fence') { if (state.tokens[tokenIdx].type === 'fence') {
state.tokens[tokenIdx].content = state.tokens[tokenIdx].content.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;') // escapeHtmlCharacters has better performance
state.tokens[tokenIdx].content = escapeHtmlCharacters(
state.tokens[tokenIdx].content,
{ skipSingleQuote: true }
)
} }
if (state.tokens[tokenIdx].type === 'inline') { if (state.tokens[tokenIdx].type === 'inline') {
const inlineTokens = state.tokens[tokenIdx].children const inlineTokens = state.tokens[tokenIdx].children
for (let childIdx = 0; childIdx < inlineTokens.length; childIdx++) { for (let childIdx = 0; childIdx < inlineTokens.length; childIdx++) {
if (inlineTokens[childIdx].type === 'html_inline') { if (inlineTokens[childIdx].type === 'html_inline') {
inlineTokens[childIdx].content = sanitizeHtml(inlineTokens[childIdx].content, options) inlineTokens[childIdx].content = sanitizeHtml(
inlineTokens[childIdx].content,
options
)
} }
} }
} }

View File

@@ -163,6 +163,22 @@ class Markdown {
} }
}) })
// Ditaa support
this.md.use(require('markdown-it-plantuml'), {
openMarker: '@startditaa',
closeMarker: '@endditaa',
generateSource: function (umlCode) {
const stripTrailingSlash = (url) => url.endsWith('/') ? url.slice(0, -1) : url
// Currently PlantUML server doesn't support Ditaa in SVG, so we set the format as PNG at the moment.
const serverAddress = stripTrailingSlash(config.preview.plantUMLServerAddress) + '/png'
const s = unescape(encodeURIComponent(umlCode))
const zippedCode = deflate.encode64(
deflate.zip_deflate(`@startditaa\n${s}\n@endditaa`, 9)
)
return `${serverAddress}/${zippedCode}`
}
})
// Override task item // Override task item
this.md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) { this.md.block.ruler.at('paragraph', function (state, startLine/*, endLine */) {
let content, terminate, i, l, token let content, terminate, i, l, token

View File

@@ -23,7 +23,9 @@ function findByWordOrTag (notes, block) {
return true return true
} }
if (note.type === 'SNIPPET_NOTE') { if (note.type === 'SNIPPET_NOTE') {
return note.description.match(wordRegExp) return note.description.match(wordRegExp) || note.snippets.some((snippet) => {
return snippet.name.match(wordRegExp) || snippet.content.match(wordRegExp)
})
} else if (note.type === 'MARKDOWN_NOTE') { } else if (note.type === 'MARKDOWN_NOTE') {
return note.content.match(wordRegExp) return note.content.match(wordRegExp)
} }

View File

@@ -6,8 +6,12 @@ export function lastFindInArray (array, callback) {
} }
} }
export function escapeHtmlCharacters (html, opt = { detectCodeBlock: false }) { export function escapeHtmlCharacters (
html,
opt = { detectCodeBlock: false, skipSingleQuote: false }
) {
const matchHtmlRegExp = /["'&<>]/g const matchHtmlRegExp = /["'&<>]/g
const matchCodeBlockRegExp = /```/g
const escapes = ['&quot;', '&amp;', '&#39;', '&lt;', '&gt;'] const escapes = ['&quot;', '&amp;', '&#39;', '&lt;', '&gt;']
let match = null let match = null
const replaceAt = (str, index, replace) => const replaceAt = (str, index, replace) =>
@@ -15,11 +19,18 @@ export function escapeHtmlCharacters (html, opt = { detectCodeBlock: false }) {
replace + replace +
str.substr(index + replace.length - (replace.length - 1)) str.substr(index + replace.length - (replace.length - 1))
// detecting code block while ((match = matchHtmlRegExp.exec(html)) !== null) {
while ((match = matchHtmlRegExp.exec(html)) != null) {
const current = { char: match[0], index: match.index } const current = { char: match[0], index: match.index }
const codeBlockIndexs = []
let openCodeBlock = null
// if the detectCodeBlock option is activated then this function should skip
// characters that needed to be escape but located in code block
if (opt.detectCodeBlock) { if (opt.detectCodeBlock) {
// position of the nearest line start // The first type of code block is lines that start with 4 spaces
// Here we check for the \n character located before the character that
// needed to be escape. It means we check for the begining of the line that
// contain that character, then we check if there are 4 spaces next to the
// \n character (the line start with 4 spaces)
let previousLineEnd = current.index - 1 let previousLineEnd = current.index - 1
while (html[previousLineEnd] !== '\n' && previousLineEnd !== -1) { while (html[previousLineEnd] !== '\n' && previousLineEnd !== -1) {
previousLineEnd-- previousLineEnd--
@@ -31,16 +42,54 @@ export function escapeHtmlCharacters (html, opt = { detectCodeBlock: false }) {
html[previousLineEnd + 3] === ' ' && html[previousLineEnd + 3] === ' ' &&
html[previousLineEnd + 4] === ' ' html[previousLineEnd + 4] === ' '
) { ) {
// so skip it // skip the current character
continue
}
// The second type of code block is lines that wrapped in ```
// We will get the position of each ```
// then push it into an array
// then the array returned will be like this:
// [startCodeblock, endCodeBlock, startCodeBlock, endCodeBlock]
while ((openCodeBlock = matchCodeBlockRegExp.exec(html)) !== null) {
codeBlockIndexs.push(openCodeBlock.index)
}
let shouldSkipChar = false
// we loop through the array of positions
// we skip 2 element as the i index position is the position of ``` that
// open the codeblock and the i + 1 is the position of the ``` that close
// the code block
for (let i = 0; i < codeBlockIndexs.length; i += 2) {
// the i index position is the position of the ``` that open code block
// so we have to + 2 as that position is the position of the first ` in the ````
// but we need to make sure that the position current character is larger
// that the last ` in the ``` that open the code block so we have to take
// the position of the first ` and + 2
// the i + 1 index position is the closing ``` so the char must less than it
if (
current.index > codeBlockIndexs[i] + 2 &&
current.index < codeBlockIndexs[i + 1]
) {
// skip it
shouldSkipChar = true
break
}
}
if (shouldSkipChar) {
// skip the current character
continue continue
} }
} }
// otherwise, escape it !!! // otherwise, escape it !!!
if (current.char === '&') { if (current.char === '&') {
// when escaping character & we have to be becareful as the & could be a part
// of an escaped character like &quot; will be came &amp;quot;
let nextStr = '' let nextStr = ''
let nextIndex = current.index let nextIndex = current.index
let escapedStr = false let escapedStr = false
// maximum length of an escape string is 5. For example ('&quot;') // maximum length of an escaped string is 5. For example ('&quot;')
// we take the next 5 character of the next string if it is one of the string:
// ['&quot;', '&amp;', '&#39;', '&lt;', '&gt;'] then we will not escape the & character
// as it is a part of the escaped string and should not be escaped
while (nextStr.length <= 5) { while (nextStr.length <= 5) {
nextStr += html[nextIndex] nextStr += html[nextIndex]
nextIndex++ nextIndex++
@@ -55,7 +104,7 @@ export function escapeHtmlCharacters (html, opt = { detectCodeBlock: false }) {
} }
} else if (current.char === '"') { } else if (current.char === '"') {
html = replaceAt(html, current.index, '&quot;') html = replaceAt(html, current.index, '&quot;')
} else if (current.char === "'") { } else if (current.char === "'" && !opt.skipSingleQuote) {
html = replaceAt(html, current.index, '&#39;') html = replaceAt(html, current.index, '&#39;')
} else if (current.char === '<') { } else if (current.char === '<') {
html = replaceAt(html, current.index, '&lt;') html = replaceAt(html, current.index, '&lt;')

View File

@@ -33,6 +33,7 @@
.control-infoButton-panel-trash .control-infoButton-panel-trash
z-index 200 z-index 200
margin-top 0px margin-top 0px
top 50px
right 0px right 0px
position absolute position absolute
padding 20px 25px 0 25px padding 20px 25px 0 25px

View File

@@ -441,7 +441,7 @@ class SnippetNoteDetail extends React.Component {
const isSuper = global.process.platform === 'darwin' const isSuper = global.process.platform === 'darwin'
? e.metaKey ? e.metaKey
: e.ctrlKey : e.ctrlKey
if (isSuper) { if (isSuper && !e.shiftKey) {
e.preventDefault() e.preventDefault()
this.addSnippet() this.addSnippet()
} }

View File

@@ -5,6 +5,7 @@ import styles from './TagSelect.styl'
import _ from 'lodash' import _ from 'lodash'
import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig' import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
import i18n from 'browser/lib/i18n' import i18n from 'browser/lib/i18n'
import ee from 'browser/main/lib/eventEmitter'
class TagSelect extends React.Component { class TagSelect extends React.Component {
constructor (props) { constructor (props) {
@@ -13,16 +14,26 @@ class TagSelect extends React.Component {
this.state = { this.state = {
newTag: '' newTag: ''
} }
this.addtagHandler = this.handleAddTag.bind(this)
} }
componentDidMount () { componentDidMount () {
this.value = this.props.value this.value = this.props.value
ee.on('editor:add-tag', this.addtagHandler)
} }
componentDidUpdate () { componentDidUpdate () {
this.value = this.props.value this.value = this.props.value
} }
componentWillUnmount () {
ee.off('editor:add-tag', this.addtagHandler)
}
handleAddTag () {
this.refs.newTag.focus()
}
handleNewTagInputKeyDown (e) { handleNewTagInputKeyDown (e) {
switch (e.keyCode) { switch (e.keyCode) {
case 9: case 9:

View File

@@ -22,7 +22,6 @@ const electron = require('electron')
const { remote } = electron const { remote } = electron
class Main extends React.Component { class Main extends React.Component {
constructor (props) { constructor (props) {
super(props) super(props)
@@ -60,10 +59,10 @@ class Main extends React.Component {
name: 'My Storage', name: 'My Storage',
path: path.join(remote.app.getPath('home'), 'Boostnote') path: path.join(remote.app.getPath('home'), 'Boostnote')
}) })
.then((data) => { .then(data => {
return data return data
}) })
.then((data) => { .then(data => {
if (data.storage.folders[0] != null) { if (data.storage.folders[0] != null) {
return data return data
} else { } else {
@@ -72,7 +71,7 @@ class Main extends React.Component {
color: '#1278BD', color: '#1278BD',
name: 'Default' name: 'Default'
}) })
.then((_data) => { .then(_data => {
return { return {
storage: _data.storage, storage: _data.storage,
notes: data.notes notes: data.notes
@@ -80,7 +79,7 @@ class Main extends React.Component {
}) })
} }
}) })
.then((data) => { .then(data => {
console.log(data) console.log(data)
store.dispatch({ store.dispatch({
type: 'ADD_STORAGE', type: 'ADD_STORAGE',
@@ -98,16 +97,16 @@ class Main extends React.Component {
{ {
name: 'example.html', name: 'example.html',
mode: 'html', mode: 'html',
content: '<html>\n<body>\n<h1 id=\'hello\'>Enjoy Boostnote!</h1>\n</body>\n</html>' content: "<html>\n<body>\n<h1 id='hello'>Enjoy Boostnote!</h1>\n</body>\n</html>"
}, },
{ {
name: 'example.js', name: 'example.js',
mode: 'javascript', mode: 'javascript',
content: 'var boostnote = document.getElementById(\'enjoy\').innerHTML\n\nconsole.log(boostnote)' content: "var boostnote = document.getElementById('enjoy').innerHTML\n\nconsole.log(boostnote)"
} }
] ]
}) })
.then((note) => { .then(note => {
store.dispatch({ store.dispatch({
type: 'UPDATE_NOTE', type: 'UPDATE_NOTE',
note: note note: note
@@ -120,7 +119,7 @@ class Main extends React.Component {
title: 'Welcome to Boostnote!', title: 'Welcome to Boostnote!',
content: '# Welcome to Boostnote!\n## Click here to edit markdown :wave:\n\n<iframe width="560" height="315" src="https://www.youtube.com/embed/L0qNPLsvmyM" frameborder="0" allowfullscreen></iframe>\n\n## Docs :memo:\n- [Boostnote | Boost your happiness, productivity and creativity.](https://hackernoon.com/boostnote-boost-your-happiness-productivity-and-creativity-315034efeebe)\n- [Cloud Syncing & Backups](https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup)\n- [How to sync your data across Desktop and Mobile apps](https://github.com/BoostIO/Boostnote/wiki/Sync-Data-Across-Desktop-and-Mobile-apps)\n- [Convert data from **Evernote** to Boostnote.](https://github.com/BoostIO/Boostnote/wiki/Evernote)\n- [Keyboard Shortcuts](https://github.com/BoostIO/Boostnote/wiki/Keyboard-Shortcuts)\n- [Keymaps in Editor mode](https://github.com/BoostIO/Boostnote/wiki/Keymaps-in-Editor-mode)\n- [How to set syntax highlight in Snippet note](https://github.com/BoostIO/Boostnote/wiki/Syntax-Highlighting)\n\n---\n\n## Article Archive :books:\n- [Reddit English](http://bit.ly/2mOJPu7)\n- [Reddit Spanish](https://www.reddit.com/r/boostnote_es/)\n- [Reddit Chinese](https://www.reddit.com/r/boostnote_cn/)\n- [Reddit Japanese](https://www.reddit.com/r/boostnote_jp/)\n\n---\n\n## Community :beers:\n- [GitHub](http://bit.ly/2AWWzkD)\n- [Twitter](http://bit.ly/2z8BUJZ)\n- [Facebook Group](http://bit.ly/2jcca8t)' content: '# Welcome to Boostnote!\n## Click here to edit markdown :wave:\n\n<iframe width="560" height="315" src="https://www.youtube.com/embed/L0qNPLsvmyM" frameborder="0" allowfullscreen></iframe>\n\n## Docs :memo:\n- [Boostnote | Boost your happiness, productivity and creativity.](https://hackernoon.com/boostnote-boost-your-happiness-productivity-and-creativity-315034efeebe)\n- [Cloud Syncing & Backups](https://github.com/BoostIO/Boostnote/wiki/Cloud-Syncing-and-Backup)\n- [How to sync your data across Desktop and Mobile apps](https://github.com/BoostIO/Boostnote/wiki/Sync-Data-Across-Desktop-and-Mobile-apps)\n- [Convert data from **Evernote** to Boostnote.](https://github.com/BoostIO/Boostnote/wiki/Evernote)\n- [Keyboard Shortcuts](https://github.com/BoostIO/Boostnote/wiki/Keyboard-Shortcuts)\n- [Keymaps in Editor mode](https://github.com/BoostIO/Boostnote/wiki/Keymaps-in-Editor-mode)\n- [How to set syntax highlight in Snippet note](https://github.com/BoostIO/Boostnote/wiki/Syntax-Highlighting)\n\n---\n\n## Article Archive :books:\n- [Reddit English](http://bit.ly/2mOJPu7)\n- [Reddit Spanish](https://www.reddit.com/r/boostnote_es/)\n- [Reddit Chinese](https://www.reddit.com/r/boostnote_cn/)\n- [Reddit Japanese](https://www.reddit.com/r/boostnote_jp/)\n\n---\n\n## Community :beers:\n- [GitHub](http://bit.ly/2AWWzkD)\n- [Twitter](http://bit.ly/2z8BUJZ)\n- [Facebook Group](http://bit.ly/2jcca8t)'
}) })
.then((note) => { .then(note => {
store.dispatch({ store.dispatch({
type: 'UPDATE_NOTE', type: 'UPDATE_NOTE',
note: note note: note
@@ -131,10 +130,10 @@ class Main extends React.Component {
.then(defaultMarkdownNote) .then(defaultMarkdownNote)
.then(() => data.storage) .then(() => data.storage)
}) })
.then((storage) => { .then(storage => {
hashHistory.push('/storages/' + storage.key) hashHistory.push('/storages/' + storage.key)
}) })
.catch((err) => { .catch(err => {
throw err throw err
}) })
} }
@@ -142,12 +141,7 @@ class Main extends React.Component {
componentDidMount () { componentDidMount () {
const { dispatch, config } = this.props const { dispatch, config } = this.props
const supportedThemes = [ const supportedThemes = ['dark', 'white', 'solarized-dark', 'monokai']
'dark',
'white',
'solarized-dark',
'monokai'
]
if (supportedThemes.indexOf(config.ui.theme) !== -1) { if (supportedThemes.indexOf(config.ui.theme) !== -1) {
document.body.setAttribute('data-theme', config.ui.theme) document.body.setAttribute('data-theme', config.ui.theme)
@@ -162,19 +156,18 @@ class Main extends React.Component {
} }
applyShortcuts() applyShortcuts()
// Reload all data // Reload all data
dataApi.init() dataApi.init().then(data => {
.then((data) => { dispatch({
dispatch({ type: 'INIT_ALL',
type: 'INIT_ALL', storages: data.storages,
storages: data.storages, notes: data.notes
notes: data.notes
})
if (data.storages.length < 1) {
this.init()
}
}) })
if (data.storages.length < 1) {
this.init()
}
})
eventEmitter.on('editor:fullscreen', this.toggleFullScreen) eventEmitter.on('editor:fullscreen', this.toggleFullScreen)
} }
@@ -199,34 +192,40 @@ class Main extends React.Component {
handleMouseUp (e) { handleMouseUp (e) {
// Change width of NoteList component. // Change width of NoteList component.
if (this.state.isRightSliderFocused) { if (this.state.isRightSliderFocused) {
this.setState({ this.setState(
isRightSliderFocused: false {
}, () => { isRightSliderFocused: false
const { dispatch } = this.props },
const newListWidth = this.state.listWidth () => {
// TODO: ConfigManager should dispatch itself. const { dispatch } = this.props
ConfigManager.set({listWidth: newListWidth}) const newListWidth = this.state.listWidth
dispatch({ // TODO: ConfigManager should dispatch itself.
type: 'SET_LIST_WIDTH', ConfigManager.set({ listWidth: newListWidth })
listWidth: newListWidth dispatch({
}) type: 'SET_LIST_WIDTH',
}) listWidth: newListWidth
})
}
)
} }
// Change width of SideNav component. // Change width of SideNav component.
if (this.state.isLeftSliderFocused) { if (this.state.isLeftSliderFocused) {
this.setState({ this.setState(
isLeftSliderFocused: false {
}, () => { isLeftSliderFocused: false
const { dispatch } = this.props },
const navWidth = this.state.navWidth () => {
// TODO: ConfigManager should dispatch itself. const { dispatch } = this.props
ConfigManager.set({ navWidth }) const navWidth = this.state.navWidth
dispatch({ // TODO: ConfigManager should dispatch itself.
type: 'SET_NAV_WIDTH', ConfigManager.set({ navWidth })
navWidth dispatch({
}) type: 'SET_NAV_WIDTH',
}) navWidth
})
}
)
} }
} }
@@ -271,8 +270,8 @@ class Main extends React.Component {
} }
hideLeftLists (noteDetail, noteList, mainBody) { hideLeftLists (noteDetail, noteList, mainBody) {
this.setState({noteDetailWidth: noteDetail.style.left}) this.setState({ noteDetailWidth: noteDetail.style.left })
this.setState({mainBodyWidth: mainBody.style.left}) this.setState({ mainBodyWidth: mainBody.style.left })
noteDetail.style.left = '0px' noteDetail.style.left = '0px'
mainBody.style.left = '0px' mainBody.style.left = '0px'
noteList.style.display = 'none' noteList.style.display = 'none'
@@ -294,33 +293,36 @@ class Main extends React.Component {
<div <div
className='Main' className='Main'
styleName='root' styleName='root'
onMouseMove={(e) => this.handleMouseMove(e)} onMouseMove={e => this.handleMouseMove(e)}
onMouseUp={(e) => this.handleMouseUp(e)} onMouseUp={e => this.handleMouseUp(e)}
> >
<SideNav <SideNav
{..._.pick(this.props, [ {..._.pick(this.props, ['dispatch', 'data', 'config', 'location'])}
'dispatch',
'data',
'config',
'location'
])}
width={this.state.navWidth} width={this.state.navWidth}
/> />
{!config.isSideNavFolded && {!config.isSideNavFolded &&
<div styleName={this.state.isLeftSliderFocused ? 'slider--active' : 'slider'} <div
style={{left: this.state.navWidth}} styleName={
onMouseDown={(e) => this.handleLeftSlideMouseDown(e)} this.state.isLeftSliderFocused ? 'slider--active' : 'slider'
}
style={{ left: this.state.navWidth }}
onMouseDown={e => this.handleLeftSlideMouseDown(e)}
draggable='false' draggable='false'
> >
<div styleName='slider-hitbox' /> <div styleName='slider-hitbox' />
</div> </div>}
} <div
<div styleName={config.isSideNavFolded ? 'body--expanded' : 'body'} styleName={config.isSideNavFolded ? 'body--expanded' : 'body'}
id='main-body' id='main-body'
ref='body' ref='body'
style={{left: config.isSideNavFolded ? foldedNavigationWidth : this.state.navWidth}} style={{
left: config.isSideNavFolded
? foldedNavigationWidth
: this.state.navWidth
}}
> >
<TopBar style={{width: this.state.listWidth}} <TopBar
style={{ width: this.state.listWidth }}
{..._.pick(this.props, [ {..._.pick(this.props, [
'dispatch', 'dispatch',
'config', 'config',
@@ -329,7 +331,8 @@ class Main extends React.Component {
'location' 'location'
])} ])}
/> />
<NoteList style={{width: this.state.listWidth}} <NoteList
style={{ width: this.state.listWidth }}
{..._.pick(this.props, [ {..._.pick(this.props, [
'dispatch', 'dispatch',
'data', 'data',
@@ -338,15 +341,20 @@ class Main extends React.Component {
'location' 'location'
])} ])}
/> />
<div styleName={this.state.isRightSliderFocused ? 'slider-right--active' : 'slider-right'} <div
style={{left: this.state.listWidth - 1}} styleName={
onMouseDown={(e) => this.handleRightSlideMouseDown(e)} this.state.isRightSliderFocused
? 'slider-right--active'
: 'slider-right'
}
style={{ left: this.state.listWidth - 1 }}
onMouseDown={e => this.handleRightSlideMouseDown(e)}
draggable='false' draggable='false'
> >
<div styleName='slider-hitbox' /> <div styleName='slider-hitbox' />
</div> </div>
<Detail <Detail
style={{left: this.state.listWidth}} style={{ left: this.state.listWidth }}
{..._.pick(this.props, [ {..._.pick(this.props, [
'dispatch', 'dispatch',
'data', 'data',
@@ -374,4 +382,4 @@ Main.propTypes = {
data: PropTypes.shape({}).isRequired data: PropTypes.shape({}).isRequired
} }
export default connect((x) => x)(CSSModules(Main, styles)) export default connect(x => x)(CSSModules(Main, styles))

View File

@@ -418,10 +418,10 @@ class NoteList extends React.Component {
} }
handleSortByChange (e) { handleSortByChange (e) {
const { dispatch } = this.props const { dispatch, params: { folderKey } } = this.props
const config = { const config = {
sortBy: e.target.value [folderKey]: { sortBy: e.target.value }
} }
ConfigManager.set(config) ConfigManager.set(config)
@@ -909,12 +909,13 @@ class NoteList extends React.Component {
} }
render () { render () {
const { location, config } = this.props const { location, config, params: { folderKey } } = this.props
let { notes } = this.props let { notes } = this.props
const { selectedNoteKeys } = this.state const { selectedNoteKeys } = this.state
const sortFunc = config.sortBy === 'CREATED_AT' const sortBy = _.get(config, [folderKey, 'sortBy'], config.sortBy.default)
const sortFunc = sortBy === 'CREATED_AT'
? sortByCreatedAt ? sortByCreatedAt
: config.sortBy === 'ALPHABETICAL' : sortBy === 'ALPHABETICAL'
? sortByAlphabetical ? sortByAlphabetical
: sortByUpdatedAt : sortByUpdatedAt
const sortedNotes = location.pathname.match(/\/starred|\/trash/) const sortedNotes = location.pathname.match(/\/starred|\/trash/)
@@ -965,7 +966,7 @@ class NoteList extends React.Component {
notes.length === 1 || notes.length === 1 ||
(autoSelectFirst && index === 0) (autoSelectFirst && index === 0)
const dateDisplay = moment( const dateDisplay = moment(
config.sortBy === 'CREATED_AT' sortBy === 'CREATED_AT'
? note.createdAt : note.updatedAt ? note.createdAt : note.updatedAt
).fromNow('D') ).fromNow('D')
@@ -1014,7 +1015,7 @@ class NoteList extends React.Component {
<i className='fa fa-angle-down' /> <i className='fa fa-angle-down' />
<select styleName='control-sortBy-select' <select styleName='control-sortBy-select'
title={i18n.__('Select filter mode')} title={i18n.__('Select filter mode')}
value={config.sortBy} value={sortBy}
onChange={(e) => this.handleSortByChange(e)} onChange={(e) => this.handleSortByChange(e)}
> >
<option title='Sort by update time' value='UPDATED_AT'>{i18n.__('Updated')}</option> <option title='Sort by update time' value='UPDATED_AT'>{i18n.__('Updated')}</option>

View File

@@ -152,3 +152,7 @@ body[data-theme="monokai"]
background-color $ui-monokai-backgroundColor background-color $ui-monokai-backgroundColor
.sortableItemHelper .sortableItemHelper
color: $ui-monokai-text-color color: $ui-monokai-text-color
body[data-theme="default"]
.SideNav ::-webkit-scrollbar-thumb
background-color rgba(255, 255, 255, 0.3)

View File

@@ -16,7 +16,9 @@ export const DEFAULT_CONFIG = {
isSideNavFolded: false, isSideNavFolded: false,
listWidth: 280, listWidth: 280,
navWidth: 200, navWidth: 200,
sortBy: 'UPDATED_AT', // 'CREATED_AT', 'UPDATED_AT', 'APLHABETICAL' sortBy: {
default: 'UPDATED_AT' // 'CREATED_AT', 'UPDATED_AT', 'APLHABETICAL'
},
sortTagsBy: 'ALPHABETICAL', // 'ALPHABETICAL', 'COUNTER' sortTagsBy: 'ALPHABETICAL', // 'ALPHABETICAL', 'COUNTER'
listStyle: 'DEFAULT', // 'DEFAULT', 'SMALL' listStyle: 'DEFAULT', // 'DEFAULT', 'SMALL'
amaEnabled: true, amaEnabled: true,

View File

@@ -82,9 +82,9 @@ function createAttachmentDestinationFolder (destinationStoragePath, noteKey) {
* @param noteKey Key of the current note * @param noteKey Key of the current note
*/ */
function migrateAttachments (markdownContent, storagePath, noteKey) { function migrateAttachments (markdownContent, storagePath, noteKey) {
if (sander.existsSync(path.join(storagePath, 'images'))) { if (noteKey !== undefined && sander.existsSync(path.join(storagePath, 'images'))) {
const attachments = getAttachmentsInMarkdownContent(markdownContent) || [] const attachments = getAttachmentsInMarkdownContent(markdownContent) || []
if (attachments !== []) { if (attachments.length) {
createAttachmentDestinationFolder(storagePath, noteKey) createAttachmentDestinationFolder(storagePath, noteKey)
} }
for (const attachment of attachments) { for (const attachment of attachments) {

View File

@@ -22,7 +22,7 @@ class SnippetList extends React.Component {
reloadSnippetList () { reloadSnippetList () {
dataApi.fetchSnippet().then(snippets => { dataApi.fetchSnippet().then(snippets => {
this.setState({snippets}) this.setState({snippets})
this.props.onSnippetSelect(snippets[0]) this.props.onSnippetSelect(this.props.currentSnippet)
}) })
} }

76
dev-scripts/dev.js Normal file
View File

@@ -0,0 +1,76 @@
const webpack = require('webpack')
const WebpackDevServer = require('webpack-dev-server')
const config = require('../webpack.config')
const signale = require('signale')
const { spawn } = require('child_process')
const electron = require('electron')
const port = 8080
let server = null
let firstRun = true
const options = {
publicPath: config.output.publicPath,
hot: true,
inline: true,
quiet: true
}
function startServer () {
config.plugins.push(new webpack.HotModuleReplacementPlugin())
config.entry.main.unshift(
`webpack-dev-server/client?http://localhost:${port}/`,
'webpack/hot/dev-server'
)
const compiler = webpack(config)
server = new WebpackDevServer(compiler, options)
return new Promise((resolve, reject) => {
server.listen(port, 'localhost', function (err) {
if (err) {
reject(err)
}
signale.success(`Webpack Dev Server listening at localhost:${port}`)
signale.watch(`Waiting for webpack to bundle...`)
compiler.plugin('done', stats => {
if (!stats.hasErrors()) {
signale.success(`Bundle success !`)
resolve()
} else {
if (!firstRun) {
console.log(stats.compilation.errors[0])
} else {
firstRun = false
reject(stats.compilation.errors[0])
}
}
})
})
})
}
function startElectron () {
spawn(electron, ['--hot', './index.js'])
.on('close', () => {
server.close()
})
.on('error', err => {
signale.error(err)
server.close()
})
.on('disconnect', () => {
server.close()
})
.on('exit', () => {
server.close()
})
}
startServer()
.then(() => {
startElectron()
signale.success('Electron started')
})
.catch(err => {
signale.error(err)
process.exit(1)
})

View File

@@ -2,10 +2,9 @@
This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md) and [German](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md). This page is also available in [Japanese](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Korean](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russain](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Simplified Chinese](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), [French](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md) and [German](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md).
## Environments ## Environments
* npm: 4.x
* node: 7.x
You should use `npm v4.x` because `$ grunt pre-build` fails on `v5.x`. * npm: 6.x
* node: 8.x
## Development ## Development
@@ -21,17 +20,9 @@ $ yarn
Build and run. Build and run.
``` ```
$ yarn run dev-start $ yarn run dev
``` ```
This command runs `yarn run webpack` and `yarn run hot` in parallel. It is the same as running these commands in two terminals.
The `webpack` will watch for code changes and then apply them automatically.
If the following error occurs: `Failed to load resource: net::ERR_CONNECTION_REFUSED`, please reload Boostnote.
![net::ERR_CONNECTION_REFUSED](https://cloud.githubusercontent.com/assets/11307908/24343004/081e66ae-1279-11e7-8d9e-7f478043d835.png)
> ### Notice > ### Notice
> There are some cases where you have to refresh the app manually. > There are some cases where you have to refresh the app manually.
> 1. When editing a constructor method of a component > 1. When editing a constructor method of a component
@@ -44,8 +35,6 @@ You can build the program by using `grunt`. However, we don't recommend this bec
So, we've prepared a separate script which just makes an executable file. So, we've prepared a separate script which just makes an executable file.
This build doesn't work on npm v5.3.0. So you need to use v5.2.0 when you build it.
``` ```
grunt pre-build grunt pre-build
``` ```

View File

@@ -2,10 +2,9 @@
Diese Seite ist auch verfügbar in [Japanisch](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Koreanisch](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russisch](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Vereinfachtem Chinesisch](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), [Französisch](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md) und [Deutsch](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md). Diese Seite ist auch verfügbar in [Japanisch](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Koreanisch](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russisch](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Vereinfachtem Chinesisch](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), [Französisch](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md) und [Deutsch](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md).
## Umgebungen ## Umgebungen
* npm: 4.x
* node: 7.x
Du solltest `npm v4.x` benutzen weil `$ grunt pre-build` scheitert mit Version `v5.x`. * npm: 6.x
* node: 8.x
## Entwicklung ## Entwicklung
@@ -21,17 +20,9 @@ $ yarn
Bauen und Ausführen. Bauen und Ausführen.
``` ```
$ yarn run dev-start $ yarn run dev
``` ```
Dieser Befehl startet `yarn run webpack` und `yarn run hot` parallel. Es hat den selben Effekt wie beide Befehle separat in zwei Terminals zu starten.
Das `webpack` überprüft den Code auf Änderungen und wendet diese dann automatisch an.
Wenn folgender Fehler passiert: `Failed to load resource: net::ERR_CONNECTION_REFUSED`, bitte Boostnote neu starten.
![net::ERR_CONNECTION_REFUSED](https://cloud.githubusercontent.com/assets/11307908/24343004/081e66ae-1279-11e7-8d9e-7f478043d835.png)
> ### Notiz > ### Notiz
> Es gibt einige Fälle bei denen die App manuell zu refreshen ist. > Es gibt einige Fälle bei denen die App manuell zu refreshen ist.
> 1. Wenn eine "constructor method" einer Komponente manuell editiert wird. > 1. Wenn eine "constructor method" einer Komponente manuell editiert wird.
@@ -44,11 +35,10 @@ Du kannst das Programm unter Verwendung von `grunt` bauen. Jedoch empfehlen wir
Deshalb haben wir ein separates Script vorbereitet welches eine ausführbare Datei erstellt. Deshalb haben wir ein separates Script vorbereitet welches eine ausführbare Datei erstellt.
Dieser build funktioniert nicht mit npm v5.3.0. Deshalb musst du für den Build die Version v5.2.0 verwenden.
``` ```
grunt pre-build grunt pre-build
``` ```
Du findest die ausführbare Datein in dem Verzeichnis `dist`. Beachte, der auto updater funktioniert nicht da die app nicht signiert ist. Du findest die ausführbare Datein in dem Verzeichnis `dist`. Beachte, der auto updater funktioniert nicht da die app nicht signiert ist.
Wenn du es für notwendig erachtest, kannst du codesign or authenticode mit dieser ausführbaren Datei verwenden. Wenn du es für notwendig erachtest, kannst du codesign or authenticode mit dieser ausführbaren Datei verwenden.

View File

@@ -2,10 +2,9 @@
Cette page est également disponible en [Anglais](https://github.com/BoostIO/Boostnote/blob/master/docs/build.md), [Japonais](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Coréen](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russe](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Chinois Simplifié](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md) et en [Allemand](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md) Cette page est également disponible en [Anglais](https://github.com/BoostIO/Boostnote/blob/master/docs/build.md), [Japonais](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [Coréen](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [Russe](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [Chinois Simplifié](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md) et en [Allemand](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md)
## Environnements ## Environnements
* npm: 4.x
* node: 7.x
Il est conseillé d'utiliser `npm v4.x` car `$ grunt pre-build` ne marche pas sur la `v5.x`. * npm: 6.x
* node: 8.x
## Développement ## Développement
@@ -20,17 +19,9 @@ $ yarn
Build et start Build et start
``` ```
$ yarn run dev-start $ yarn run dev
``` ```
Cette commande lance `yarn run webpack` et `yarn run hot` en parallèle. Cela revient au même que si on utilisait ces deux commandes dans 2 terminaux.
La commande `webpack` va surveiller les changements de code et les appliquer automatiquement.
Si l'erreur suivante apparait : `Failed to load resource: net::ERR_CONNECTION_REFUSED`, relancez Boostnote.
![net::ERR_CONNECTION_REFUSED](https://cloud.githubusercontent.com/assets/11307908/24343004/081e66ae-1279-11e7-8d9e-7f478043d835.png)
> ### Notice > ### Notice
> Il y a certains cas où vous voudrez relancer l'application manuellement. > Il y a certains cas où vous voudrez relancer l'application manuellement.
> 1. Quand vous éditez la méthode constructeur dans un composant > 1. Quand vous éditez la méthode constructeur dans un composant
@@ -43,8 +34,6 @@ Vous pouvez build le programme en utilisant `grunt`. Cependant, nous ne recomman
Nous avons donc préparé un script séparé qui va rendre un fichier exécutable. Nous avons donc préparé un script séparé qui va rendre un fichier exécutable.
Le build ne fonctionne pas sur `npm v5.3.0`. Il faut donc utiliser `npm v5.2.0` quand vous faites le build.
``` ```
grunt pre-build grunt pre-build
``` ```

View File

@@ -1,9 +1,15 @@
# Build # Build
## 環境
* npm: 6.x
* node: 8.x
## 開発 ## 開発
Webpack HRMを使います。 Webpack HRMを使います。
次の命令から私達がしておいた設定を使うことができます。 Boostnoteの最上位ディレクトリにて以下のコマンドを実行して、
デフォルトの設定の開発環境を起動させます。
依存するパッケージをインストールします。 依存するパッケージをインストールします。
@@ -14,30 +20,20 @@ $ yarn
ビルドして実行します。 ビルドして実行します。
``` ```
$ yarn run dev-start $ yarn run dev
``` ```
このコマンドは `yarn run webpack``yarn run hot`を並列に実行します。つまりこのコマンドは2つのターミナルで同時にこれらのコマンドを実行するのと同じことです。
そして、Webpackが自動的にコードの変更を確認し、それを適用してくれるようになります。
もし、 `Failed to load resource: net::ERR_CONNECTION_REFUSED`というエラーが起きた場合、Boostnoteをリロードしてください。
![net::ERR_CONNECTION_REFUSED](https://cloud.githubusercontent.com/assets/11307908/24343004/081e66ae-1279-11e7-8d9e-7f478043d835.png)
> ### 注意 > ### 注意
> 時々、直接リフレッシュをする必要があります。 > 時々、直接リフレッシュをする必要があります。
> 1. コンポネントのコンストラクタ関数を編集する場合 > 1. コンポネントのコンストラクタ関数を編集する場合
> 2. 新しいCSSクラスを追加する場合(1.の理由と同じ: CSSクラス名はコンポネントごとに書きなおされまが、この作業はコンストラクタで行われます。) > 2. 新しいCSSクラスを追加する場合(1.の理由と同じ: CSSクラス名はコンポネントごとに書きなおされまが、この作業はコンストラクタで行われます。)
## 配布 ## 配布
Gruntを使います。 Gruntを使います。
実際の配布は`grunt`で実行できます。しかし、これにはCodesignとAuthenticodeの仮定が含まれるので、使っては行けないです 実際の配布は`grunt`で実行できます。しかし、これにはCodesignとAuthenticodeを実行するタスクが含まれるので、使用しないでください
それで、実行ファイルを作るスクリプトを用意しておきました。 代わりに、実行ファイルを作るスクリプトを用意しておきました。
このビルドはnpm v5.3.0では動かないのでv5.2.0で動かす必要があります。
``` ```
grunt pre-build grunt pre-build

View File

@@ -1,8 +1,9 @@
# Build # Build
## 환경 ## 환경
* npm: 4.x
* node: 7.x * npm: 6.x
* node: 8.x
`$ grunt pre-build``npm v5.x`에서 실행할 수 없기 때문에, 반드시 `npm v4.x`를 사용하셔야 합니다. `$ grunt pre-build``npm v5.x`에서 실행할 수 없기 때문에, 반드시 `npm v4.x`를 사용하셔야 합니다.
@@ -20,17 +21,9 @@ $ yarn
그 다음, 아래의 명령으로 빌드를 끝내고 자동적으로 어플리케이션을 실행합니다. 그 다음, 아래의 명령으로 빌드를 끝내고 자동적으로 어플리케이션을 실행합니다.
``` ```
$ yarn run dev-start $ yarn run dev
``` ```
이 명령은 `yarn run webpack``yarn run hot`을 동시에 실행합니다. 이는 두개의 터미널에서 각각의 명령을 동시에 실행하는 것과 같습니다.
`Webpack`은 코드의 변화를 자동으로 탐지하여 적용시키는 역할을 합니다.
만약, `Failed to load resource: net::ERR_CONNECTION_REFUSED`과 같은 에러가 나타난다면 Boostnote를 리로드해주세요.
![net::ERR_CONNECTION_REFUSED](https://cloud.githubusercontent.com/assets/11307908/24343004/081e66ae-1279-11e7-8d9e-7f478043d835.png)
> ### 주의 > ### 주의
> 가끔 직접 리프레쉬를 해주어야 하는 경우가 있습니다. > 가끔 직접 리프레쉬를 해주어야 하는 경우가 있습니다.
> 1. 콤포넌트의 컨스트럭터 함수를 수정할 경우 > 1. 콤포넌트의 컨스트럭터 함수를 수정할 경우
@@ -43,8 +36,6 @@ Boostnote에서는 배포 자동화를 위하여 그런트를 사용합니다.
그래서, 실행파일만을 만드는 스크립트를 준비해 뒀습니다. 그래서, 실행파일만을 만드는 스크립트를 준비해 뒀습니다.
이 빌드는 npm v5.3.0에서는 작동하지 않습니다. 그러므로, 성공적으로 빌드하기 위해서는 v5.2.0을 사용해야 합니다.
``` ```
grunt pre-build grunt pre-build
``` ```

View File

@@ -1,10 +1,9 @@
# Сборка # Сборка
## Используемые инструменты ## Используемые инструменты
* npm: 4.x
* node: 7.x
Вы должны использовать `npm v4.x`, так как `$ grunt pre-build` не работает в `v5.x`. * npm: 6.x
* node: 8.x
## Разработка ## Разработка
@@ -20,17 +19,9 @@ $ yarn
Соберите и запустите. Соберите и запустите.
``` ```
$ yarn run dev-start $ yarn run dev
``` ```
Эта команда выполняет `yarn run webpack` и `yarn run hot` параллельно. Результат будет такой же, если вы выполните эти две команды раздельно.
`Webpack` будет следить за изменениями в коде и будет применять их автоматически.
Если возникает следующая ошибка: `Failed to load resource: net::ERR_CONNECTION_REFUSED`, пожалуйста, перезапустите Boostnote.
![net::ERR_CONNECTION_REFUSED](https://cloud.githubusercontent.com/assets/11307908/24343004/081e66ae-1279-11e7-8d9e-7f478043d835.png)
> ### Примечание > ### Примечание
> В некоторых случаях вам необходимо обновить приложение вручную. > В некоторых случаях вам необходимо обновить приложение вручную.
> 1. При редактировании метода конструктора компонента > 1. При редактировании метода конструктора компонента
@@ -41,9 +32,7 @@ $ yarn run dev-start
Мы используем Grunt для автоматического деплоя. Мы используем Grunt для автоматического деплоя.
Вы можете создать задачу, используя `grunt`. Однако мы не рекомендуем этого делать, так как задача по умолчанию включает в себя код и аутентификацию. Вы можете создать задачу, используя `grunt`. Однако мы не рекомендуем этого делать, так как задача по умолчанию включает в себя код и аутентификацию.
Мы подготовили отдельный скрипт, который просто создает исполняемый файл: Мы подготовили отдельный скрипт, который просто создает исполняемый файл.
This build doesn't work on npm v5.3.0. So you need to use v5.2.0 when you build it.
``` ```
grunt pre-build grunt pre-build

View File

@@ -1,37 +1,27 @@
# 构建Boostnote # 构建Boostnote
## 环境 ## 环境
* npm: 4.x
* node: 7.x
因为`$ grunt pre-build`的问题,您只能使用`npm v4.x`而不能使用`npm v5.x` * npm: 6.x
* node: 8.x
## 开发 ## 开发
我们使用Webpack HMR来开发Boostnote。 我们使用Webpack HMR来开发Boostnote。
在代码根目录下运行下列指令可以以默认配置运行Boostnote。 在代码根目录下运行下列指令可以以默认配置运行Boostnote。
### 首先使用yarn安装所需的依赖包。 ### 首先使用yarn安装所需的依赖包。
``` ```
$ yarn $ yarn
``` ```
### 接着编译并且运行Boostnote。 ### 接着编译并且运行Boostnote。
``` ```
$ yarn run dev-start $ yarn run dev
``` ```
这个指令相当于在两个终端内同时运行`yarn run webpack``yarn run hot`
如果出现错误`Failed to load resource: net::ERR_CONNECTION_REFUSED`请尝试重新运行Boostnote。
![net::ERR_CONNECTION_REFUSED](https://cloud.githubusercontent.com/assets/11307908/24343004/081e66ae-1279-11e7-8d9e-7f478043d835.png)
### 然后您就可以进行开发了
当您对代码作出更改的时候,`webpack`会自动抓取并应用所有代码更改。
> ### 提示 > ### 提示
> 在如下情况中您可能需要重新运行Boostnote才能应用代码更改 > 在如下情况中您可能需要重新运行Boostnote才能应用代码更改
> 1. 当您在修改了一个组件的构造函数的时候When editing a constructor method of a component > 1. 当您在修改了一个组件的构造函数的时候When editing a constructor method of a component
@@ -39,18 +29,16 @@ $ yarn run dev-start
## 部署 ## 部署
我们使用Grunt来自动部署Boostnote。 我们使用Grunt来自动部署Boostnote。
因为部署需要协同设计(codesign)与验证码(authenticode),所以您可以但我们不建议通过`grunt`来部署。 因为部署需要协同设计(codesign)与验证码(authenticode),所以您可以但我们不建议通过`grunt`来部署。
所以我们准备了一个脚本文件来生成执行文件。 所以我们准备了一个脚本文件来生成执行文件。
``` ```
grunt pre-build grunt pre-build
``` ```
您只能使用`npm v5.2.0`而不能使用`npm v5.3.0` 接下来您就可以在`dist`目录中找到可执行文件。
接下来您就可以在`dist`目录中找到可执行文件。
> ### 提示 > ### 提示
> 因为此可执行文件并没有被注册,所以自动更新不可用。 > 因为此可执行文件并没有被注册,所以自动更新不可用。
> 如果需要,您也可将协同设计(codesign)与验证码(authenticode)使用于这个可执行文件中。 > 如果需要,您也可将协同设计(codesign)与验证码(authenticode)使用于这个可执行文件中。

View File

@@ -2,10 +2,9 @@
此文件還提供下列的語言 [日文](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [韓文](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [俄文](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [簡體中文](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), [法文](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md) and [德文](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md). 此文件還提供下列的語言 [日文](https://github.com/BoostIO/Boostnote/blob/master/docs/jp/build.md), [韓文](https://github.com/BoostIO/Boostnote/blob/master/docs/ko/build.md), [俄文](https://github.com/BoostIO/Boostnote/blob/master/docs/ru/build.md), [簡體中文](https://github.com/BoostIO/Boostnote/blob/master/docs/zh_CN/build.md), [法文](https://github.com/BoostIO/Boostnote/blob/master/docs/fr/build.md) and [德文](https://github.com/BoostIO/Boostnote/blob/master/docs/de/build.md).
## 環境 ## 環境
* npm: 4.x
* node: 7.x
`$ grunt pre-build``npm v5.x` 有問題,所以只能用 `npm v4.x` * npm: 6.x
* node: 8.x
## 開發 ## 開發
@@ -22,18 +21,9 @@ $ yarn
**開始開發** **開始開發**
``` ```
$ yarn run dev-start $ yarn run dev
``` ```
上述指令同時運行了 `yarn run webpack``yarn run hot`,相當於將這兩個指令在不同的 terminal 中運行。
`webpack` 會同時監控修改過的程式碼,並
The `webpack` will watch for code changes and then apply them automatically.
If the following error occurs: `Failed to load resource: net::ERR_CONNECTION_REFUSED`, please reload Boostnote.
![net::ERR_CONNECTION_REFUSED](https://cloud.githubusercontent.com/assets/11307908/24343004/081e66ae-1279-11e7-8d9e-7f478043d835.png)
> ### Notice > ### Notice
> There are some cases where you have to refresh the app manually. > There are some cases where you have to refresh the app manually.
> 1. When editing a constructor method of a component > 1. When editing a constructor method of a component
@@ -46,8 +36,6 @@ You can build the program by using `grunt`. However, we don't recommend this bec
So, we've prepared a separate script which just makes an executable file. So, we've prepared a separate script which just makes an executable file.
This build doesn't work on npm v5.3.0. So you need to use v5.2.0 when you build it.
``` ```
grunt pre-build grunt pre-build
``` ```

View File

@@ -218,6 +218,16 @@ const edit = {
label: 'Select All', label: 'Select All',
accelerator: 'Command+A', accelerator: 'Command+A',
selector: 'selectAll:' selector: 'selectAll:'
},
{
type: 'separator'
},
{
label: 'Add Tag',
accelerator: 'CommandOrControl+Shift+T',
click () {
mainWindow.webContents.send('editor:add-tag')
}
} }
] ]
} }

View File

@@ -7,9 +7,11 @@ const config = new Config()
const _ = require('lodash') const _ = require('lodash')
var showMenu = process.platform !== 'win32' var showMenu = process.platform !== 'win32'
const windowSize = config.get('windowsize') || { width: 1080, height: 720 } const windowSize = config.get('windowsize') || { x: null, y: null, width: 1080, height: 720 }
const mainWindow = new BrowserWindow({ const mainWindow = new BrowserWindow({
x: windowSize.x,
y: windowSize.y,
width: windowSize.width, width: windowSize.width,
height: windowSize.height, height: windowSize.height,
minWidth: 500, minWidth: 500,
@@ -59,6 +61,7 @@ if (process.platform === 'darwin') {
} }
mainWindow.on('resize', _.throttle(storeWindowSize, 500)) mainWindow.on('resize', _.throttle(storeWindowSize, 500))
mainWindow.on('move', _.throttle(storeWindowSize, 500))
function storeWindowSize () { function storeWindowSize () {
try { try {

View File

@@ -1,72 +1,83 @@
<!DOCTYPE html> <!DOCTYPE html>
<html> <html>
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0"/> <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=0" />
<link rel="stylesheet" href="../node_modules/font-awesome/css/font-awesome.min.css" media="screen" charset="utf-8"> <link rel="stylesheet" href="../node_modules/font-awesome/css/font-awesome.min.css" media="screen" charset="utf-8">
<link rel="shortcut icon" href="../resources/favicon.ico"> <link rel="shortcut icon" href="../resources/favicon.ico">
<link rel="stylesheet" href="../node_modules/codemirror/lib/codemirror.css"> <link rel="stylesheet" href="../node_modules/codemirror/lib/codemirror.css">
<link rel="stylesheet" href="../node_modules/katex/dist/katex.min.css">
<link rel="stylesheet" href="../node_modules/codemirror/addon/dialog/dialog.css"> <link rel="stylesheet" href="../node_modules/codemirror/addon/dialog/dialog.css">
<title>Boostnote</title> <title>Boostnote</title>
<style> <style>
@font-face { @font-face {
font-family: 'OpenSans'; font-family: 'OpenSans';
src: url('../resources/fonts/Lato-Regular.woff2') format('woff2'), /* Modern Browsers */ src: url('../resources/fonts/Lato-Regular.woff2') format('woff2'), /* Modern Browsers */
url('../resources/fonts/Lato-Regular.woff') format('woff'), /* Modern Browsers */ url('../resources/fonts/Lato-Regular.woff') format('woff'), /* Modern Browsers */
url('../resources/fonts/Lato-Regular.ttf') format('truetype'); url('../resources/fonts/Lato-Regular.ttf') format('truetype');
font-style: normal; font-style: normal;
font-weight: normal; font-weight: normal;
text-rendering: optimizeLegibility; text-rendering: optimizeLegibility;
} }
@font-face {
font-family: 'Lato'; @font-face {
src: url('../resources/fonts/Lato-Regular.woff2') format('woff2'), /* Modern Browsers */ font-family: 'Lato';
url('../resources/fonts/Lato-Regular.woff') format('woff'), /* Modern Browsers */ src: url('../resources/fonts/Lato-Regular.woff2') format('woff2'), /* Modern Browsers */
url('../resources/fonts/Lato-Regular.ttf') format('truetype'); url('../resources/fonts/Lato-Regular.woff') format('woff'), /* Modern Browsers */
font-style: normal; url('../resources/fonts/Lato-Regular.ttf') format('truetype');
font-weight: normal; font-style: normal;
text-rendering: optimizeLegibility; font-weight: normal;
} text-rendering: optimizeLegibility;
#loadingCover{ }
background-color: #f4f4f4;
position: absolute; #loadingCover {
top: 0; background-color: #f4f4f4;
bottom: 0; position: absolute;
left: 0; top: 0;
right: 0; bottom: 0;
box-sizing: border-box; left: 0;
padding: 65px 0; right: 0;
font-family: sans-serif; box-sizing: border-box;
} padding: 65px 0;
#loadingCover img{ font-family: sans-serif;
display: block; }
margin: 75px auto 5px;
width: 160px; #loadingCover img {
height: 160px; display: block;
} margin: 75px auto 5px;
#loadingCover .message{ width: 160px;
font-size: 30px; height: 160px;
text-align: center; }
line-height: 1.6;
font-weight: 100; #loadingCover .message {
color: #888; font-size: 30px;
} text-align: center;
.CodeEditor { line-height: 1.6;
opacity: 1 !important; font-weight: 100;
pointer-events: auto !important; color: #888;
} }
.CodeMirror-ruler {
border-left-color: rgba(142, 142, 142, 0.5); .CodeEditor {
mix-blend-mode: difference; opacity: 1 !important;
} pointer-events: auto !important;
}
.CodeMirror-ruler {
border-left-color: rgba(142, 142, 142, 0.5);
mix-blend-mode: difference;
}
</style> </style>
</head> </head>
<body> <body>
<div id="loadingCover"> <div id="loadingCover">
<img src="../resources/app.png"> <img src="../resources/app.png">
<div class='message'><i class="fa fa-spinner fa-spin" spin></i></div> <div class='message'>
<i class="fa fa-spinner fa-spin" spin></i>
</div>
</div> </div>
<div id="content"></div> <div id="content"></div>
@@ -130,4 +141,5 @@
} }
</style> </style>
</body> </body>
</html>
</html>

35
package-lock.json generated
View File

@@ -1,35 +0,0 @@
{
"name": "boost",
"version": "0.10.0",
"lockfileVersion": 1,
"requires": true,
"dependencies": {
"debug": {
"version": "3.1.0",
"resolved": "https://registry.npmjs.org/debug/-/debug-3.1.0.tgz",
"integrity": "sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g==",
"requires": {
"ms": "2.0.0"
}
},
"i18n-2": {
"version": "0.7.2",
"resolved": "https://registry.npmjs.org/i18n-2/-/i18n-2-0.7.2.tgz",
"integrity": "sha512-Rdh6vfpNhL7q61cNf27x7QGULTi1TcGLVdFb5OJ6dOiJo+EkOTqEg0+3xgyeEMgYhopUBsh2IiSkFkjM+EhEmA==",
"requires": {
"debug": "3.1.0",
"sprintf": "0.1.5"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
},
"sprintf": {
"version": "0.1.5",
"resolved": "https://registry.npmjs.org/sprintf/-/sprintf-0.1.5.tgz",
"integrity": "sha1-j4PjmpMXwaUCy324BQ5Rxnn27c8="
}
}
}

View File

@@ -7,17 +7,15 @@
"license": "GPL-3.0", "license": "GPL-3.0",
"scripts": { "scripts": {
"start": "electron ./index.js", "start": "electron ./index.js",
"hot": "electron ./index.js --hot",
"webpack": "webpack-dev-server --hot --inline --config webpack.config.js",
"compile": "grunt compile", "compile": "grunt compile",
"test": "PWD=$(pwd) NODE_ENV=test ava --serial", "test": "PWD=$(pwd) NODE_ENV=test ava --serial",
"jest": "jest", "jest": "jest",
"fix": "eslint . --fix", "fix": "eslint . --fix",
"lint": "eslint .", "lint": "eslint .",
"dev-start": "concurrently --kill-others \"npm run webpack\" \"npm run hot\"" "dev": "node dev-scripts/dev.js"
}, },
"config": { "config": {
"electron-version": "2.0.3" "electron-version": "2.0.7"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -57,7 +55,7 @@
"chart.js": "^2.7.2", "chart.js": "^2.7.2",
"codemirror": "^5.39.0", "codemirror": "^5.39.0",
"codemirror-mode-elixir": "^1.1.1", "codemirror-mode-elixir": "^1.1.1",
"electron-config": "^0.2.1", "electron-config": "^1.0.0",
"electron-gh-releases": "^2.0.2", "electron-gh-releases": "^2.0.2",
"escape-string-regexp": "^1.0.5", "escape-string-regexp": "^1.0.5",
"file-url": "^2.0.2", "file-url": "^2.0.2",
@@ -73,7 +71,7 @@
"lodash": "^4.11.1", "lodash": "^4.11.1",
"lodash-move": "^1.1.1", "lodash-move": "^1.1.1",
"markdown-it": "^6.0.1", "markdown-it": "^6.0.1",
"markdown-it-admonition": "https://github.com/johannbre/markdown-it-admonition.git", "markdown-it-admonition": "^1.0.4",
"markdown-it-emoji": "^1.1.1", "markdown-it-emoji": "^1.1.1",
"markdown-it-footnote": "^3.0.0", "markdown-it-footnote": "^3.0.0",
"markdown-it-imsize": "^2.0.1", "markdown-it-imsize": "^2.0.1",
@@ -120,8 +118,8 @@
"css-loader": "^0.19.0", "css-loader": "^0.19.0",
"devtron": "^1.1.0", "devtron": "^1.1.0",
"dom-storage": "^2.0.2", "dom-storage": "^2.0.2",
"electron": "2.0.3", "electron": "2.0.7",
"electron-packager": "^6.0.0", "electron-packager": "^12.0.0",
"eslint": "^3.13.1", "eslint": "^3.13.1",
"eslint-config-standard": "^6.2.1", "eslint-config-standard": "^6.2.1",
"eslint-config-standard-jsx": "^3.2.0", "eslint-config-standard-jsx": "^3.2.0",
@@ -145,6 +143,7 @@
"react-router": "^2.4.0", "react-router": "^2.4.0",
"react-router-redux": "^4.0.4", "react-router-redux": "^4.0.4",
"react-test-renderer": "^15.6.2", "react-test-renderer": "^15.6.2",
"signale": "^1.2.1",
"standard": "^8.4.0", "standard": "^8.4.0",
"style-loader": "^0.12.4", "style-loader": "^0.12.4",
"stylus": "^0.52.4", "stylus": "^0.52.4",

View File

@@ -319,6 +319,21 @@ it('should remove the all ":storage" and noteKey references', function () {
expect(actual).toEqual(expectedOutput) expect(actual).toEqual(expectedOutput)
}) })
it('should make sure that "removeStorageAndNoteReferences" works with markdown content as well', function () {
const noteKey = 'noteKey'
const testInput =
'Test input' +
'![' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + noteKey + path.sep + 'image.jpg](imageName}) \n' +
'[' + systemUnderTest.STORAGE_FOLDER_PLACEHOLDER + path.sep + noteKey + path.sep + 'pdf.pdf](pdf})'
const expectedOutput =
'Test input' +
'![' + systemUnderTest.DESTINATION_FOLDER + path.sep + 'image.jpg](imageName}) \n' +
'[' + systemUnderTest.DESTINATION_FOLDER + path.sep + 'pdf.pdf](pdf})'
const actual = systemUnderTest.removeStorageAndNoteReferences(testInput, noteKey)
expect(actual).toEqual(expectedOutput)
})
it('should delete the correct attachment folder if a note is deleted', function () { it('should delete the correct attachment folder if a note is deleted', function () {
const dummyStorage = {path: 'dummyStoragePath'} const dummyStorage = {path: 'dummyStoragePath'}
const storageKey = 'storageKey' const storageKey = 'storageKey'

View File

@@ -33,13 +33,38 @@ test('escapeHtmlCharacters should NOT skip code block if that option is NOT enab
t.is(actual, expected) t.is(actual, expected)
}) })
test('escapeHtmlCharacters should NOT escape & character if it\'s a part of an escaped character', t => { test("escapeHtmlCharacters should NOT escape & character if it's a part of an escaped character", t => {
const input = 'Do not escape &amp; or &quot; but do escape &' const input = 'Do not escape &amp; or &quot; but do escape &'
const expected = 'Do not escape &amp; or &quot; but do escape &amp;' const expected = 'Do not escape &amp; or &quot; but do escape &amp;'
const actual = escapeHtmlCharacters(input) const actual = escapeHtmlCharacters(input)
t.is(actual, expected) t.is(actual, expected)
}) })
test('escapeHtmlCharacters should skip char if in code block', t => {
const input = `
\`\`\`
<dontescapeme>
\`\`\`
das<das>dasd
dasdasdasd
\`\`\`
<dontescapeme>
\`\`\`
`
const expected = `
\`\`\`
<dontescapeme>
\`\`\`
das&lt;das&gt;dasd
dasdasdasd
\`\`\`
<dontescapeme>
\`\`\`
`
const actual = escapeHtmlCharacters(input, { detectCodeBlock: true })
t.is(actual, expected)
})
test('escapeHtmlCharacters should return the correct result', t => { test('escapeHtmlCharacters should return the correct result', t => {
const input = '& < > " \'' const input = '& < > " \''
const expected = '&amp; &lt; &gt; &quot; &#39;' const expected = '&amp; &lt; &gt; &quot; &#39;'

View File

@@ -12,6 +12,7 @@ test('getTodoStatus should return a correct hash object', t => {
['- [ ] a\n- [x] a\n', { total: 2, completed: 1 }], ['- [ ] a\n- [x] a\n', { total: 2, completed: 1 }],
['+ [ ] a\n', { total: 1, completed: 0 }], ['+ [ ] a\n', { total: 1, completed: 0 }],
['+ [ ] a\n+ [x] a\n', { total: 2, completed: 1 }], ['+ [ ] a\n+ [x] a\n', { total: 2, completed: 1 }],
['+ [ ] a\n+ [X] a\n', { total: 2, completed: 1 }],
['+ [ ] a\n+ [testx] a\n', { total: 1, completed: 0 }], ['+ [ ] a\n+ [testx] a\n', { total: 1, completed: 0 }],
['+ [ ] a\n+ [xtest] a\n', { total: 1, completed: 0 }], ['+ [ ] a\n+ [xtest] a\n', { total: 1, completed: 0 }],
['+ [ ] a\n+ foo[x]bar a\n', { total: 1, completed: 0 }], ['+ [ ] a\n+ foo[x]bar a\n', { total: 1, completed: 0 }],

View File

@@ -5,7 +5,7 @@ const { parse } = require('browser/lib/RcParser')
// Unit test // Unit test
test('RcParser should return a json object', t => { test('RcParser should return a json object', t => {
const validJson = { 'editor': { 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Control + L' }, 'listWidth': 135, 'navWidth': 135 } const validJson = { 'editor': { 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Control + L' }, 'listWidth': 135, 'navWidth': 135 }
const allJson = { 'amaEnabled': true, 'editor': { 'fontFamily': 'Monaco, Consolas', 'fontSize': '14', 'indentSize': '2', 'indentType': 'space', 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Cmd + Alt + L' }, 'isSideNavFolded': false, 'listStyle': 'DEFAULT', 'listWidth': 174, 'navWidth': 200, 'preview': { 'codeBlockTheme': 'dracula', 'fontFamily': 'Lato', 'fontSize': '14', 'lineNumber': true }, 'sortBy': 'UPDATED_AT', 'ui': { 'defaultNote': 'ALWAYS_ASK', 'disableDirectWrite': false, 'theme': 'default' }, 'zoom': 1 } const allJson = { 'amaEnabled': true, 'editor': { 'fontFamily': 'Monaco, Consolas', 'fontSize': '14', 'indentSize': '2', 'indentType': 'space', 'keyMap': 'vim', 'switchPreview': 'BLUR', 'theme': 'monokai' }, 'hotkey': { 'toggleMain': 'Cmd + Alt + L' }, 'isSideNavFolded': false, 'listStyle': 'DEFAULT', 'listWidth': 174, 'navWidth': 200, 'preview': { 'codeBlockTheme': 'dracula', 'fontFamily': 'Lato', 'fontSize': '14', 'lineNumber': true }, 'sortBy': { 'default': 'UPDATED_AT' }, 'ui': { 'defaultNote': 'ALWAYS_ASK', 'disableDirectWrite': false, 'theme': 'default' }, 'zoom': 1 }
// [input, expected] // [input, expected]
const validTestCases = [ const validTestCases = [

View File

@@ -4,20 +4,24 @@ const NodeTargetPlugin = require('webpack/lib/node/NodeTargetPlugin')
var config = { var config = {
entry: { entry: {
main: './browser/main/index.js' main: ['./browser/main/index.js']
}, },
resolve: { resolve: {
extensions: ['', '.js', '.jsx', '.styl'], extensions: ['', '.js', '.jsx', '.styl'],
packageMains: ['webpack', 'browser', 'web', 'browserify', ['jam', 'main'], 'main'], packageMains: [
'webpack',
'browser',
'web',
'browserify',
['jam', 'main'],
'main'
],
alias: { alias: {
'lib': path.join(__dirname, 'lib'), lib: path.join(__dirname, 'lib'),
'browser': path.join(__dirname, 'browser') browser: path.join(__dirname, 'browser')
} }
}, },
plugins: [ plugins: [new webpack.NoErrorsPlugin(), new NodeTargetPlugin()],
new webpack.NoErrorsPlugin(),
new NodeTargetPlugin()
],
stylus: { stylus: {
use: [require('nib')()], use: [require('nib')()],
import: [ import: [
@@ -43,14 +47,13 @@ var config = {
react: 'var React', react: 'var React',
'react-dom': 'var ReactDOM', 'react-dom': 'var ReactDOM',
'react-redux': 'var ReactRedux', 'react-redux': 'var ReactRedux',
'codemirror': 'var CodeMirror', codemirror: 'var CodeMirror',
'redux': 'var Redux', redux: 'var Redux',
'raphael': 'var Raphael', raphael: 'var Raphael',
'flowchart': 'var flowchart', flowchart: 'var flowchart',
'sequence-diagram': 'var Diagram' 'sequence-diagram': 'var Diagram'
} }
] ]
} }
module.exports = config module.exports = config

365
yarn.lock
View File

@@ -358,6 +358,19 @@ asar@^0.12.0:
mksnapshot "^0.3.0" mksnapshot "^0.3.0"
tmp "0.0.28" tmp "0.0.28"
asar@^0.14.0:
version "0.14.3"
resolved "https://registry.yarnpkg.com/asar/-/asar-0.14.3.tgz#c72a81542a48e3bca459fb1b07ee2b6adfae265d"
dependencies:
chromium-pickle-js "^0.2.0"
commander "^2.9.0"
cuint "^0.2.1"
glob "^6.0.4"
minimatch "^3.0.3"
mkdirp "^0.5.0"
mksnapshot "^0.3.0"
tmp "0.0.28"
asar@^0.9.0: asar@^0.9.0:
version "0.9.1" version "0.9.1"
resolved "https://registry.yarnpkg.com/asar/-/asar-0.9.1.tgz#b2f2fe1b49c163013bdb229d6eba2d2078ff5cc4" resolved "https://registry.yarnpkg.com/asar/-/asar-0.9.1.tgz#b2f2fe1b49c163013bdb229d6eba2d2078ff5cc4"
@@ -438,6 +451,10 @@ atob@^2.1.1:
version "2.1.1" version "2.1.1"
resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a" resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.1.tgz#ae2d5a729477f289d60dd7f96a6314a22dd6c22a"
author-regex@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/author-regex/-/author-regex-1.0.0.tgz#d08885be6b9bbf9439fe087c76287245f0a81450"
auto-bind@^1.1.0: auto-bind@^1.1.0:
version "1.2.0" version "1.2.0"
resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-1.2.0.tgz#8b7e318aad53d43ba8a8ecaf0066d85d5f798cd6" resolved "https://registry.yarnpkg.com/auto-bind/-/auto-bind-1.2.0.tgz#8b7e318aad53d43ba8a8ecaf0066d85d5f798cd6"
@@ -1222,9 +1239,9 @@ balanced-match@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767"
base64-js@0.0.8: base64-js@1.2.0:
version "0.0.8" version "1.2.0"
resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-0.0.8.tgz#1101e9544f4a76b1bc3b26d452ca96d7a35e7978" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.2.0.tgz#a39992d723584811982be5e290bb6a53d86700f1"
base64-js@^1.0.2: base64-js@^1.0.2:
version "1.3.0" version "1.3.0"
@@ -1277,7 +1294,7 @@ bluebird@^2.9.30:
version "2.11.0" version "2.11.0"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-2.11.0.tgz#534b9033c022c9579c56ba3b3e5a5caafbb650e1"
bluebird@^3.0.0, bluebird@^3.1.1, bluebird@^3.3.4: bluebird@^3.0.0, bluebird@^3.1.1, bluebird@^3.3.4, bluebird@^3.5.0:
version "3.5.1" version "3.5.1"
resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.1.tgz#d9551f9de98f1fcda1e683d17ee91a0602ee2eb9"
@@ -1396,6 +1413,21 @@ buf-compare@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/buf-compare/-/buf-compare-1.0.1.tgz#fef28da8b8113a0a0db4430b0b6467b69730b34a" resolved "https://registry.yarnpkg.com/buf-compare/-/buf-compare-1.0.1.tgz#fef28da8b8113a0a0db4430b0b6467b69730b34a"
buffer-alloc-unsafe@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
buffer-alloc@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
dependencies:
buffer-alloc-unsafe "^1.1.0"
buffer-fill "^1.0.0"
buffer-fill@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
buffer-from@^1.0.0: buffer-from@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.0.0.tgz#4cb8832d23612589b0406e9e2956c17f06fdf531"
@@ -1572,7 +1604,7 @@ chalk@^1.0.0, chalk@^1.1.1, chalk@^1.1.3:
strip-ansi "^3.0.0" strip-ansi "^3.0.0"
supports-color "^2.0.0" supports-color "^2.0.0"
chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1: chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.3.2, chalk@^2.4.1:
version "2.4.1" version "2.4.1"
resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.1.tgz#18c49ab16a037b6eb0152cc83e3471338215b66e"
dependencies: dependencies:
@@ -1860,6 +1892,10 @@ commondir@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b"
compare-version@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/compare-version/-/compare-version-0.1.2.tgz#0162ec2d9351f5ddd59a9202cba935366a725080"
compare-versions@^3.1.0: compare-versions@^3.1.0:
version "3.2.1" version "3.2.1"
resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.2.1.tgz#a49eb7689d4caaf0b6db5220173fd279614000f7" resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.2.1.tgz#a49eb7689d4caaf0b6db5220173fd279614000f7"
@@ -1928,14 +1964,15 @@ concurrently@^3.4.0:
supports-color "^3.2.3" supports-color "^3.2.3"
tree-kill "^1.1.0" tree-kill "^1.1.0"
conf@^0.11.1: conf@^1.0.0:
version "0.11.2" version "1.4.0"
resolved "https://registry.yarnpkg.com/conf/-/conf-0.11.2.tgz#879f479267600483e502583462ca4063fc9779b2" resolved "https://registry.yarnpkg.com/conf/-/conf-1.4.0.tgz#1ea66c9d7a9b601674a5bb9d2b8dc3c726625e67"
dependencies: dependencies:
dot-prop "^3.0.0" dot-prop "^4.1.0"
env-paths "^0.3.0" env-paths "^1.0.0"
mkdirp "^0.5.1" make-dir "^1.0.0"
pkg-up "^1.0.0" pkg-up "^2.0.0"
write-file-atomic "^2.3.0"
configstore@^3.0.0: configstore@^3.0.0:
version "3.1.2" version "3.1.2"
@@ -2464,7 +2501,7 @@ debug-log@^1.0.0:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f" resolved "https://registry.yarnpkg.com/debug-log/-/debug-log-1.0.1.tgz#2307632d4c04382b8df8a32f70b895046d52745f"
debug@*, debug@^3.0.1, debug@^3.1.0: debug@*, debug@^3.0.0, debug@^3.0.1, debug@^3.1.0:
version "3.1.0" version "3.1.0"
resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261"
dependencies: dependencies:
@@ -2692,12 +2729,6 @@ domutils@^1.5.1:
dom-serializer "0" dom-serializer "0"
domelementtype "1" domelementtype "1"
dot-prop@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-3.0.0.tgz#1b708af094a49c9a0e7dbcad790aba539dac1177"
dependencies:
is-obj "^1.0.0"
dot-prop@^4.1.0: dot-prop@^4.1.0:
version "4.2.0" version "4.2.0"
resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57" resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.0.tgz#1f19e0c2e1aa0e32797c49799f2837ac6af69c57"
@@ -2728,24 +2759,11 @@ ee-first@1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d"
electron-config@^0.2.1: electron-config@^1.0.0:
version "0.2.1" version "1.0.0"
resolved "https://registry.yarnpkg.com/electron-config/-/electron-config-0.2.1.tgz#7e12c26412d06bf3ed3896d0479df162986b95ba" resolved "https://registry.yarnpkg.com/electron-config/-/electron-config-1.0.0.tgz#069d044cc794f04784ae72f12916725d3c8c39af"
dependencies: dependencies:
conf "^0.11.1" conf "^1.0.0"
electron-download@^2.0.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-2.2.1.tgz#3d78af3645c96435e3bf3df9b882a14cc2ca294c"
dependencies:
debug "^2.2.0"
home-path "^1.0.1"
minimist "^1.2.0"
mkdirp "^0.5.0"
mv "^2.0.3"
nugget "^1.5.1"
path-exists "^1.0.0"
rc "^1.1.2"
electron-download@^3.0.1: electron-download@^3.0.1:
version "3.3.0" version "3.3.0"
@@ -2761,6 +2779,20 @@ electron-download@^3.0.1:
semver "^5.3.0" semver "^5.3.0"
sumchecker "^1.2.0" sumchecker "^1.2.0"
electron-download@^4.0.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/electron-download/-/electron-download-4.1.0.tgz#bf932c746f2f87ffcc09d1dd472f2ff6b9187845"
dependencies:
debug "^2.2.0"
env-paths "^1.0.0"
fs-extra "^2.0.0"
minimist "^1.2.0"
nugget "^2.0.0"
path-exists "^3.0.0"
rc "^1.1.2"
semver "^5.3.0"
sumchecker "^2.0.1"
electron-gh-releases@^2.0.2: electron-gh-releases@^2.0.2:
version "2.0.4" version "2.0.4"
resolved "https://registry.yarnpkg.com/electron-gh-releases/-/electron-gh-releases-2.0.4.tgz#198c07a0970fb8e80fcc67bd0b4198a010923dc3" resolved "https://registry.yarnpkg.com/electron-gh-releases/-/electron-gh-releases-2.0.4.tgz#198c07a0970fb8e80fcc67bd0b4198a010923dc3"
@@ -2797,34 +2829,38 @@ electron-installer-redhat@^0.3.0:
word-wrap "^1.1.0" word-wrap "^1.1.0"
yargs "^6.0.0" yargs "^6.0.0"
electron-osx-sign@^0.3.0: electron-osx-sign@^0.4.1:
version "0.3.2" version "0.4.10"
resolved "https://registry.yarnpkg.com/electron-osx-sign/-/electron-osx-sign-0.3.2.tgz#88fa7d6ebadb5d9c79368b96491a0d8c4630146e" resolved "https://registry.yarnpkg.com/electron-osx-sign/-/electron-osx-sign-0.4.10.tgz#be4f3b89b2a75a1dc5f1e7249081ab2929ca3a26"
dependencies: dependencies:
debug "^2.2.0" bluebird "^3.5.0"
minimist "^1.1.1" compare-version "^0.1.2"
run-series "^1.1.1" debug "^2.6.8"
isbinaryfile "^3.0.2"
minimist "^1.2.0"
plist "^2.1.0"
electron-packager@^6.0.0: electron-packager@^12.0.0:
version "6.0.2" version "12.1.0"
resolved "https://registry.yarnpkg.com/electron-packager/-/electron-packager-6.0.2.tgz#8ee00669fe8a36309502732fcfed117d7ee9ac29" resolved "https://registry.yarnpkg.com/electron-packager/-/electron-packager-12.1.0.tgz#048dd4ff3848be19c5873c315b5b312df6215328"
dependencies: dependencies:
asar "^0.11.0" asar "^0.14.0"
electron-download "^2.0.0" debug "^3.0.0"
electron-osx-sign "^0.3.0" electron-download "^4.0.0"
electron-osx-sign "^0.4.1"
extract-zip "^1.0.3" extract-zip "^1.0.3"
fs-extra "^0.26.5" fs-extra "^5.0.0"
get-package-info "0.0.2" galactus "^0.2.1"
minimist "^1.1.1" get-package-info "^1.0.0"
mkdirp "^0.5.0" nodeify "^1.0.1"
mv "^2.0.3" parse-author "^2.0.0"
ncp "^2.0.0" pify "^3.0.0"
object-assign "^4.0.1" plist "^2.0.0"
plist "^1.1.0" rcedit "^1.0.0"
rcedit "^0.5.0"
resolve "^1.1.6" resolve "^1.1.6"
rimraf "^2.3.2" sanitize-filename "^1.6.0"
run-series "^1.1.1" semver "^5.3.0"
yargs-parser "^10.0.0"
electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.47: electron-to-chromium@^1.2.7, electron-to-chromium@^1.3.47:
version "1.3.48" version "1.3.48"
@@ -2841,9 +2877,9 @@ electron-winstaller@^2.2.0:
lodash.template "^4.2.2" lodash.template "^4.2.2"
temp "^0.8.3" temp "^0.8.3"
electron@2.0.3: electron@2.0.7:
version "2.0.3" version "2.0.7"
resolved "https://registry.yarnpkg.com/electron/-/electron-2.0.3.tgz#8e591e820cae2ccdb0c3fd74c6d07834913fc133" resolved "https://registry.yarnpkg.com/electron/-/electron-2.0.7.tgz#f7ce410433298e319032ce31f0e6ffd709ff052c"
dependencies: dependencies:
"@types/node" "^8.0.24" "@types/node" "^8.0.24"
electron-download "^3.0.1" electron-download "^3.0.1"
@@ -2882,9 +2918,9 @@ entities@^1.1.1, entities@~1.1.1:
version "1.1.1" version "1.1.1"
resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0" resolved "https://registry.yarnpkg.com/entities/-/entities-1.1.1.tgz#6e5c2d0a5621b5dadaecef80b90edfb5cd7772f0"
env-paths@^0.3.0: env-paths@^1.0.0:
version "0.3.1" version "1.0.0"
resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-0.3.1.tgz#c30ccfcbc30c890943dc08a85582517ef00da463" resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-1.0.0.tgz#4168133b42bb05c38a35b1ae4397c8298ab369e0"
equal-length@^1.0.0: equal-length@^1.0.0:
version "1.0.1" version "1.0.1"
@@ -3577,6 +3613,13 @@ flatten@^1.0.2:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782" resolved "https://registry.yarnpkg.com/flatten/-/flatten-1.0.2.tgz#dae46a9d78fbe25292258cc1e780a41d95c03782"
flora-colossus@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/flora-colossus/-/flora-colossus-1.0.0.tgz#54729c361edecee014dd441679e1a37c1d773a45"
dependencies:
debug "^3.1.0"
fs-extra "^4.0.0"
flowchart.js@^1.6.5: flowchart.js@^1.6.5:
version "1.11.0" version "1.11.0"
resolved "https://registry.yarnpkg.com/flowchart.js/-/flowchart.js-1.11.0.tgz#e8df60e69d08df90c07ffb09e857d555d8981fc7" resolved "https://registry.yarnpkg.com/flowchart.js/-/flowchart.js-1.11.0.tgz#e8df60e69d08df90c07ffb09e857d555d8981fc7"
@@ -3653,7 +3696,7 @@ fs-extra@0.18.2:
jsonfile "^2.0.0" jsonfile "^2.0.0"
rimraf "^2.2.8" rimraf "^2.2.8"
fs-extra@0.26.7, fs-extra@^0.26.0, fs-extra@^0.26.5, fs-extra@^0.26.7: fs-extra@0.26.7, fs-extra@^0.26.0, fs-extra@^0.26.7:
version "0.26.7" version "0.26.7"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-0.26.7.tgz#9ae1fdd94897798edab76d0918cf42d0c3184fa9"
dependencies: dependencies:
@@ -3681,6 +3724,21 @@ fs-extra@^1.0.0:
jsonfile "^2.1.0" jsonfile "^2.1.0"
klaw "^1.0.0" klaw "^1.0.0"
fs-extra@^2.0.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-2.1.2.tgz#046c70163cef9aad46b0e4a7fa467fb22d71de35"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^2.1.0"
fs-extra@^4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94"
dependencies:
graceful-fs "^4.1.2"
jsonfile "^4.0.0"
universalify "^0.1.0"
fs-extra@^5.0.0: fs-extra@^5.0.0:
version "5.0.0" version "5.0.0"
resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd" resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-5.0.0.tgz#414d0110cdd06705734d055652c5411260c31abd"
@@ -3723,6 +3781,14 @@ function-name-support@^0.2.0:
version "0.2.0" version "0.2.0"
resolved "https://registry.yarnpkg.com/function-name-support/-/function-name-support-0.2.0.tgz#55d3bfaa6eafd505a50f9bc81fdf57564a0bb071" resolved "https://registry.yarnpkg.com/function-name-support/-/function-name-support-0.2.0.tgz#55d3bfaa6eafd505a50f9bc81fdf57564a0bb071"
galactus@^0.2.1:
version "0.2.1"
resolved "https://registry.yarnpkg.com/galactus/-/galactus-0.2.1.tgz#cbed2d20a40c1f5679a35908e2b9415733e78db9"
dependencies:
debug "^3.1.0"
flora-colossus "^1.0.0"
fs-extra "^4.0.0"
gar@^1.0.2: gar@^1.0.2:
version "1.0.3" version "1.0.3"
resolved "https://registry.yarnpkg.com/gar/-/gar-1.0.3.tgz#cd6e954dff11821697a9ed5852c7ac5f18df02ce" resolved "https://registry.yarnpkg.com/gar/-/gar-1.0.3.tgz#cd6e954dff11821697a9ed5852c7ac5f18df02ce"
@@ -3761,13 +3827,14 @@ get-folder-size@^1.0.0:
async "^1.4.2" async "^1.4.2"
gar "^1.0.2" gar "^1.0.2"
get-package-info@0.0.2: get-package-info@^1.0.0:
version "0.0.2" version "1.0.0"
resolved "https://registry.yarnpkg.com/get-package-info/-/get-package-info-0.0.2.tgz#72c38fbee2e76728424a00dc14e24dd1a28c2391" resolved "https://registry.yarnpkg.com/get-package-info/-/get-package-info-1.0.0.tgz#6432796563e28113cd9474dbbd00052985a4999c"
dependencies: dependencies:
bluebird "^3.1.1" bluebird "^3.1.1"
debug "^2.2.0"
lodash.get "^4.0.0" lodash.get "^4.0.0"
resolve "^1.1.6" read-pkg-up "^2.0.0"
get-port@^3.0.0: get-port@^3.0.0:
version "3.2.0" version "3.2.0"
@@ -3840,7 +3907,7 @@ glob@^5.0.5:
once "^1.3.0" once "^1.3.0"
path-is-absolute "^1.0.0" path-is-absolute "^1.0.0"
glob@^6.0.1, glob@^6.0.3, glob@^6.0.4: glob@^6.0.3, glob@^6.0.4:
version "6.0.4" version "6.0.4"
resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22" resolved "https://registry.yarnpkg.com/glob/-/glob-6.0.4.tgz#0f08860f6a155127b2fadd4f9ce24b1aab6e4d22"
dependencies: dependencies:
@@ -4715,6 +4782,10 @@ is-promise@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa" resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-2.1.0.tgz#79a2a9ece7f096e80f36d2b2f3bc16c1ff4bf3fa"
is-promise@~1, is-promise@~1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/is-promise/-/is-promise-1.0.1.tgz#31573761c057e33c2e91aab9e96da08cefbe76e5"
is-property@^1.0.0: is-property@^1.0.0:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84"
@@ -4775,6 +4846,12 @@ isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11"
isbinaryfile@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-3.0.3.tgz#5d6def3edebf6e8ca8cae9c30183a804b5f8be80"
dependencies:
buffer-alloc "^1.2.0"
isexe@^2.0.0: isexe@^2.0.0:
version "2.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10"
@@ -5576,10 +5653,6 @@ lodash.uniq@^4.5.0:
version "4.5.0" version "4.5.0"
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
lodash@^3.5.0:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.12.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1: lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.12.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1:
version "4.17.10" version "4.17.10"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
@@ -5650,9 +5723,9 @@ map-visit@^1.0.0:
dependencies: dependencies:
object-visit "^1.0.0" object-visit "^1.0.0"
"markdown-it-admonition@https://github.com/johannbre/markdown-it-admonition.git": markdown-it-admonition@^1.0.4:
version "1.0.2" version "1.0.4"
resolved "https://github.com/johannbre/markdown-it-admonition.git#e0c0fcd59e9119d6d60ed209aa3d0f1177ec0166" resolved "https://registry.yarnpkg.com/markdown-it-admonition/-/markdown-it-admonition-1.0.4.tgz#d7bbc7eb1fe6168fc8cc304de7a9d8c993acb2f5"
markdown-it-emoji@^1.1.1: markdown-it-emoji@^1.1.1:
version "1.4.0" version "1.4.0"
@@ -6032,14 +6105,6 @@ mute-stream@0.0.5:
version "0.0.5" version "0.0.5"
resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0" resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.5.tgz#8fbfabb0a98a253d3184331f9e8deb7372fac6c0"
mv@^2.0.3:
version "2.1.1"
resolved "https://registry.yarnpkg.com/mv/-/mv-2.1.1.tgz#ae6ce0d6f6d5e0a4f7d893798d03c1ea9559b6a2"
dependencies:
mkdirp "~0.5.1"
ncp "~2.0.0"
rimraf "~2.4.0"
nan@^2.9.2: nan@^2.9.2:
version "2.10.0" version "2.10.0"
resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f" resolved "https://registry.yarnpkg.com/nan/-/nan-2.10.0.tgz#96d0cd610ebd58d4b4de9cc0c6828cda99c7548f"
@@ -6069,10 +6134,6 @@ natural-compare@^1.4.0:
version "1.4.0" version "1.4.0"
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
ncp@^2.0.0, ncp@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/ncp/-/ncp-2.0.0.tgz#195a21d6c46e361d2fb1281ba38b91e9df7bdbb3"
needle@^2.2.0: needle@^2.2.0:
version "2.2.1" version "2.2.1"
resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d" resolved "https://registry.yarnpkg.com/needle/-/needle-2.2.1.tgz#b5e325bd3aae8c2678902fa296f729455d1d3a7d"
@@ -6175,6 +6236,13 @@ node-uuid@~1.4.0:
version "1.4.8" version "1.4.8"
resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907" resolved "https://registry.yarnpkg.com/node-uuid/-/node-uuid-1.4.8.tgz#b040eb0923968afabf8d32fb1f17f1167fdab907"
nodeify@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/nodeify/-/nodeify-1.0.1.tgz#64ab69a7bdbaf03ce107b4f0335c87c0b9e91b1d"
dependencies:
is-promise "~1.0.0"
promise "~1.3.0"
nopt@^3.0.1: nopt@^3.0.1:
version "3.0.6" version "3.0.6"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9"
@@ -6248,18 +6316,6 @@ npmlog@^4.0.2:
gauge "~2.7.3" gauge "~2.7.3"
set-blocking "~2.0.0" set-blocking "~2.0.0"
nugget@^1.5.1:
version "1.6.2"
resolved "https://registry.yarnpkg.com/nugget/-/nugget-1.6.2.tgz#88ca6e03ba5706a99173f5da0902593d6bcae107"
dependencies:
debug "^2.1.3"
minimist "^1.1.0"
pretty-bytes "^1.0.2"
progress-stream "^1.1.0"
request "^2.45.0"
single-line-log "^0.4.1"
throttleit "0.0.2"
nugget@^2.0.0: nugget@^2.0.0:
version "2.0.1" version "2.0.1"
resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0" resolved "https://registry.yarnpkg.com/nugget/-/nugget-2.0.1.tgz#201095a487e1ad36081b3432fa3cada4f8d071b0"
@@ -6498,6 +6554,12 @@ pako@~0.2.0:
version "0.2.9" version "0.2.9"
resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75"
parse-author@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/parse-author/-/parse-author-2.0.0.tgz#d3460bf1ddd0dfaeed42da754242e65fb684a81f"
dependencies:
author-regex "^1.0.0"
parse-glob@^3.0.4: parse-glob@^3.0.4:
version "3.0.4" version "3.0.4"
resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c" resolved "https://registry.yarnpkg.com/parse-glob/-/parse-glob-3.0.4.tgz#b2c376cfb11f35513badd173ef0bb6e3a388391c"
@@ -6548,10 +6610,6 @@ path-browserify@0.0.0:
version "0.0.0" version "0.0.0"
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a" resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.0.tgz#a0b870729aae214005b7d5032ec2cbbb0fb4451a"
path-exists@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-1.0.0.tgz#d5a8998eb71ef37a74c34eb0d9eba6e878eea081"
path-exists@^2.0.0, path-exists@^2.1.0: path-exists@^2.0.0, path-exists@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b"
@@ -6636,7 +6694,7 @@ pinkie@^2.0.0:
version "2.0.4" version "2.0.4"
resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870"
pkg-conf@^2.0.0: pkg-conf@^2.0.0, pkg-conf@^2.1.0:
version "2.1.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058" resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058"
dependencies: dependencies:
@@ -6663,19 +6721,18 @@ pkg-dir@^2.0.0:
dependencies: dependencies:
find-up "^2.1.0" find-up "^2.1.0"
pkg-up@^1.0.0: pkg-up@^2.0.0:
version "1.0.0" version "2.0.0"
resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-1.0.0.tgz#3e08fb461525c4421624a33b9f7e6d0af5b05a26" resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f"
dependencies: dependencies:
find-up "^1.0.0" find-up "^2.1.0"
plist@^1.1.0: plist@^2.0.0, plist@^2.1.0:
version "1.2.0" version "2.1.0"
resolved "https://registry.yarnpkg.com/plist/-/plist-1.2.0.tgz#084b5093ddc92506e259f874b8d9b1afb8c79593" resolved "https://registry.yarnpkg.com/plist/-/plist-2.1.0.tgz#57ccdb7a0821df21831217a3cad54e3e146a1025"
dependencies: dependencies:
base64-js "0.0.8" base64-js "1.2.0"
util-deprecate "1.0.2" xmlbuilder "8.2.2"
xmlbuilder "4.0.0"
xmldom "0.1.x" xmldom "0.1.x"
plur@^2.0.0: plur@^2.0.0:
@@ -7005,6 +7062,12 @@ promise@^7.1.1:
dependencies: dependencies:
asap "~2.0.3" asap "~2.0.3"
promise@~1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/promise/-/promise-1.3.0.tgz#e5cc9a4c8278e4664ffedc01c7da84842b040175"
dependencies:
is-promise "~1"
prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0: prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8, prop-types@^15.6.0:
version "15.6.1" version "15.6.1"
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.1.tgz#36644453564255ddda391191fb3a125cbdf654ca"
@@ -7123,9 +7186,9 @@ rc@^1.0.1, rc@^1.1.2, rc@^1.1.6, rc@^1.1.7:
minimist "^1.2.0" minimist "^1.2.0"
strip-json-comments "~2.0.1" strip-json-comments "~2.0.1"
rcedit@^0.5.0: rcedit@^1.0.0:
version "0.5.1" version "1.1.0"
resolved "https://registry.yarnpkg.com/rcedit/-/rcedit-0.5.1.tgz#d0bdcf5d280a9d1c29da6f118ccce2ce153cef1d" resolved "https://registry.yarnpkg.com/rcedit/-/rcedit-1.1.0.tgz#ae21c28d4efdd78e95fcab7309a5dd084920b16a"
react-codemirror@^0.3.0: react-codemirror@^0.3.0:
version "0.3.0" version "0.3.0"
@@ -7610,7 +7673,7 @@ right-align@^0.1.1:
dependencies: dependencies:
align-text "^0.1.1" align-text "^0.1.1"
rimraf@^2.2.8, rimraf@^2.3.2, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1: rimraf@^2.2.8, rimraf@^2.5.2, rimraf@^2.5.4, rimraf@^2.6.1:
version "2.6.2" version "2.6.2"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.2.tgz#2ed8150d24a16ea8651e6d6ef0f47c4158ce7a36"
dependencies: dependencies:
@@ -7620,12 +7683,6 @@ rimraf@~2.2.6, rimraf@~2.2.8:
version "2.2.8" version "2.2.8"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582" resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.2.8.tgz#e439be2aaee327321952730f99a8929e4fc50582"
rimraf@~2.4.0:
version "2.4.5"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.4.5.tgz#ee710ce5d93a8fdb856fb5ea8ff0e2d75934b2da"
dependencies:
glob "^6.0.1"
ripemd160@0.2.0: ripemd160@0.2.0:
version "0.2.0" version "0.2.0"
resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce" resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-0.2.0.tgz#2bf198bde167cacfa51c0a928e84b68bbe171fce"
@@ -7644,10 +7701,6 @@ run-parallel@^1.1.2:
version "1.1.9" version "1.1.9"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
run-series@^1.1.1:
version "1.1.8"
resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.8.tgz#2c4558f49221e01cd6371ff4e0a1e203e460fc36"
rw@1: rw@1:
version "1.3.3" version "1.3.3"
resolved "http://registry.npm.taobao.org/rw/download/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4" resolved "http://registry.npm.taobao.org/rw/download/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
@@ -7702,6 +7755,12 @@ sane@^2.0.0:
optionalDependencies: optionalDependencies:
fsevents "^1.2.3" fsevents "^1.2.3"
sanitize-filename@^1.6.0:
version "1.6.1"
resolved "https://registry.yarnpkg.com/sanitize-filename/-/sanitize-filename-1.6.1.tgz#612da1c96473fa02dccda92dcd5b4ab164a6772a"
dependencies:
truncate-utf8-bytes "^1.0.0"
sanitize-html@^1.18.2: sanitize-html@^1.18.2:
version "1.18.2" version "1.18.2"
resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.18.2.tgz#61877ba5a910327e42880a28803c2fbafa8e4642" resolved "https://registry.yarnpkg.com/sanitize-html/-/sanitize-html-1.18.2.tgz#61877ba5a910327e42880a28803c2fbafa8e4642"
@@ -7858,9 +7917,13 @@ signal-exit@^3.0.0, signal-exit@^3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.2.tgz#b5fdc08f1287ea1178628e415e25132b73646c6d"
single-line-log@^0.4.1: signale@^1.2.1:
version "0.4.1" version "1.2.1"
resolved "https://registry.yarnpkg.com/single-line-log/-/single-line-log-0.4.1.tgz#87a55649f749d783ec0dcd804e8140d9873c7cee" resolved "https://registry.yarnpkg.com/signale/-/signale-1.2.1.tgz#fbd4b952603ea3315dbe9e88f4f482f336cee828"
dependencies:
chalk "^2.3.2"
figures "^2.0.0"
pkg-conf "^2.1.0"
single-line-log@^1.1.2: single-line-log@^1.1.2:
version "1.1.2" version "1.1.2"
@@ -8299,6 +8362,12 @@ sumchecker@^1.2.0:
debug "^2.2.0" debug "^2.2.0"
es6-promise "^4.0.5" es6-promise "^4.0.5"
sumchecker@^2.0.1:
version "2.0.2"
resolved "https://registry.yarnpkg.com/sumchecker/-/sumchecker-2.0.2.tgz#0f42c10e5d05da5d42eea3e56c3399a37d6c5b3e"
dependencies:
debug "^2.2.0"
supertap@^1.0.0: supertap@^1.0.0:
version "1.0.0" version "1.0.0"
resolved "https://registry.yarnpkg.com/supertap/-/supertap-1.0.0.tgz#bd9751c7fafd68c68cf8222a29892206a119fa9e" resolved "https://registry.yarnpkg.com/supertap/-/supertap-1.0.0.tgz#bd9751c7fafd68c68cf8222a29892206a119fa9e"
@@ -8551,6 +8620,12 @@ trim-right@^1.0.1:
version "1.0.1" version "1.0.1"
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003" resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
truncate-utf8-bytes@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/truncate-utf8-bytes/-/truncate-utf8-bytes-1.0.2.tgz#405923909592d56f78a5818434b0b78489ca5f2b"
dependencies:
utf8-byte-length "^1.0.1"
tty-browserify@0.0.0: tty-browserify@0.0.0:
version "0.0.0" version "0.0.0"
resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6"
@@ -8768,7 +8843,11 @@ user-home@^2.0.0:
dependencies: dependencies:
os-homedir "^1.0.0" os-homedir "^1.0.0"
util-deprecate@1.0.2, util-deprecate@~1.0.1: utf8-byte-length@^1.0.1:
version "1.0.4"
resolved "https://registry.yarnpkg.com/utf8-byte-length/-/utf8-byte-length-1.0.4.tgz#f45f150c4c66eee968186505ab93fcbb8ad6bf61"
util-deprecate@~1.0.1:
version "1.0.2" version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
@@ -9059,7 +9138,7 @@ write-file-atomic@^1.1.4:
imurmurhash "^0.1.4" imurmurhash "^0.1.4"
slide "^1.1.5" slide "^1.1.5"
write-file-atomic@^2.0.0, write-file-atomic@^2.1.0: write-file-atomic@^2.0.0, write-file-atomic@^2.1.0, write-file-atomic@^2.3.0:
version "2.3.0" version "2.3.0"
resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab" resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.3.0.tgz#1ff61575c2e2a4e8e510d6fa4e243cce183999ab"
dependencies: dependencies:
@@ -9117,11 +9196,9 @@ xml2js@0.4.17:
sax ">=0.6.0" sax ">=0.6.0"
xmlbuilder "^4.1.0" xmlbuilder "^4.1.0"
xmlbuilder@4.0.0: xmlbuilder@8.2.2:
version "4.0.0" version "8.2.2"
resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-4.0.0.tgz#98b8f651ca30aa624036f127d11cc66dc7b907a3" resolved "https://registry.yarnpkg.com/xmlbuilder/-/xmlbuilder-8.2.2.tgz#69248673410b4ba42e1a6136551d2922335aa773"
dependencies:
lodash "^3.5.0"
xmlbuilder@^4.1.0: xmlbuilder@^4.1.0:
version "4.2.1" version "4.2.1"
@@ -9159,6 +9236,12 @@ yallist@^3.0.0, yallist@^3.0.2:
version "3.0.2" version "3.0.2"
resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9" resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.0.2.tgz#8452b4bb7e83c7c188d8041c1a837c773d6d8bb9"
yargs-parser@^10.0.0:
version "10.1.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8"
dependencies:
camelcase "^4.1.0"
yargs-parser@^4.2.0: yargs-parser@^4.2.0:
version "4.2.1" version "4.2.1"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-4.2.1.tgz#29cceac0dc4f03c6c87b4a9f217dd18c9f74871c"