mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-13 17:56:25 +00:00
Merge branch 'master' of https://github.com/BoostIO/Boostnote
This commit is contained in:
@@ -1,4 +1,4 @@
|
|||||||
# EditorConfig is awesome: http://EditorConfig.org
|
# EditorConfig is awesome: https://EditorConfig.org
|
||||||
|
|
||||||
# top-most EditorConfig file
|
# top-most EditorConfig file
|
||||||
root = true
|
root = true
|
||||||
|
|||||||
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@@ -17,7 +17,7 @@
|
|||||||
"${workspaceFolder}/index.js"
|
"${workspaceFolder}/index.js"
|
||||||
],
|
],
|
||||||
"windows": {
|
"windows": {
|
||||||
"runtimeExecutable": "${workspaceFolder}/node_modeules/.bin/electron.cmd"
|
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
|||||||
72
Backers.md
72
Backers.md
@@ -1,72 +0,0 @@
|
|||||||
<h1 align="center">Sponsors & Backers</h1>
|
|
||||||
|
|
||||||
Boostnote is an open source project. It's an independent project with its ongoing development made possible entirely thanks to the support by these awesome backers. If you'd like to join them, please consider:
|
|
||||||
|
|
||||||
- [Become a backer or sponsor on Open Collective.](https://opencollective.com/boostnoteio)
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Backers via OpenCollective
|
|
||||||
|
|
||||||
### [Gold Sponsors / $1,000 per month](https://opencollective.com/boostnoteio/order/2259)
|
|
||||||
- Get your logo on our Readme.md on GitHub and the frontpage of https://boostnote.io/.
|
|
||||||
|
|
||||||
### [Silver Sponsors / $250 per month](https://opencollective.com/boostnoteio/order/2257)
|
|
||||||
- Get your logo on our Readme.md on GitHub and the frontpage of https://boostnote.io/.
|
|
||||||
|
|
||||||
### [Bronze Sponsors / $50 per month](https://opencollective.com/boostnoteio/order/2258)
|
|
||||||
- Get your name and Url (or E-mail) on Readme.md on GitHub.
|
|
||||||
|
|
||||||
### [Backers3 / $10 per month](https://opencollective.com/boostnoteio/order/2176)
|
|
||||||
- [Ralph03](https://opencollective.com/ralph03)
|
|
||||||
|
|
||||||
- [Nikolas Dan](https://opencollective.com/nikolas-dan)
|
|
||||||
|
|
||||||
### [Backers2 / $5 per month](https://opencollective.com/boostnoteio/order/2175)
|
|
||||||
- [Yeojong Kim](https://twitter.com/yeojoy)
|
|
||||||
|
|
||||||
- [Scotia Draven](https://opencollective.com/scotia-draven)
|
|
||||||
|
|
||||||
- [A. J. Vargas](https://opencollective.com/aj-vargas)
|
|
||||||
|
|
||||||
### [Backers1](https://opencollective.com/boostnoteio/order/2563) and One-time sponsors
|
|
||||||
- Ryosuke Tamura - $30
|
|
||||||
|
|
||||||
- tatoosh11 - $10
|
|
||||||
|
|
||||||
- Alexander Borovkov - $10
|
|
||||||
|
|
||||||
- spoonhoop - $5
|
|
||||||
|
|
||||||
- Drew Williams - $2
|
|
||||||
|
|
||||||
- Andy Shaw - $2
|
|
||||||
|
|
||||||
- mysafesky -$2
|
|
||||||
|
|
||||||
---
|
|
||||||
|
|
||||||
## Backers via Bountysource
|
|
||||||
https://salt.bountysource.com/teams/boostnote
|
|
||||||
|
|
||||||
- Kuzz - $65
|
|
||||||
|
|
||||||
- Intense Raiden - $45
|
|
||||||
|
|
||||||
- ravy22 - $25
|
|
||||||
|
|
||||||
- trentpolack - $20
|
|
||||||
|
|
||||||
- hikariru - $10
|
|
||||||
|
|
||||||
- kolchan11 - $10
|
|
||||||
|
|
||||||
- RonWalker22 - $10
|
|
||||||
|
|
||||||
- hocchuc - $5
|
|
||||||
|
|
||||||
- Adam - $5
|
|
||||||
|
|
||||||
- Steve - $5
|
|
||||||
|
|
||||||
- evmin - $5
|
|
||||||
29
FAQ.md
Normal file
29
FAQ.md
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
# Frequently Asked Questions
|
||||||
|
|
||||||
|
|
||||||
|
<details><summary>Allowing dangerous HTML tags</summary>
|
||||||
|
|
||||||
|
Sometimes it is useful to allow dangerous HTML tags to add interactivity to your notebook. One of the example is to use details/summary as a way to expand/collaps your todo-list.
|
||||||
|
|
||||||
|
* How to enable:
|
||||||
|
* Go to **Preferences** → **Interface** → **Sanitization** → **Allow dangerous html tags**
|
||||||
|
* Example note: Multiple todo-list
|
||||||
|
* Create new notes
|
||||||
|
* Paste the below code, and you'll see that you can expand/collaps the todo-list, and you can have multiple todo-list in your note.
|
||||||
|
|
||||||
|
```html
|
||||||
|
<details><summary>What I want to do</summary>
|
||||||
|
|
||||||
|
- [x] Create an awesome feature X
|
||||||
|
- [ ] Do my homework
|
||||||
|
|
||||||
|
</details>
|
||||||
|
```
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
|
## Other questions
|
||||||
|
|
||||||
|
You can ask [here][ISSUES]
|
||||||
|
|
||||||
|
[ISSUES]: https://github.com/BoostIO/Boostnote/issues
|
||||||
@@ -2,10 +2,15 @@ import PropTypes from 'prop-types'
|
|||||||
import React from 'react'
|
import React from 'react'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import CodeMirror from 'codemirror'
|
import CodeMirror from 'codemirror'
|
||||||
|
import hljs from 'highlight.js'
|
||||||
import 'codemirror-mode-elixir'
|
import 'codemirror-mode-elixir'
|
||||||
import attachmentManagement from 'browser/main/lib/dataApi/attachmentManagement'
|
import attachmentManagement from 'browser/main/lib/dataApi/attachmentManagement'
|
||||||
import convertModeName from 'browser/lib/convertModeName'
|
import convertModeName from 'browser/lib/convertModeName'
|
||||||
import { options, TableEditor, Alignment } from '@susisu/mte-kernel'
|
import {
|
||||||
|
options,
|
||||||
|
TableEditor,
|
||||||
|
Alignment
|
||||||
|
} from '@susisu/mte-kernel'
|
||||||
import TextEditorInterface from 'browser/lib/TextEditorInterface'
|
import TextEditorInterface from 'browser/lib/TextEditorInterface'
|
||||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||||
import iconv from 'iconv-lite'
|
import iconv from 'iconv-lite'
|
||||||
@@ -18,17 +23,100 @@ import normalizeEditorFontFamily from 'browser/lib/normalizeEditorFontFamily'
|
|||||||
const spellcheck = require('browser/lib/spellcheck')
|
const spellcheck = require('browser/lib/spellcheck')
|
||||||
const buildEditorContextMenu = require('browser/lib/contextMenuBuilder')
|
const buildEditorContextMenu = require('browser/lib/contextMenuBuilder')
|
||||||
import TurndownService from 'turndown'
|
import TurndownService from 'turndown'
|
||||||
import { gfm } from 'turndown-plugin-gfm'
|
import {
|
||||||
|
gfm
|
||||||
|
} from 'turndown-plugin-gfm'
|
||||||
|
|
||||||
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
|
||||||
|
})) : [])
|
||||||
|
|
||||||
function translateHotkey (hotkey) {
|
function translateHotkey (hotkey) {
|
||||||
return hotkey.replace(/\s*\+\s*/g, '-').replace(/Command/g, 'Cmd').replace(/Control/g, 'Ctrl')
|
return hotkey.replace(/\s*\+\s*/g, '-').replace(/Command/g, 'Cmd').replace(/Control/g, 'Ctrl')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const languageMaps = {
|
||||||
|
brainfuck: 'Brainfuck',
|
||||||
|
cpp: 'C++',
|
||||||
|
cs: 'C#',
|
||||||
|
clojure: 'Clojure',
|
||||||
|
'clojure-repl': 'ClojureScript',
|
||||||
|
cmake: 'CMake',
|
||||||
|
coffeescript: 'CoffeeScript',
|
||||||
|
crystal: 'Crystal',
|
||||||
|
css: 'CSS',
|
||||||
|
d: 'D',
|
||||||
|
dart: 'Dart',
|
||||||
|
delphi: 'Pascal',
|
||||||
|
diff: 'Diff',
|
||||||
|
django: 'Django',
|
||||||
|
dockerfile: 'Dockerfile',
|
||||||
|
ebnf: 'EBNF',
|
||||||
|
elm: 'Elm',
|
||||||
|
erlang: 'Erlang',
|
||||||
|
'erlang-repl': 'Erlang',
|
||||||
|
fortran: 'Fortran',
|
||||||
|
fsharp: 'F#',
|
||||||
|
gherkin: 'Gherkin',
|
||||||
|
go: 'Go',
|
||||||
|
groovy: 'Groovy',
|
||||||
|
haml: 'HAML',
|
||||||
|
haskell: 'Haskell',
|
||||||
|
haxe: 'Haxe',
|
||||||
|
http: 'HTTP',
|
||||||
|
ini: 'toml',
|
||||||
|
java: 'Java',
|
||||||
|
javascript: 'JavaScript',
|
||||||
|
json: 'JSON',
|
||||||
|
julia: 'Julia',
|
||||||
|
kotlin: 'Kotlin',
|
||||||
|
less: 'LESS',
|
||||||
|
livescript: 'LiveScript',
|
||||||
|
lua: 'Lua',
|
||||||
|
markdown: 'Markdown',
|
||||||
|
mathematica: 'Mathematica',
|
||||||
|
nginx: 'Nginx',
|
||||||
|
nsis: 'NSIS',
|
||||||
|
objectivec: 'Objective-C',
|
||||||
|
ocaml: 'Ocaml',
|
||||||
|
perl: 'Perl',
|
||||||
|
php: 'PHP',
|
||||||
|
powershell: 'PowerShell',
|
||||||
|
properties: 'Properties files',
|
||||||
|
protobuf: 'ProtoBuf',
|
||||||
|
python: 'Python',
|
||||||
|
puppet: 'Puppet',
|
||||||
|
q: 'Q',
|
||||||
|
r: 'R',
|
||||||
|
ruby: 'Ruby',
|
||||||
|
rust: 'Rust',
|
||||||
|
sas: 'SAS',
|
||||||
|
scala: 'Scala',
|
||||||
|
scheme: 'Scheme',
|
||||||
|
scss: 'SCSS',
|
||||||
|
shell: 'Shell',
|
||||||
|
smalltalk: 'Smalltalk',
|
||||||
|
sml: 'SML',
|
||||||
|
sql: 'SQL',
|
||||||
|
stylus: 'Stylus',
|
||||||
|
swift: 'Swift',
|
||||||
|
tcl: 'Tcl',
|
||||||
|
tex: 'LaTex',
|
||||||
|
typescript: 'TypeScript',
|
||||||
|
twig: 'Twig',
|
||||||
|
vbnet: 'VB.NET',
|
||||||
|
vbscript: 'VBScript',
|
||||||
|
verilog: 'Verilog',
|
||||||
|
vhdl: 'VHDL',
|
||||||
|
xml: 'HTML',
|
||||||
|
xquery: 'XQuery',
|
||||||
|
yaml: 'YAML',
|
||||||
|
elixir: 'Elixir'
|
||||||
|
}
|
||||||
|
|
||||||
export default class CodeEditor extends React.Component {
|
export default class CodeEditor extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
@@ -38,6 +126,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
trailing: true
|
trailing: true
|
||||||
})
|
})
|
||||||
this.changeHandler = (editor, changeObject) => this.handleChange(editor, changeObject)
|
this.changeHandler = (editor, changeObject) => this.handleChange(editor, changeObject)
|
||||||
|
this.highlightHandler = (editor, changeObject) => this.handleHighlight(editor, changeObject)
|
||||||
this.focusHandler = () => {
|
this.focusHandler = () => {
|
||||||
ipcRenderer.send('editor:focused', true)
|
ipcRenderer.send('editor:focused', true)
|
||||||
}
|
}
|
||||||
@@ -53,7 +142,10 @@ 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(
|
attachmentManagement.deleteAttachmentsNotPresentInNote(
|
||||||
this.editor.getValue(),
|
this.editor.getValue(),
|
||||||
storageKey,
|
storageKey,
|
||||||
@@ -123,7 +215,9 @@ export default class CodeEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleFormatTable () {
|
handleFormatTable () {
|
||||||
this.tableEditor.formatAll(options({textWidthOptions: {}}))
|
this.tableEditor.formatAll(options({
|
||||||
|
textWidthOptions: {}
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
handleEditorActivity () {
|
handleEditorActivity () {
|
||||||
@@ -177,6 +271,9 @@ export default class CodeEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
'Cmd-Left': function (cm) {
|
||||||
|
cm.execCommand('goLineLeft')
|
||||||
|
},
|
||||||
'Cmd-T': function (cm) {
|
'Cmd-T': function (cm) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
},
|
},
|
||||||
@@ -235,6 +332,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
this.editor = CodeMirror(this.refs.root, {
|
this.editor = CodeMirror(this.refs.root, {
|
||||||
rulers: buildCMRulers(rulers, enableRulers),
|
rulers: buildCMRulers(rulers, enableRulers),
|
||||||
value: this.props.value,
|
value: this.props.value,
|
||||||
|
linesHighlighted: this.props.linesHighlighted,
|
||||||
lineNumbers: this.props.displayLineNumbers,
|
lineNumbers: this.props.displayLineNumbers,
|
||||||
lineWrapping: true,
|
lineWrapping: true,
|
||||||
theme: this.props.theme,
|
theme: this.props.theme,
|
||||||
@@ -248,19 +346,24 @@ export default class CodeEditor extends React.Component {
|
|||||||
foldGutter: true,
|
foldGutter: true,
|
||||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
||||||
autoCloseBrackets: {
|
autoCloseBrackets: {
|
||||||
pairs: '()[]{}\'\'""$$**``',
|
pairs: this.props.matchingPairs,
|
||||||
triples: '```"""\'\'\'',
|
triples: this.props.matchingTriples,
|
||||||
explode: '[]{}``$$',
|
explode: this.props.explodingPairs,
|
||||||
override: true
|
override: true
|
||||||
},
|
},
|
||||||
extraKeys: this.defaultKeyMap
|
extraKeys: this.defaultKeyMap
|
||||||
})
|
})
|
||||||
|
|
||||||
this.setMode(this.props.mode)
|
if (!this.props.mode && this.props.value && this.props.autoDetect) {
|
||||||
|
this.autoDetectLanguage(this.props.value)
|
||||||
|
} else {
|
||||||
|
this.setMode(this.props.mode)
|
||||||
|
}
|
||||||
|
|
||||||
this.editor.on('focus', this.focusHandler)
|
this.editor.on('focus', this.focusHandler)
|
||||||
this.editor.on('blur', this.blurHandler)
|
this.editor.on('blur', this.blurHandler)
|
||||||
this.editor.on('change', this.changeHandler)
|
this.editor.on('change', this.changeHandler)
|
||||||
|
this.editor.on('gutterClick', this.highlightHandler)
|
||||||
this.editor.on('paste', this.pasteHandler)
|
this.editor.on('paste', this.pasteHandler)
|
||||||
if (this.props.switchPreview !== 'RIGHTCLICK') {
|
if (this.props.switchPreview !== 'RIGHTCLICK') {
|
||||||
this.editor.on('contextmenu', this.contextMenuHandler)
|
this.editor.on('contextmenu', this.contextMenuHandler)
|
||||||
@@ -292,43 +395,117 @@ export default class CodeEditor extends React.Component {
|
|||||||
})
|
})
|
||||||
|
|
||||||
this.editorKeyMap = CodeMirror.normalizeKeyMap({
|
this.editorKeyMap = CodeMirror.normalizeKeyMap({
|
||||||
'Tab': () => { this.tableEditor.nextCell(this.tableEditorOptions) },
|
'Tab': () => {
|
||||||
'Shift-Tab': () => { this.tableEditor.previousCell(this.tableEditorOptions) },
|
this.tableEditor.nextCell(this.tableEditorOptions)
|
||||||
'Enter': () => { this.tableEditor.nextRow(this.tableEditorOptions) },
|
},
|
||||||
'Ctrl-Enter': () => { this.tableEditor.escape(this.tableEditorOptions) },
|
'Shift-Tab': () => {
|
||||||
'Cmd-Enter': () => { this.tableEditor.escape(this.tableEditorOptions) },
|
this.tableEditor.previousCell(this.tableEditorOptions)
|
||||||
'Shift-Ctrl-Left': () => { this.tableEditor.alignColumn(Alignment.LEFT, this.tableEditorOptions) },
|
},
|
||||||
'Shift-Cmd-Left': () => { this.tableEditor.alignColumn(Alignment.LEFT, this.tableEditorOptions) },
|
'Enter': () => {
|
||||||
'Shift-Ctrl-Right': () => { this.tableEditor.alignColumn(Alignment.RIGHT, this.tableEditorOptions) },
|
this.tableEditor.nextRow(this.tableEditorOptions)
|
||||||
'Shift-Cmd-Right': () => { this.tableEditor.alignColumn(Alignment.RIGHT, this.tableEditorOptions) },
|
},
|
||||||
'Shift-Ctrl-Up': () => { this.tableEditor.alignColumn(Alignment.CENTER, this.tableEditorOptions) },
|
'Ctrl-Enter': () => {
|
||||||
'Shift-Cmd-Up': () => { this.tableEditor.alignColumn(Alignment.CENTER, this.tableEditorOptions) },
|
this.tableEditor.escape(this.tableEditorOptions)
|
||||||
'Shift-Ctrl-Down': () => { this.tableEditor.alignColumn(Alignment.NONE, this.tableEditorOptions) },
|
},
|
||||||
'Shift-Cmd-Down': () => { this.tableEditor.alignColumn(Alignment.NONE, this.tableEditorOptions) },
|
'Cmd-Enter': () => {
|
||||||
'Ctrl-Left': () => { this.tableEditor.moveFocus(0, -1, this.tableEditorOptions) },
|
this.tableEditor.escape(this.tableEditorOptions)
|
||||||
'Cmd-Left': () => { this.tableEditor.moveFocus(0, -1, this.tableEditorOptions) },
|
},
|
||||||
'Ctrl-Right': () => { this.tableEditor.moveFocus(0, 1, this.tableEditorOptions) },
|
'Shift-Ctrl-Left': () => {
|
||||||
'Cmd-Right': () => { this.tableEditor.moveFocus(0, 1, this.tableEditorOptions) },
|
this.tableEditor.alignColumn(Alignment.LEFT, this.tableEditorOptions)
|
||||||
'Ctrl-Up': () => { this.tableEditor.moveFocus(-1, 0, this.tableEditorOptions) },
|
},
|
||||||
'Cmd-Up': () => { this.tableEditor.moveFocus(-1, 0, this.tableEditorOptions) },
|
'Shift-Cmd-Left': () => {
|
||||||
'Ctrl-Down': () => { this.tableEditor.moveFocus(1, 0, this.tableEditorOptions) },
|
this.tableEditor.alignColumn(Alignment.LEFT, this.tableEditorOptions)
|
||||||
'Cmd-Down': () => { this.tableEditor.moveFocus(1, 0, this.tableEditorOptions) },
|
},
|
||||||
'Ctrl-K Ctrl-I': () => { this.tableEditor.insertRow(this.tableEditorOptions) },
|
'Shift-Ctrl-Right': () => {
|
||||||
'Cmd-K Cmd-I': () => { this.tableEditor.insertRow(this.tableEditorOptions) },
|
this.tableEditor.alignColumn(Alignment.RIGHT, this.tableEditorOptions)
|
||||||
'Ctrl-L Ctrl-I': () => { this.tableEditor.deleteRow(this.tableEditorOptions) },
|
},
|
||||||
'Cmd-L Cmd-I': () => { this.tableEditor.deleteRow(this.tableEditorOptions) },
|
'Shift-Cmd-Right': () => {
|
||||||
'Ctrl-K Ctrl-J': () => { this.tableEditor.insertColumn(this.tableEditorOptions) },
|
this.tableEditor.alignColumn(Alignment.RIGHT, this.tableEditorOptions)
|
||||||
'Cmd-K Cmd-J': () => { this.tableEditor.insertColumn(this.tableEditorOptions) },
|
},
|
||||||
'Ctrl-L Ctrl-J': () => { this.tableEditor.deleteColumn(this.tableEditorOptions) },
|
'Shift-Ctrl-Up': () => {
|
||||||
'Cmd-L Cmd-J': () => { this.tableEditor.deleteColumn(this.tableEditorOptions) },
|
this.tableEditor.alignColumn(Alignment.CENTER, this.tableEditorOptions)
|
||||||
'Alt-Shift-Ctrl-Left': () => { this.tableEditor.moveColumn(-1, this.tableEditorOptions) },
|
},
|
||||||
'Alt-Shift-Cmd-Left': () => { this.tableEditor.moveColumn(-1, this.tableEditorOptions) },
|
'Shift-Cmd-Up': () => {
|
||||||
'Alt-Shift-Ctrl-Right': () => { this.tableEditor.moveColumn(1, this.tableEditorOptions) },
|
this.tableEditor.alignColumn(Alignment.CENTER, this.tableEditorOptions)
|
||||||
'Alt-Shift-Cmd-Right': () => { this.tableEditor.moveColumn(1, this.tableEditorOptions) },
|
},
|
||||||
'Alt-Shift-Ctrl-Up': () => { this.tableEditor.moveRow(-1, this.tableEditorOptions) },
|
'Shift-Ctrl-Down': () => {
|
||||||
'Alt-Shift-Cmd-Up': () => { this.tableEditor.moveRow(-1, this.tableEditorOptions) },
|
this.tableEditor.alignColumn(Alignment.NONE, this.tableEditorOptions)
|
||||||
'Alt-Shift-Ctrl-Down': () => { this.tableEditor.moveRow(1, this.tableEditorOptions) },
|
},
|
||||||
'Alt-Shift-Cmd-Down': () => { this.tableEditor.moveRow(1, this.tableEditorOptions) }
|
'Shift-Cmd-Down': () => {
|
||||||
|
this.tableEditor.alignColumn(Alignment.NONE, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Ctrl-Left': () => {
|
||||||
|
this.tableEditor.moveFocus(0, -1, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Cmd-Left': () => {
|
||||||
|
this.tableEditor.moveFocus(0, -1, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Ctrl-Right': () => {
|
||||||
|
this.tableEditor.moveFocus(0, 1, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Cmd-Right': () => {
|
||||||
|
this.tableEditor.moveFocus(0, 1, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Ctrl-Up': () => {
|
||||||
|
this.tableEditor.moveFocus(-1, 0, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Cmd-Up': () => {
|
||||||
|
this.tableEditor.moveFocus(-1, 0, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Ctrl-Down': () => {
|
||||||
|
this.tableEditor.moveFocus(1, 0, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Cmd-Down': () => {
|
||||||
|
this.tableEditor.moveFocus(1, 0, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Ctrl-K Ctrl-I': () => {
|
||||||
|
this.tableEditor.insertRow(this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Cmd-K Cmd-I': () => {
|
||||||
|
this.tableEditor.insertRow(this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Ctrl-L Ctrl-I': () => {
|
||||||
|
this.tableEditor.deleteRow(this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Cmd-L Cmd-I': () => {
|
||||||
|
this.tableEditor.deleteRow(this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Ctrl-K Ctrl-J': () => {
|
||||||
|
this.tableEditor.insertColumn(this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Cmd-K Cmd-J': () => {
|
||||||
|
this.tableEditor.insertColumn(this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Ctrl-L Ctrl-J': () => {
|
||||||
|
this.tableEditor.deleteColumn(this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Cmd-L Cmd-J': () => {
|
||||||
|
this.tableEditor.deleteColumn(this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Alt-Shift-Ctrl-Left': () => {
|
||||||
|
this.tableEditor.moveColumn(-1, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Alt-Shift-Cmd-Left': () => {
|
||||||
|
this.tableEditor.moveColumn(-1, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Alt-Shift-Ctrl-Right': () => {
|
||||||
|
this.tableEditor.moveColumn(1, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Alt-Shift-Cmd-Right': () => {
|
||||||
|
this.tableEditor.moveColumn(1, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Alt-Shift-Ctrl-Up': () => {
|
||||||
|
this.tableEditor.moveRow(-1, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Alt-Shift-Cmd-Up': () => {
|
||||||
|
this.tableEditor.moveRow(-1, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Alt-Shift-Ctrl-Down': () => {
|
||||||
|
this.tableEditor.moveRow(1, this.tableEditorOptions)
|
||||||
|
},
|
||||||
|
'Alt-Shift-Cmd-Down': () => {
|
||||||
|
this.tableEditor.moveRow(1, this.tableEditorOptions)
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
if (this.props.enableTableEditor) {
|
if (this.props.enableTableEditor) {
|
||||||
@@ -339,6 +516,8 @@ export default class CodeEditor extends React.Component {
|
|||||||
this.setState({
|
this.setState({
|
||||||
clientWidth: this.refs.root.clientWidth
|
clientWidth: this.refs.root.clientWidth
|
||||||
})
|
})
|
||||||
|
|
||||||
|
this.initialHighlighting()
|
||||||
}
|
}
|
||||||
|
|
||||||
expandSnippet (line, cursor, cm, snippets) {
|
expandSnippet (line, cursor, cm, snippets) {
|
||||||
@@ -415,8 +594,14 @@ export default class CodeEditor extends React.Component {
|
|||||||
return {
|
return {
|
||||||
text: wordBeforeCursor,
|
text: wordBeforeCursor,
|
||||||
range: {
|
range: {
|
||||||
from: { line: lineNumber, ch: originCursorPosition },
|
from: {
|
||||||
to: { line: lineNumber, ch: cursorPosition }
|
line: lineNumber,
|
||||||
|
ch: originCursorPosition
|
||||||
|
},
|
||||||
|
to: {
|
||||||
|
line: lineNumber,
|
||||||
|
ch: cursorPosition
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -442,7 +627,10 @@ 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)
|
||||||
}
|
}
|
||||||
@@ -483,6 +671,18 @@ export default class CodeEditor extends React.Component {
|
|||||||
this.editor.setOption('scrollPastEnd', this.props.scrollPastEnd)
|
this.editor.setOption('scrollPastEnd', this.props.scrollPastEnd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (prevProps.matchingPairs !== this.props.matchingPairs ||
|
||||||
|
prevProps.matchingTriples !== this.props.matchingTriples ||
|
||||||
|
prevProps.explodingPairs !== this.props.explodingPairs) {
|
||||||
|
const bracketObject = {
|
||||||
|
pairs: this.props.matchingPairs,
|
||||||
|
triples: this.props.matchingTriples,
|
||||||
|
explode: this.props.explodingPairs,
|
||||||
|
override: true
|
||||||
|
}
|
||||||
|
this.editor.setOption('autoCloseBrackets', bracketObject)
|
||||||
|
}
|
||||||
|
|
||||||
if (prevProps.enableTableEditor !== this.props.enableTableEditor) {
|
if (prevProps.enableTableEditor !== this.props.enableTableEditor) {
|
||||||
if (this.props.enableTableEditor) {
|
if (this.props.enableTableEditor) {
|
||||||
this.editor.on('cursorActivity', this.editorActivityHandler)
|
this.editor.on('cursorActivity', this.editorActivityHandler)
|
||||||
@@ -515,7 +715,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
if (prevProps.spellCheck !== this.props.spellCheck) {
|
if (prevProps.spellCheck !== this.props.spellCheck) {
|
||||||
if (this.props.spellCheck === false) {
|
if (this.props.spellCheck === false) {
|
||||||
spellcheck.setLanguage(this.editor, spellcheck.SPELLCHECK_DISABLED)
|
spellcheck.setLanguage(this.editor, spellcheck.SPELLCHECK_DISABLED)
|
||||||
let elem = document.getElementById('editor-bottom-panel')
|
const elem = document.getElementById('editor-bottom-panel')
|
||||||
elem.parentNode.removeChild(elem)
|
elem.parentNode.removeChild(elem)
|
||||||
} else {
|
} else {
|
||||||
this.editor.addPanel(this.createSpellCheckPanel(), {position: 'bottom'})
|
this.editor.addPanel(this.createSpellCheckPanel(), {position: 'bottom'})
|
||||||
@@ -528,7 +728,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
setMode (mode) {
|
setMode (mode) {
|
||||||
let syntax = CodeMirror.findModeByName(convertModeName(mode))
|
let syntax = CodeMirror.findModeByName(convertModeName(mode || 'text'))
|
||||||
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
|
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
|
||||||
|
|
||||||
this.editor.setOption('mode', syntax.mime)
|
this.editor.setOption('mode', syntax.mime)
|
||||||
@@ -537,12 +737,96 @@ export default class CodeEditor extends React.Component {
|
|||||||
|
|
||||||
handleChange (editor, changeObject) {
|
handleChange (editor, changeObject) {
|
||||||
spellcheck.handleChange(editor, changeObject)
|
spellcheck.handleChange(editor, changeObject)
|
||||||
|
|
||||||
|
this.updateHighlight(editor, changeObject)
|
||||||
|
|
||||||
this.value = editor.getValue()
|
this.value = editor.getValue()
|
||||||
if (this.props.onChange) {
|
if (this.props.onChange) {
|
||||||
this.props.onChange(editor)
|
this.props.onChange(editor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
incrementLines (start, linesAdded, linesRemoved, editor) {
|
||||||
|
let highlightedLines = editor.options.linesHighlighted
|
||||||
|
|
||||||
|
const totalHighlightedLines = highlightedLines.length
|
||||||
|
|
||||||
|
let offset = linesAdded - linesRemoved
|
||||||
|
|
||||||
|
// Store new items to be added as we're changing the lines
|
||||||
|
let newLines = []
|
||||||
|
|
||||||
|
let i = totalHighlightedLines
|
||||||
|
|
||||||
|
while (i--) {
|
||||||
|
const lineNumber = highlightedLines[i]
|
||||||
|
|
||||||
|
// Interval that will need to be updated
|
||||||
|
// Between start and (start + offset) remove highlight
|
||||||
|
if (lineNumber >= start) {
|
||||||
|
highlightedLines.splice(highlightedLines.indexOf(lineNumber), 1)
|
||||||
|
|
||||||
|
// Lines that need to be relocated
|
||||||
|
if (lineNumber >= (start + linesRemoved)) {
|
||||||
|
newLines.push(lineNumber + offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adding relocated lines
|
||||||
|
highlightedLines.push(...newLines)
|
||||||
|
|
||||||
|
if (this.props.onChange) {
|
||||||
|
this.props.onChange(editor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handleHighlight (editor, changeObject) {
|
||||||
|
const lines = editor.options.linesHighlighted
|
||||||
|
|
||||||
|
if (!lines.includes(changeObject)) {
|
||||||
|
lines.push(changeObject)
|
||||||
|
editor.addLineClass(changeObject, 'text', 'CodeMirror-activeline-background')
|
||||||
|
} else {
|
||||||
|
lines.splice(lines.indexOf(changeObject), 1)
|
||||||
|
editor.removeLineClass(changeObject, 'text', 'CodeMirror-activeline-background')
|
||||||
|
}
|
||||||
|
if (this.props.onChange) {
|
||||||
|
this.props.onChange(editor)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateHighlight (editor, changeObject) {
|
||||||
|
const linesAdded = changeObject.text.length - 1
|
||||||
|
const linesRemoved = changeObject.removed.length - 1
|
||||||
|
|
||||||
|
// If no lines added or removed return
|
||||||
|
if (linesAdded === 0 && linesRemoved === 0) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
let start = changeObject.from.line
|
||||||
|
|
||||||
|
switch (changeObject.origin) {
|
||||||
|
case '+insert", "undo':
|
||||||
|
start += 1
|
||||||
|
break
|
||||||
|
|
||||||
|
case 'paste':
|
||||||
|
case '+delete':
|
||||||
|
case '+input':
|
||||||
|
if (changeObject.to.ch !== 0 || changeObject.from.ch !== 0) {
|
||||||
|
start += 1
|
||||||
|
}
|
||||||
|
break
|
||||||
|
|
||||||
|
default:
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
this.incrementLines(start, linesAdded, linesRemoved, editor)
|
||||||
|
}
|
||||||
|
|
||||||
moveCursorTo (row, col) {}
|
moveCursorTo (row, col) {}
|
||||||
|
|
||||||
scrollToLine (event, num) {
|
scrollToLine (event, num) {
|
||||||
@@ -567,6 +851,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
this.value = this.props.value
|
this.value = this.props.value
|
||||||
this.editor.setValue(this.props.value)
|
this.editor.setValue(this.props.value)
|
||||||
this.editor.clearHistory()
|
this.editor.clearHistory()
|
||||||
|
this.restartHighlighting()
|
||||||
this.editor.on('change', this.changeHandler)
|
this.editor.on('change', this.changeHandler)
|
||||||
this.editor.refresh()
|
this.editor.refresh()
|
||||||
}
|
}
|
||||||
@@ -579,7 +864,10 @@ 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(
|
attachmentManagement.handleAttachmentDrop(
|
||||||
this,
|
this,
|
||||||
storageKey,
|
storageKey,
|
||||||
@@ -592,6 +880,11 @@ export default class CodeEditor extends React.Component {
|
|||||||
this.editor.replaceSelection(imageMd)
|
this.editor.replaceSelection(imageMd)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
autoDetectLanguage (content) {
|
||||||
|
const res = hljs.highlightAuto(content, Object.keys(languageMaps))
|
||||||
|
this.setMode(languageMaps[res.language])
|
||||||
|
}
|
||||||
|
|
||||||
handlePaste (editor, forceSmartPaste) {
|
handlePaste (editor, forceSmartPaste) {
|
||||||
const { storageKey, noteKey, fetchUrlTitle, enableSmartPaste } = this.props
|
const { storageKey, noteKey, fetchUrlTitle, enableSmartPaste } = this.props
|
||||||
|
|
||||||
@@ -602,15 +895,21 @@ export default class CodeEditor extends React.Component {
|
|||||||
|
|
||||||
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,
|
||||||
{ line: startCursor.line, ch: startCursor.ch }
|
ch: startCursor.ch - 2
|
||||||
)
|
}, {
|
||||||
|
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,
|
||||||
{ line: endCursor.line, ch: endCursor.ch + 1 }
|
ch: endCursor.ch
|
||||||
)
|
}, {
|
||||||
|
line: endCursor.line,
|
||||||
|
ch: endCursor.ch + 1
|
||||||
|
})
|
||||||
return prevChar === '](' && nextChar === ')'
|
return prevChar === '](' && nextChar === ')'
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -656,7 +955,13 @@ export default class CodeEditor extends React.Component {
|
|||||||
this.handlePasteText(editor, pastedTxt)
|
this.handlePasteText(editor, pastedTxt)
|
||||||
} else if (fetchUrlTitle && isURL(pastedTxt) && !isInLinkTag(editor)) {
|
} else if (fetchUrlTitle && isURL(pastedTxt) && !isInLinkTag(editor)) {
|
||||||
this.handlePasteUrl(editor, pastedTxt)
|
this.handlePasteUrl(editor, pastedTxt)
|
||||||
} else if (enableSmartPaste || forceSmartPaste) {
|
} else if (attachmentManagement.isAttachmentLink(pastedTxt)) {
|
||||||
|
attachmentManagement
|
||||||
|
.handleAttachmentLinkPaste(storageKey, noteKey, pastedTxt)
|
||||||
|
.then(modifiedText => {
|
||||||
|
this.editor.replaceSelection(modifiedText)
|
||||||
|
})
|
||||||
|
} else {
|
||||||
const image = clipboard.readImage()
|
const image = clipboard.readImage()
|
||||||
if (!image.isEmpty()) {
|
if (!image.isEmpty()) {
|
||||||
attachmentManagement.handlePastNativeImage(
|
attachmentManagement.handlePastNativeImage(
|
||||||
@@ -665,22 +970,20 @@ export default class CodeEditor extends React.Component {
|
|||||||
noteKey,
|
noteKey,
|
||||||
image
|
image
|
||||||
)
|
)
|
||||||
} else {
|
} else if (enableSmartPaste || forceSmartPaste) {
|
||||||
const pastedHtml = clipboard.readHTML()
|
const pastedHtml = clipboard.readHTML()
|
||||||
if (pastedHtml.length > 0) {
|
if (pastedHtml.length > 0) {
|
||||||
this.handlePasteHtml(editor, pastedHtml)
|
this.handlePasteHtml(editor, pastedHtml)
|
||||||
} else {
|
} else {
|
||||||
this.handlePasteText(editor, pastedTxt)
|
this.handlePasteText(editor, pastedTxt)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
this.handlePasteText(editor, pastedTxt)
|
||||||
}
|
}
|
||||||
} else if (attachmentManagement.isAttachmentLink(pastedTxt)) {
|
}
|
||||||
attachmentManagement
|
|
||||||
.handleAttachmentLinkPaste(storageKey, noteKey, pastedTxt)
|
if (!this.props.mode && this.props.autoDetect) {
|
||||||
.then(modifiedText => {
|
this.autoDetectLanguage(editor.doc.getValue())
|
||||||
this.editor.replaceSelection(modifiedText)
|
|
||||||
})
|
|
||||||
} else {
|
|
||||||
this.handlePasteText(editor, pastedTxt)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -758,6 +1061,29 @@ export default class CodeEditor extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
initialHighlighting () {
|
||||||
|
if (this.editor.options.linesHighlighted == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
const totalHighlightedLines = this.editor.options.linesHighlighted.length
|
||||||
|
const totalAvailableLines = this.editor.lineCount()
|
||||||
|
|
||||||
|
for (let i = 0; i < totalHighlightedLines; i++) {
|
||||||
|
const lineNumber = this.editor.options.linesHighlighted[i]
|
||||||
|
if (lineNumber > totalAvailableLines) {
|
||||||
|
// make sure that we skip the invalid lines althrough this case should not be happened.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
this.editor.addLineClass(lineNumber, 'text', 'CodeMirror-activeline-background')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
restartHighlighting () {
|
||||||
|
this.editor.options.linesHighlighted = this.props.linesHighlighted
|
||||||
|
this.initialHighlighting()
|
||||||
|
}
|
||||||
|
|
||||||
mapImageResponse (response, pastedTxt) {
|
mapImageResponse (response, pastedTxt) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
@@ -803,20 +1129,28 @@ export default class CodeEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const {className, fontSize} = this.props
|
const {
|
||||||
|
className,
|
||||||
|
fontSize
|
||||||
|
} = this.props
|
||||||
const fontFamily = normalizeEditorFontFamily(this.props.fontFamily)
|
const fontFamily = normalizeEditorFontFamily(this.props.fontFamily)
|
||||||
const width = this.props.width
|
const width = this.props.width
|
||||||
return (
|
return (<
|
||||||
<div
|
div className={
|
||||||
className={className == null ? 'CodeEditor' : `CodeEditor ${className}`}
|
className == null ? 'CodeEditor' : `CodeEditor ${className}`
|
||||||
ref='root'
|
}
|
||||||
tabIndex='-1'
|
ref='root'
|
||||||
style={{
|
tabIndex='-1'
|
||||||
fontFamily,
|
style={
|
||||||
fontSize: fontSize,
|
{
|
||||||
width: width
|
fontFamily,
|
||||||
}}
|
fontSize: fontSize,
|
||||||
onDrop={e => this.handleDropImage(e)}
|
width: width
|
||||||
|
}
|
||||||
|
}
|
||||||
|
onDrop={
|
||||||
|
e => this.handleDropImage(e)
|
||||||
|
}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -850,6 +1184,7 @@ CodeEditor.propTypes = {
|
|||||||
onBlur: PropTypes.func,
|
onBlur: PropTypes.func,
|
||||||
onChange: PropTypes.func,
|
onChange: PropTypes.func,
|
||||||
readOnly: PropTypes.bool,
|
readOnly: PropTypes.bool,
|
||||||
|
autoDetect: PropTypes.bool,
|
||||||
spellCheck: PropTypes.bool
|
spellCheck: PropTypes.bool
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -861,5 +1196,6 @@ CodeEditor.defaultProps = {
|
|||||||
fontFamily: 'Monaco, Consolas',
|
fontFamily: 'Monaco, Consolas',
|
||||||
indentSize: 4,
|
indentSize: 4,
|
||||||
indentType: 'space',
|
indentType: 'space',
|
||||||
|
autoDetect: false,
|
||||||
spellCheck: false
|
spellCheck: false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import MarkdownPreview from 'browser/components/MarkdownPreview'
|
|||||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||||
import { findStorage } from 'browser/lib/findStorage'
|
import { findStorage } from 'browser/lib/findStorage'
|
||||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||||
|
import attachmentManagement from 'browser/main/lib/dataApi/attachmentManagement'
|
||||||
|
|
||||||
class MarkdownEditor extends React.Component {
|
class MarkdownEditor extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -221,6 +222,28 @@ class MarkdownEditor extends React.Component {
|
|||||||
this.refs.code.editor.replaceSelection(`${mdElement}${this.refs.code.editor.getSelection()}${mdElement}`)
|
this.refs.code.editor.replaceSelection(`${mdElement}${this.refs.code.editor.getSelection()}${mdElement}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleDropImage (dropEvent) {
|
||||||
|
dropEvent.preventDefault()
|
||||||
|
const { storageKey, noteKey } = this.props
|
||||||
|
|
||||||
|
this.setState({
|
||||||
|
status: 'CODE'
|
||||||
|
}, () => {
|
||||||
|
this.refs.code.focus()
|
||||||
|
|
||||||
|
this.refs.code.editor.execCommand('goDocEnd')
|
||||||
|
this.refs.code.editor.execCommand('goLineEnd')
|
||||||
|
this.refs.code.editor.execCommand('newlineAndIndent')
|
||||||
|
|
||||||
|
attachmentManagement.handleAttachmentDrop(
|
||||||
|
this.refs.code,
|
||||||
|
storageKey,
|
||||||
|
noteKey,
|
||||||
|
dropEvent
|
||||||
|
)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
handleKeyUp (e) {
|
handleKeyUp (e) {
|
||||||
const keyPressed = this.state.keyPressed
|
const keyPressed = this.state.keyPressed
|
||||||
keyPressed.delete(e.keyCode)
|
keyPressed.delete(e.keyCode)
|
||||||
@@ -232,7 +255,7 @@ class MarkdownEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const {className, value, config, storageKey, noteKey} = this.props
|
const {className, value, config, storageKey, noteKey, linesHighlighted} = this.props
|
||||||
|
|
||||||
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
||||||
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
||||||
@@ -270,11 +293,15 @@ class MarkdownEditor extends React.Component {
|
|||||||
enableRulers={config.editor.enableRulers}
|
enableRulers={config.editor.enableRulers}
|
||||||
rulers={config.editor.rulers}
|
rulers={config.editor.rulers}
|
||||||
displayLineNumbers={config.editor.displayLineNumbers}
|
displayLineNumbers={config.editor.displayLineNumbers}
|
||||||
|
matchingPairs={config.editor.matchingPairs}
|
||||||
|
matchingTriples={config.editor.matchingTriples}
|
||||||
|
explodingPairs={config.editor.explodingPairs}
|
||||||
scrollPastEnd={config.editor.scrollPastEnd}
|
scrollPastEnd={config.editor.scrollPastEnd}
|
||||||
storageKey={storageKey}
|
storageKey={storageKey}
|
||||||
noteKey={noteKey}
|
noteKey={noteKey}
|
||||||
fetchUrlTitle={config.editor.fetchUrlTitle}
|
fetchUrlTitle={config.editor.fetchUrlTitle}
|
||||||
enableTableEditor={config.editor.enableTableEditor}
|
enableTableEditor={config.editor.enableTableEditor}
|
||||||
|
linesHighlighted={linesHighlighted}
|
||||||
onChange={(e) => this.handleChange(e)}
|
onChange={(e) => this.handleChange(e)}
|
||||||
onBlur={(e) => this.handleBlur(e)}
|
onBlur={(e) => this.handleBlur(e)}
|
||||||
spellCheck={config.editor.spellcheck}
|
spellCheck={config.editor.spellcheck}
|
||||||
@@ -314,6 +341,7 @@ class MarkdownEditor extends React.Component {
|
|||||||
customCSS={config.preview.customCSS}
|
customCSS={config.preview.customCSS}
|
||||||
allowCustomCSS={config.preview.allowCustomCSS}
|
allowCustomCSS={config.preview.allowCustomCSS}
|
||||||
lineThroughCheckbox={config.preview.lineThroughCheckbox}
|
lineThroughCheckbox={config.preview.lineThroughCheckbox}
|
||||||
|
onDrop={(e) => this.handleDropImage(e)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -21,6 +21,8 @@ import yaml from 'js-yaml'
|
|||||||
import context from 'browser/lib/context'
|
import context from 'browser/lib/context'
|
||||||
import i18n from 'browser/lib/i18n'
|
import i18n from 'browser/lib/i18n'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
|
import { render } from 'react-dom'
|
||||||
|
import Carousel from 'react-image-carousel'
|
||||||
import ConfigManager from '../main/lib/ConfigManager'
|
import ConfigManager from '../main/lib/ConfigManager'
|
||||||
|
|
||||||
const { remote, shell } = require('electron')
|
const { remote, shell } = require('electron')
|
||||||
@@ -40,7 +42,8 @@ const appPath = fileUrl(
|
|||||||
)
|
)
|
||||||
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`,
|
||||||
|
`${appPath}/node_modules/react-image-carousel/lib/css/main.min.css`
|
||||||
]
|
]
|
||||||
|
|
||||||
function buildStyle (
|
function buildStyle (
|
||||||
@@ -207,7 +210,7 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
this.saveAsHtmlHandler = () => this.handleSaveAsHtml()
|
this.saveAsHtmlHandler = () => this.handleSaveAsHtml()
|
||||||
this.printHandler = () => this.handlePrint()
|
this.printHandler = () => this.handlePrint()
|
||||||
|
|
||||||
this.linkClickHandler = this.handlelinkClick.bind(this)
|
this.linkClickHandler = this.handleLinkClick.bind(this)
|
||||||
this.initMarkdown = this.initMarkdown.bind(this)
|
this.initMarkdown = this.initMarkdown.bind(this)
|
||||||
this.initMarkdown()
|
this.initMarkdown()
|
||||||
}
|
}
|
||||||
@@ -410,6 +413,8 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
|
const { onDrop } = this.props
|
||||||
|
|
||||||
this.refs.root.setAttribute('sandbox', 'allow-scripts')
|
this.refs.root.setAttribute('sandbox', 'allow-scripts')
|
||||||
this.refs.root.contentWindow.document.body.addEventListener(
|
this.refs.root.contentWindow.document.body.addEventListener(
|
||||||
'contextmenu',
|
'contextmenu',
|
||||||
@@ -447,7 +452,7 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
)
|
)
|
||||||
this.refs.root.contentWindow.document.addEventListener(
|
this.refs.root.contentWindow.document.addEventListener(
|
||||||
'drop',
|
'drop',
|
||||||
this.preventImageDroppedHandler
|
onDrop || this.preventImageDroppedHandler
|
||||||
)
|
)
|
||||||
this.refs.root.contentWindow.document.addEventListener(
|
this.refs.root.contentWindow.document.addEventListener(
|
||||||
'dragover',
|
'dragover',
|
||||||
@@ -464,6 +469,8 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount () {
|
componentWillUnmount () {
|
||||||
|
const { onDrop } = this.props
|
||||||
|
|
||||||
this.refs.root.contentWindow.document.body.removeEventListener(
|
this.refs.root.contentWindow.document.body.removeEventListener(
|
||||||
'contextmenu',
|
'contextmenu',
|
||||||
this.contextMenuHandler
|
this.contextMenuHandler
|
||||||
@@ -482,7 +489,7 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
)
|
)
|
||||||
this.refs.root.contentWindow.document.removeEventListener(
|
this.refs.root.contentWindow.document.removeEventListener(
|
||||||
'drop',
|
'drop',
|
||||||
this.preventImageDroppedHandler
|
onDrop || this.preventImageDroppedHandler
|
||||||
)
|
)
|
||||||
this.refs.root.contentWindow.document.removeEventListener(
|
this.refs.root.contentWindow.document.removeEventListener(
|
||||||
'dragover',
|
'dragover',
|
||||||
@@ -767,6 +774,34 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
mermaidRender(el, htmlTextHelper.decodeEntities(el.innerHTML), theme)
|
mermaidRender(el, htmlTextHelper.decodeEntities(el.innerHTML), theme)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
_.forEach(
|
||||||
|
this.refs.root.contentWindow.document.querySelectorAll('.gallery'),
|
||||||
|
el => {
|
||||||
|
const images = el.innerHTML.split(/\n/g).filter(i => i.length > 0)
|
||||||
|
el.innerHTML = ''
|
||||||
|
|
||||||
|
const height = el.attributes.getNamedItem('data-height')
|
||||||
|
if (height && height.value !== 'undefined') {
|
||||||
|
el.style.height = height.value + 'vh'
|
||||||
|
}
|
||||||
|
|
||||||
|
let autoplay = el.attributes.getNamedItem('data-autoplay')
|
||||||
|
if (autoplay && autoplay.value !== 'undefined') {
|
||||||
|
autoplay = parseInt(autoplay.value, 10) || 0
|
||||||
|
} else {
|
||||||
|
autoplay = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
render(
|
||||||
|
<Carousel
|
||||||
|
images={images}
|
||||||
|
autoplay={autoplay}
|
||||||
|
/>,
|
||||||
|
el
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
focus () {
|
focus () {
|
||||||
@@ -809,7 +844,7 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
return new window.Notification(title, options)
|
return new window.Notification(title, options)
|
||||||
}
|
}
|
||||||
|
|
||||||
handlelinkClick (e) {
|
handleLinkClick (e) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
|
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ class MarkdownSplitEditor extends React.Component {
|
|||||||
this.refs.code.setValue(value)
|
this.refs.code.setValue(value)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleOnChange () {
|
handleOnChange (e) {
|
||||||
this.value = this.refs.code.value
|
this.value = this.refs.code.value
|
||||||
this.props.onChange()
|
this.props.onChange(e)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleScroll (e) {
|
handleScroll (e) {
|
||||||
@@ -136,7 +136,7 @@ class MarkdownSplitEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const {config, value, storageKey, noteKey} = this.props
|
const {config, value, storageKey, noteKey, linesHighlighted} = this.props
|
||||||
const storage = findStorage(storageKey)
|
const storage = findStorage(storageKey)
|
||||||
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
||||||
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
||||||
@@ -160,6 +160,9 @@ class MarkdownSplitEditor extends React.Component {
|
|||||||
fontFamily={config.editor.fontFamily}
|
fontFamily={config.editor.fontFamily}
|
||||||
fontSize={editorFontSize}
|
fontSize={editorFontSize}
|
||||||
displayLineNumbers={config.editor.displayLineNumbers}
|
displayLineNumbers={config.editor.displayLineNumbers}
|
||||||
|
matchingPairs={config.editor.matchingPairs}
|
||||||
|
matchingTriples={config.editor.matchingTriples}
|
||||||
|
explodingPairs={config.editor.explodingPairs}
|
||||||
indentType={config.editor.indentType}
|
indentType={config.editor.indentType}
|
||||||
indentSize={editorIndentSize}
|
indentSize={editorIndentSize}
|
||||||
enableRulers={config.editor.enableRulers}
|
enableRulers={config.editor.enableRulers}
|
||||||
@@ -169,7 +172,8 @@ class MarkdownSplitEditor extends React.Component {
|
|||||||
enableTableEditor={config.editor.enableTableEditor}
|
enableTableEditor={config.editor.enableTableEditor}
|
||||||
storageKey={storageKey}
|
storageKey={storageKey}
|
||||||
noteKey={noteKey}
|
noteKey={noteKey}
|
||||||
onChange={this.handleOnChange.bind(this)}
|
linesHighlighted={linesHighlighted}
|
||||||
|
onChange={(e) => this.handleOnChange(e)}
|
||||||
onScroll={this.handleScroll.bind(this)}
|
onScroll={this.handleScroll.bind(this)}
|
||||||
spellCheck={config.editor.spellcheck}
|
spellCheck={config.editor.spellcheck}
|
||||||
enableSmartPaste={config.editor.enableSmartPaste}
|
enableSmartPaste={config.editor.enableSmartPaste}
|
||||||
|
|||||||
@@ -3,19 +3,30 @@
|
|||||||
flex 1
|
flex 1
|
||||||
min-width 70px
|
min-width 70px
|
||||||
overflow hidden
|
overflow hidden
|
||||||
|
border-left 1px solid $ui-borderColor
|
||||||
|
border-top 1px solid $ui-borderColor
|
||||||
&:hover
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||||
.deleteButton
|
.deleteButton
|
||||||
color $ui-inactive-text-color
|
color: $ui-text-color
|
||||||
&:hover
|
visibility visible
|
||||||
background-color darken($ui-backgroundColor, 15%)
|
transition 0.15s
|
||||||
&:active
|
.button
|
||||||
color white
|
color: $ui-text-color
|
||||||
background-color $ui-active-color
|
transition 0.15s
|
||||||
|
|
||||||
.root--active
|
.root--active
|
||||||
@extend .root
|
@extend .root
|
||||||
min-width 100px
|
min-width 100px
|
||||||
border-bottom $ui-border
|
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||||
|
.deleteButton
|
||||||
|
visibility visible
|
||||||
|
color: $ui-text-color
|
||||||
|
transition 0.15s
|
||||||
|
.button
|
||||||
|
font-weight bold
|
||||||
|
color: $ui-text-color
|
||||||
|
transition 0.15s
|
||||||
|
|
||||||
.button
|
.button
|
||||||
width 100%
|
width 100%
|
||||||
@@ -27,8 +38,7 @@
|
|||||||
background-color transparent
|
background-color transparent
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
border-left 4px solid transparent
|
border-left 4px solid transparent
|
||||||
&:hover
|
color $ui-inactive-text-color
|
||||||
background-color $ui-button--hover-backgroundColor
|
|
||||||
|
|
||||||
.deleteButton
|
.deleteButton
|
||||||
position absolute
|
position absolute
|
||||||
@@ -42,6 +52,7 @@
|
|||||||
color $ui-inactive-text-color
|
color $ui-inactive-text-color
|
||||||
background-color transparent
|
background-color transparent
|
||||||
border-radius 2px
|
border-radius 2px
|
||||||
|
visibility hidden
|
||||||
|
|
||||||
.input
|
.input
|
||||||
height 29px
|
height 29px
|
||||||
@@ -50,76 +61,66 @@
|
|||||||
width 100%
|
width 100%
|
||||||
outline none
|
outline none
|
||||||
|
|
||||||
|
body[data-theme="default"], body[data-theme="white"]
|
||||||
|
.root--active
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 60%)
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root
|
.root
|
||||||
color $ui-dark-text-color
|
|
||||||
border-color $ui-dark-borderColor
|
border-color $ui-dark-borderColor
|
||||||
|
border-top 1px solid $ui-dark-borderColor
|
||||||
&:hover
|
&:hover
|
||||||
background-color $ui-dark-button--hover-backgroundColor
|
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||||
|
transition 0.15s
|
||||||
|
.button
|
||||||
|
color $ui-dark-text-color
|
||||||
|
transition 0.15s
|
||||||
.deleteButton
|
.deleteButton
|
||||||
color $ui-dark-inactive-text-color
|
color $ui-dark-text-color
|
||||||
&:hover
|
transition 0.15s
|
||||||
background-color darken($ui-dark-button--hover-backgroundColor, 15%)
|
|
||||||
&:active
|
|
||||||
color $ui-dark-text-color
|
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
|
||||||
|
|
||||||
.root--active
|
.root--active
|
||||||
color $ui-dark-text-color
|
background-color $ui-dark-button--active-backgroundColor
|
||||||
border-color $ui-dark-borderColor
|
border-left 1px solid $ui-dark-borderColor
|
||||||
&:hover
|
border-top 1px solid $ui-dark-borderColor
|
||||||
background-color $ui-dark-button--hover-backgroundColor
|
.button
|
||||||
.deleteButton
|
color $ui-dark-text-color
|
||||||
color $ui-dark-inactive-text-color
|
.deleteButton
|
||||||
&:hover
|
color $ui-dark-text-color
|
||||||
background-color darken($ui-dark-button--hover-backgroundColor, 15%)
|
|
||||||
&:active
|
|
||||||
color $ui-dark-text-color
|
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
|
||||||
|
|
||||||
.button
|
.button
|
||||||
border none
|
border none
|
||||||
color $ui-dark-text-color
|
|
||||||
background-color transparent
|
background-color transparent
|
||||||
transition color background-color 0.15s
|
transition color background-color 0.15s
|
||||||
border-left 4px solid transparent
|
border-left 4px solid transparent
|
||||||
&:hover
|
|
||||||
color $ui-dark-text-color
|
|
||||||
background-color $ui-dark-button--hover-backgroundColor
|
|
||||||
|
|
||||||
.input
|
.input
|
||||||
background-color $ui-dark-button--hover-backgroundColor
|
background-color $ui-dark-button--active-backgroundColor
|
||||||
color $ui-dark-text-color
|
color $ui-dark-text-color
|
||||||
|
transition 0.15s
|
||||||
.deleteButton
|
|
||||||
color alpha($ui-dark-text-color, 30%)
|
|
||||||
|
|
||||||
body[data-theme="solarized-dark"]
|
body[data-theme="solarized-dark"]
|
||||||
.root
|
.root
|
||||||
color $ui-solarized-dark-text-color
|
|
||||||
border-color $ui-dark-borderColor
|
|
||||||
&:hover
|
|
||||||
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
|
||||||
.deleteButton
|
|
||||||
color $ui-solarized-dark-text-color
|
|
||||||
&:hover
|
|
||||||
background-color darken($ui-solarized-dark-noteDetail-backgroundColor, 15%)
|
|
||||||
&:active
|
|
||||||
color $ui-solarized-dark-text-color
|
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
|
||||||
|
|
||||||
.root--active
|
|
||||||
color $ui-solarized-dark-text-color
|
|
||||||
border-color $ui-solarized-dark-borderColor
|
border-color $ui-solarized-dark-borderColor
|
||||||
&:hover
|
&:hover
|
||||||
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
||||||
|
transition 0.15s
|
||||||
.deleteButton
|
.deleteButton
|
||||||
color $ui-solarized-dark-text-color
|
color $ui-solarized-dark-button--active-color
|
||||||
&:hover
|
transition 0.15s
|
||||||
background-color darken($ui-solarized-dark-noteDetail-backgroundColor, 15%)
|
.button
|
||||||
&:active
|
color $ui-solarized-dark-button--active-color
|
||||||
color $ui-solarized-dark-text-color
|
transition 0.15s
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
|
||||||
|
.root--active
|
||||||
|
color $ui-solarized-dark-button--active-color
|
||||||
|
background-color $ui-solarized-dark-button-backgroundColor
|
||||||
|
border-color $ui-solarized-dark-borderColor
|
||||||
|
.deleteButton
|
||||||
|
color $ui-solarized-dark-button--active-color
|
||||||
|
.button
|
||||||
|
color $ui-solarized-dark-button--active-color
|
||||||
|
|
||||||
.button
|
.button
|
||||||
border none
|
border none
|
||||||
@@ -127,101 +128,75 @@ body[data-theme="solarized-dark"]
|
|||||||
background-color transparent
|
background-color transparent
|
||||||
transition color background-color 0.15s
|
transition color background-color 0.15s
|
||||||
border-left 4px solid transparent
|
border-left 4px solid transparent
|
||||||
&:hover
|
|
||||||
color $ui-solarized-dark-text-color
|
|
||||||
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
|
||||||
|
|
||||||
.input
|
.input
|
||||||
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
||||||
color $ui-solarized-dark-text-color
|
color $ui-solarized-dark-button--active-color
|
||||||
|
transition 0.15s
|
||||||
.deleteButton
|
|
||||||
color alpha($ui-solarized-dark-text-color, 30%)
|
|
||||||
|
|
||||||
body[data-theme="monokai"]
|
body[data-theme="monokai"]
|
||||||
.root
|
.root
|
||||||
color $ui-monokai-text-color
|
|
||||||
border-color $ui-dark-borderColor
|
|
||||||
&:hover
|
|
||||||
background-color $ui-monokai-noteDetail-backgroundColor
|
|
||||||
.deleteButton
|
|
||||||
color $ui-monokai-text-color
|
|
||||||
&:hover
|
|
||||||
background-color darken($ui-monokai-noteDetail-backgroundColor, 15%)
|
|
||||||
&:active
|
|
||||||
color $ui-monokai-text-color
|
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
|
||||||
|
|
||||||
.root--active
|
|
||||||
color $ui-monokai-text-color
|
|
||||||
border-color $ui-monokai-borderColor
|
border-color $ui-monokai-borderColor
|
||||||
&:hover
|
&:hover
|
||||||
background-color $ui-monokai-noteDetail-backgroundColor
|
background-color $ui-monokai-noteDetail-backgroundColor
|
||||||
|
transition 0.15s
|
||||||
.deleteButton
|
.deleteButton
|
||||||
color $ui-monokai-text-color
|
color $ui-monokai-text-color
|
||||||
&:hover
|
transition 0.15s
|
||||||
background-color darken($ui-monokai-noteDetail-backgroundColor, 15%)
|
.button
|
||||||
&:active
|
color $ui-monokai-text-color
|
||||||
color $ui-monokai-text-color
|
transition 0.15s
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
|
||||||
|
|
||||||
|
.root--active
|
||||||
|
color $ui-monokai-active-color
|
||||||
|
background-color $ui-monokai-button-backgroundColor
|
||||||
|
border-color $ui-monokai-borderColor
|
||||||
|
.deleteButton
|
||||||
|
color $ui-monokai-text-color
|
||||||
|
.button
|
||||||
|
color $ui-monokai-active-color
|
||||||
|
|
||||||
.button
|
.button
|
||||||
border none
|
border none
|
||||||
color $ui-monokai-text-color
|
color $ui-inactive-text-color
|
||||||
background-color transparent
|
background-color transparent
|
||||||
transition color background-color 0.15s
|
transition color background-color 0.15s
|
||||||
border-left 4px solid transparent
|
border-left 4px solid transparent
|
||||||
&:hover
|
|
||||||
color $ui-monokai-text-color
|
|
||||||
background-color $ui-monokai-noteDetail-backgroundColor
|
|
||||||
|
|
||||||
.input
|
.input
|
||||||
background-color $ui-monokai-noteDetail-backgroundColor
|
background-color $ui-monokai-noteDetail-backgroundColor
|
||||||
color $ui-monokai-text-color
|
color $ui-monokai-text-color
|
||||||
|
transition 0.15s
|
||||||
.deleteButton
|
|
||||||
color alpha($ui-monokai-text-color, 30%)
|
|
||||||
|
|
||||||
body[data-theme="dracula"]
|
body[data-theme="dracula"]
|
||||||
.root
|
.root
|
||||||
color $ui-dracula-text-color
|
|
||||||
border-color $ui-dark-borderColor
|
|
||||||
&:hover
|
|
||||||
background-color $ui-dracula-noteDetail-backgroundColor
|
|
||||||
.deleteButton
|
|
||||||
color $ui-dracula-text-color
|
|
||||||
&:hover
|
|
||||||
background-color darken($ui-dracula-noteDetail-backgroundColor, 15%)
|
|
||||||
&:active
|
|
||||||
color $ui-dracula-text-color
|
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
|
||||||
|
|
||||||
.root--active
|
|
||||||
color $ui-dracula-text-color
|
|
||||||
border-color $ui-dracula-borderColor
|
border-color $ui-dracula-borderColor
|
||||||
&:hover
|
&:hover
|
||||||
background-color $ui-dracula-noteDetail-backgroundColor
|
background-color $ui-dracula-noteDetail-backgroundColor
|
||||||
|
transition 0.15s
|
||||||
.deleteButton
|
.deleteButton
|
||||||
color $ui-dracula-text-color
|
color $ui-dracula-text-color
|
||||||
&:hover
|
transition 0.15s
|
||||||
background-color darken($ui-dracula-noteDetail-backgroundColor, 15%)
|
.button
|
||||||
&:active
|
color $ui-dracula-text-color
|
||||||
color $ui-dracula-text-color
|
transition 0.15s
|
||||||
background-color $ui-dark-button--active-backgroundColor
|
|
||||||
|
.root--active
|
||||||
|
color $ui-dracula-text-color
|
||||||
|
background-color $ui-dracula-button-backgroundColor
|
||||||
|
border-color $ui-dracula-borderColor
|
||||||
|
.deleteButton
|
||||||
|
color $ui-dracula-text-color
|
||||||
|
.button
|
||||||
|
color $ui-dracula-active-color
|
||||||
|
|
||||||
.button
|
.button
|
||||||
border none
|
border none
|
||||||
color $ui-dracula-text-color
|
color $ui-inactive-text-color
|
||||||
background-color transparent
|
background-color transparent
|
||||||
transition color background-color 0.15s
|
transition color background-color 0.15s
|
||||||
border-left 4px solid transparent
|
border-left 4px solid transparent
|
||||||
&:hover
|
|
||||||
color $ui-dracula-text-color
|
|
||||||
background-color $ui-dracula-noteDetail-backgroundColor
|
|
||||||
|
|
||||||
.input
|
.input
|
||||||
background-color $ui-dracula-noteDetail-backgroundColor
|
background-color $ui-dracula-noteDetail-backgroundColor
|
||||||
color $ui-dracula-text-color
|
color $ui-dracula-text-color
|
||||||
|
|
||||||
.deleteButton
|
|
||||||
color alpha($ui-dracula-text-color, 30%)
|
|
||||||
@@ -55,11 +55,12 @@ body
|
|||||||
line-height 1.6
|
line-height 1.6
|
||||||
overflow-x hidden
|
overflow-x hidden
|
||||||
background-color $ui-noteDetail-backgroundColor
|
background-color $ui-noteDetail-backgroundColor
|
||||||
|
// do not allow display line breaks
|
||||||
|
.katex-display > .katex
|
||||||
|
white-space nowrap
|
||||||
|
// allow inline line breaks
|
||||||
.katex
|
.katex
|
||||||
font 400 1.2em 'KaTeX_Main'
|
|
||||||
line-height 1.2em
|
|
||||||
white-space initial
|
white-space initial
|
||||||
text-indent 0
|
|
||||||
.katex .mfrac>.vlist>span:nth-child(2)
|
.katex .mfrac>.vlist>span:nth-child(2)
|
||||||
top 0 !important
|
top 0 !important
|
||||||
.katex-error
|
.katex-error
|
||||||
@@ -183,6 +184,10 @@ ul
|
|||||||
display list-item
|
display list-item
|
||||||
&.taskListItem
|
&.taskListItem
|
||||||
list-style none
|
list-style none
|
||||||
|
&>input
|
||||||
|
margin-left -1.6em
|
||||||
|
&>p
|
||||||
|
margin-left -1.8em
|
||||||
p
|
p
|
||||||
margin 0
|
margin 0
|
||||||
&>li>ul, &>li>ol
|
&>li>ul, &>li>ol
|
||||||
@@ -416,6 +421,26 @@ pre.fence
|
|||||||
canvas, svg
|
canvas, svg
|
||||||
max-width 100% !important
|
max-width 100% !important
|
||||||
|
|
||||||
|
.gallery
|
||||||
|
width 100%
|
||||||
|
height 50vh
|
||||||
|
|
||||||
|
.carousel
|
||||||
|
.carousel-main img
|
||||||
|
min-width auto
|
||||||
|
max-width 100%
|
||||||
|
min-height auto
|
||||||
|
max-height 100%
|
||||||
|
|
||||||
|
.carousel-footer::-webkit-scrollbar-corner
|
||||||
|
background-color transparent
|
||||||
|
|
||||||
|
.carousel-main, .carousel-footer
|
||||||
|
background-color $ui-noteDetail-backgroundColor
|
||||||
|
.prev, .next
|
||||||
|
color $ui-text-color
|
||||||
|
background-color $ui-tag-backgroundColor
|
||||||
|
|
||||||
themeDarkBackground = darken(#21252B, 10%)
|
themeDarkBackground = darken(#21252B, 10%)
|
||||||
themeDarkText = #f9f9f9
|
themeDarkText = #f9f9f9
|
||||||
themeDarkBorder = lighten(themeDarkBackground, 20%)
|
themeDarkBorder = lighten(themeDarkBackground, 20%)
|
||||||
@@ -475,6 +500,14 @@ body[data-theme="dark"]
|
|||||||
border-color themeDarkBorder
|
border-color themeDarkBorder
|
||||||
background-color themeDarkPreview
|
background-color themeDarkPreview
|
||||||
|
|
||||||
|
pre.fence
|
||||||
|
.gallery
|
||||||
|
.carousel-main, .carousel-footer
|
||||||
|
background-color $ui-dark-noteDetail-backgroundColor
|
||||||
|
.prev, .next
|
||||||
|
color $ui-dark-text-color
|
||||||
|
background-color $ui-dark-tag-backgroundColor
|
||||||
|
|
||||||
themeSolarizedDarkTableOdd = $ui-solarized-dark-noteDetail-backgroundColor
|
themeSolarizedDarkTableOdd = $ui-solarized-dark-noteDetail-backgroundColor
|
||||||
themeSolarizedDarkTableEven = darken($ui-solarized-dark-noteDetail-backgroundColor, 10%)
|
themeSolarizedDarkTableEven = darken($ui-solarized-dark-noteDetail-backgroundColor, 10%)
|
||||||
themeSolarizedDarkTableHead = themeSolarizedDarkTableEven
|
themeSolarizedDarkTableHead = themeSolarizedDarkTableEven
|
||||||
@@ -510,6 +543,14 @@ body[data-theme="solarized-dark"]
|
|||||||
border-color themeDarkBorder
|
border-color themeDarkBorder
|
||||||
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
||||||
|
|
||||||
|
pre.fence
|
||||||
|
.gallery
|
||||||
|
.carousel-main, .carousel-footer
|
||||||
|
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
||||||
|
.prev, .next
|
||||||
|
color $ui-solarized-dark-button--active-color
|
||||||
|
background-color $ui-solarized-dark-button-backgroundColor
|
||||||
|
|
||||||
themeMonokaiTableOdd = $ui-monokai-noteDetail-backgroundColor
|
themeMonokaiTableOdd = $ui-monokai-noteDetail-backgroundColor
|
||||||
themeMonokaiTableEven = darken($ui-monokai-noteDetail-backgroundColor, 10%)
|
themeMonokaiTableEven = darken($ui-monokai-noteDetail-backgroundColor, 10%)
|
||||||
themeMonokaiTableHead = themeMonokaiTableEven
|
themeMonokaiTableHead = themeMonokaiTableEven
|
||||||
@@ -538,6 +579,7 @@ body[data-theme="monokai"]
|
|||||||
border-right solid 1px themeMonokaiTableBorder
|
border-right solid 1px themeMonokaiTableBorder
|
||||||
kbd
|
kbd
|
||||||
background-color themeDarkBackground
|
background-color themeDarkBackground
|
||||||
|
|
||||||
dl
|
dl
|
||||||
border-color themeDarkBorder
|
border-color themeDarkBorder
|
||||||
background-color themeMonokaiTableHead
|
background-color themeMonokaiTableHead
|
||||||
@@ -547,6 +589,14 @@ body[data-theme="monokai"]
|
|||||||
border-color themeDarkBorder
|
border-color themeDarkBorder
|
||||||
background-color $ui-monokai-noteDetail-backgroundColor
|
background-color $ui-monokai-noteDetail-backgroundColor
|
||||||
|
|
||||||
|
pre.fence
|
||||||
|
.gallery
|
||||||
|
.carousel-main, .carousel-footer
|
||||||
|
background-color $ui-monokai-noteDetail-backgroundColor
|
||||||
|
.prev, .next
|
||||||
|
color $ui-monokai-button--active-color
|
||||||
|
background-color $ui-monokai-button-backgroundColor
|
||||||
|
|
||||||
themeDraculaTableOdd = $ui-dracula-noteDetail-backgroundColor
|
themeDraculaTableOdd = $ui-dracula-noteDetail-backgroundColor
|
||||||
themeDraculaTableEven = darken($ui-dracula-noteDetail-backgroundColor, 10%)
|
themeDraculaTableEven = darken($ui-dracula-noteDetail-backgroundColor, 10%)
|
||||||
themeDraculaTableHead = themeDraculaTableEven
|
themeDraculaTableHead = themeDraculaTableEven
|
||||||
@@ -575,6 +625,7 @@ body[data-theme="dracula"]
|
|||||||
border-right solid 1px themeDraculaTableBorder
|
border-right solid 1px themeDraculaTableBorder
|
||||||
kbd
|
kbd
|
||||||
background-color themeDarkBackground
|
background-color themeDarkBackground
|
||||||
|
|
||||||
dl
|
dl
|
||||||
border-color themeDarkBorder
|
border-color themeDarkBorder
|
||||||
background-color themeDraculaTableHead
|
background-color themeDraculaTableHead
|
||||||
@@ -583,3 +634,11 @@ body[data-theme="dracula"]
|
|||||||
dd
|
dd
|
||||||
border-color themeDarkBorder
|
border-color themeDarkBorder
|
||||||
background-color $ui-dracula-noteDetail-backgroundColor
|
background-color $ui-dracula-noteDetail-backgroundColor
|
||||||
|
|
||||||
|
pre.fence
|
||||||
|
.gallery
|
||||||
|
.carousel-main, .carousel-footer
|
||||||
|
background-color $ui-dracula-noteDetail-backgroundColor
|
||||||
|
.prev, .next
|
||||||
|
color $ui-dracula-button--active-color
|
||||||
|
background-color $ui-dracula-button-backgroundColor
|
||||||
|
|||||||
@@ -2,51 +2,27 @@
|
|||||||
* @fileoverview Markdown table of contents generator
|
* @fileoverview Markdown table of contents generator
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import { EOL } from 'os'
|
||||||
import toc from 'markdown-toc'
|
import toc from 'markdown-toc'
|
||||||
import diacritics from 'diacritics-map'
|
|
||||||
import stripColor from 'strip-color'
|
|
||||||
import mdlink from 'markdown-link'
|
import mdlink from 'markdown-link'
|
||||||
|
import slugify from './slugify'
|
||||||
|
|
||||||
const EOL = require('os').EOL
|
const hasProp = Object.prototype.hasOwnProperty
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @caseSensitiveSlugify Custom slugify function
|
* From @enyaxu/markdown-it-anchor
|
||||||
* Same implementation that the original used by markdown-toc (node_modules/markdown-toc/lib/utils.js),
|
|
||||||
* but keeps original case to properly handle https://github.com/BoostIO/Boostnote/issues/2067
|
|
||||||
*/
|
*/
|
||||||
function caseSensitiveSlugify (str) {
|
function uniqueSlug (slug, slugs, opts) {
|
||||||
function replaceDiacritics (str) {
|
let uniq = slug
|
||||||
return str.replace(/[À-ž]/g, function (ch) {
|
let i = opts.uniqueSlugStartIndex
|
||||||
return diacritics[ch] || ch
|
while (hasProp.call(slugs, uniq)) uniq = `${slug}-${i++}`
|
||||||
})
|
slugs[uniq] = true
|
||||||
}
|
return uniq
|
||||||
|
|
||||||
function getTitle (str) {
|
|
||||||
if (/^\[[^\]]+\]\(/.test(str)) {
|
|
||||||
var m = /^\[([^\]]+)\]/.exec(str)
|
|
||||||
if (m) return m[1]
|
|
||||||
}
|
|
||||||
return str
|
|
||||||
}
|
|
||||||
|
|
||||||
str = getTitle(str)
|
|
||||||
str = stripColor(str)
|
|
||||||
// str = str.toLowerCase() //let's be case sensitive
|
|
||||||
|
|
||||||
// `.split()` is often (but not always) faster than `.replace()`
|
|
||||||
str = str.split(' ').join('-')
|
|
||||||
str = str.split(/\t/).join('--')
|
|
||||||
str = str.split(/<\/?[^>]+>/).join('')
|
|
||||||
str = str.split(/[|$&`~=\\\/@+*!?({[\]})<>=.,;:'"^]/).join('')
|
|
||||||
str = str.split(/[。?!,、;:“”【】()〔〕[]﹃﹄“ ”‘’﹁﹂—…-~《》〈〉「」]/).join('')
|
|
||||||
str = replaceDiacritics(str)
|
|
||||||
return str
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function linkify (tok, text, slug, opts) {
|
function linkify (token) {
|
||||||
var uniqeID = opts.num === 0 ? '' : '-' + opts.num
|
token.content = mdlink(token.content, '#' + token.slug)
|
||||||
tok.content = mdlink(text, '#' + slug + uniqeID)
|
return token
|
||||||
return tok
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const TOC_MARKER_START = '<!-- toc -->'
|
const TOC_MARKER_START = '<!-- toc -->'
|
||||||
@@ -91,8 +67,23 @@ export function generateInEditor (editor) {
|
|||||||
* @returns generatedTOC String containing generated TOC
|
* @returns generatedTOC String containing generated TOC
|
||||||
*/
|
*/
|
||||||
export function generate (markdownText) {
|
export function generate (markdownText) {
|
||||||
const generatedToc = toc(markdownText, {slugify: caseSensitiveSlugify, linkify: linkify})
|
const slugs = {}
|
||||||
return TOC_MARKER_START + EOL + EOL + generatedToc.content + EOL + EOL + TOC_MARKER_END
|
const opts = {
|
||||||
|
uniqueSlugStartIndex: 1
|
||||||
|
}
|
||||||
|
|
||||||
|
const result = toc(markdownText, {
|
||||||
|
slugify: title => {
|
||||||
|
return uniqueSlug(slugify(title), slugs, opts)
|
||||||
|
},
|
||||||
|
linkify: false
|
||||||
|
})
|
||||||
|
|
||||||
|
const md = toc.bullets(result.json.map(linkify), {
|
||||||
|
highest: result.highest
|
||||||
|
})
|
||||||
|
|
||||||
|
return TOC_MARKER_START + EOL + EOL + md + EOL + EOL + TOC_MARKER_END
|
||||||
}
|
}
|
||||||
|
|
||||||
function wrapTocWithEol (toc, editor) {
|
function wrapTocWithEol (toc, editor) {
|
||||||
|
|||||||
@@ -7,7 +7,6 @@ import _ from 'lodash'
|
|||||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||||
import katex from 'katex'
|
import katex from 'katex'
|
||||||
import { lastFindInArray } from './utils'
|
import { lastFindInArray } from './utils'
|
||||||
import anchor from '@enyaxu/markdown-it-anchor'
|
|
||||||
|
|
||||||
function createGutter (str, firstLineNumber) {
|
function createGutter (str, firstLineNumber) {
|
||||||
if (Number.isNaN(firstLineNumber)) firstLineNumber = 1
|
if (Number.isNaN(firstLineNumber)) firstLineNumber = 1
|
||||||
@@ -118,14 +117,8 @@ class Markdown {
|
|||||||
this.md.use(require('markdown-it-imsize'))
|
this.md.use(require('markdown-it-imsize'))
|
||||||
this.md.use(require('markdown-it-footnote'))
|
this.md.use(require('markdown-it-footnote'))
|
||||||
this.md.use(require('markdown-it-multimd-table'))
|
this.md.use(require('markdown-it-multimd-table'))
|
||||||
this.md.use(anchor, {
|
this.md.use(require('@enyaxu/markdown-it-anchor'), {
|
||||||
slugify: (title) => {
|
slugify: require('./slugify')
|
||||||
var slug = encodeURI(title.trim()
|
|
||||||
.replace(/[\]\[\!\"\#\$\%\&\'\(\)\*\+\,\.\/\:\;\<\=\>\?\@\\\^\_\{\|\}\~]/g, '')
|
|
||||||
.replace(/\s+/g, '-'))
|
|
||||||
.replace(/\-+$/, '')
|
|
||||||
return slug
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
this.md.use(require('markdown-it-kbd'))
|
this.md.use(require('markdown-it-kbd'))
|
||||||
this.md.use(require('markdown-it-admonition'), {types: ['note', 'hint', 'attention', 'caution', 'danger', 'error']})
|
this.md.use(require('markdown-it-admonition'), {types: ['note', 'hint', 'attention', 'caution', 'danger', 'error']})
|
||||||
@@ -152,6 +145,21 @@ class Markdown {
|
|||||||
<div class="flowchart" data-height="${token.parameters.height}">${token.content}</div>
|
<div class="flowchart" data-height="${token.parameters.height}">${token.content}</div>
|
||||||
</pre>`
|
</pre>`
|
||||||
},
|
},
|
||||||
|
gallery: token => {
|
||||||
|
const content = token.content.split('\n').slice(0, -1).map(line => {
|
||||||
|
const match = /!\[[^\]]*]\(([^\)]*)\)/.exec(line)
|
||||||
|
if (match) {
|
||||||
|
return match[1]
|
||||||
|
} else {
|
||||||
|
return line
|
||||||
|
}
|
||||||
|
}).join('\n')
|
||||||
|
|
||||||
|
return `<pre class="fence" data-line="${token.map[0]}">
|
||||||
|
<span class="filename">${token.fileName}</span>
|
||||||
|
<div class="gallery" data-autoplay="${token.parameters.autoplay}" data-height="${token.parameters.height}">${content}</div>
|
||||||
|
</pre>`
|
||||||
|
},
|
||||||
mermaid: token => {
|
mermaid: token => {
|
||||||
return `<pre class="fence" data-line="${token.map[0]}">
|
return `<pre class="fence" data-line="${token.map[0]}">
|
||||||
<span class="filename">${token.fileName}</span>
|
<span class="filename">${token.fileName}</span>
|
||||||
|
|||||||
@@ -18,7 +18,8 @@ export function createMarkdownNote (storage, folder, dispatch, location, params,
|
|||||||
folder: folder,
|
folder: folder,
|
||||||
title: '',
|
title: '',
|
||||||
tags,
|
tags,
|
||||||
content: ''
|
content: '',
|
||||||
|
linesHighlighted: []
|
||||||
})
|
})
|
||||||
.then(note => {
|
.then(note => {
|
||||||
const noteHash = note.key
|
const noteHash = note.key
|
||||||
@@ -45,6 +46,8 @@ export function createSnippetNote (storage, folder, dispatch, location, params,
|
|||||||
tags = params.tagname.split(' ')
|
tags = params.tagname.split(' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const defaultLanguage = config.editor.snippetDefaultLanguage === 'Auto Detect' ? null : config.editor.snippetDefaultLanguage
|
||||||
|
|
||||||
return dataApi
|
return dataApi
|
||||||
.createNote(storage, {
|
.createNote(storage, {
|
||||||
type: 'SNIPPET_NOTE',
|
type: 'SNIPPET_NOTE',
|
||||||
@@ -55,8 +58,9 @@ export function createSnippetNote (storage, folder, dispatch, location, params,
|
|||||||
snippets: [
|
snippets: [
|
||||||
{
|
{
|
||||||
name: '',
|
name: '',
|
||||||
mode: config.editor.snippetDefaultLanguage || 'text',
|
mode: defaultLanguage,
|
||||||
content: ''
|
content: '',
|
||||||
|
linesHighlighted: []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
|
|||||||
17
browser/lib/slugify.js
Normal file
17
browser/lib/slugify.js
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
import diacritics from 'diacritics-map'
|
||||||
|
|
||||||
|
function replaceDiacritics (str) {
|
||||||
|
return str.replace(/[À-ž]/g, function (ch) {
|
||||||
|
return diacritics[ch] || ch
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = function slugify (title) {
|
||||||
|
let slug = title.trim()
|
||||||
|
|
||||||
|
slug = replaceDiacritics(slug)
|
||||||
|
|
||||||
|
slug = slug.replace(/[^\w\s-]/g, '').replace(/\s+/g, '-')
|
||||||
|
|
||||||
|
return encodeURI(slug).replace(/\-+$/, '')
|
||||||
|
}
|
||||||
@@ -39,12 +39,14 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
isMovingNote: false,
|
isMovingNote: false,
|
||||||
note: Object.assign({
|
note: Object.assign({
|
||||||
title: '',
|
title: '',
|
||||||
content: ''
|
content: '',
|
||||||
|
linesHighlighted: []
|
||||||
}, props.note),
|
}, props.note),
|
||||||
isLockButtonShown: false,
|
isLockButtonShown: false,
|
||||||
isLocked: false,
|
isLocked: false,
|
||||||
editorType: props.config.editor.type
|
editorType: props.config.editor.type
|
||||||
}
|
}
|
||||||
|
|
||||||
this.dispatchTimer = null
|
this.dispatchTimer = null
|
||||||
|
|
||||||
this.toggleLockButton = this.handleToggleLockButton.bind(this)
|
this.toggleLockButton = this.handleToggleLockButton.bind(this)
|
||||||
@@ -71,7 +73,7 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
if (!this.state.isMovingNote && (isNewNote || hasDeletedTags)) {
|
if (!this.state.isMovingNote && (isNewNote || hasDeletedTags)) {
|
||||||
if (this.saveQueue != null) this.saveNow()
|
if (this.saveQueue != null) this.saveNow()
|
||||||
this.setState({
|
this.setState({
|
||||||
note: Object.assign({}, nextProps.note)
|
note: Object.assign({linesHighlighted: []}, nextProps.note)
|
||||||
}, () => {
|
}, () => {
|
||||||
this.refs.content.reload()
|
this.refs.content.reload()
|
||||||
if (this.refs.tags) this.refs.tags.reset()
|
if (this.refs.tags) this.refs.tags.reset()
|
||||||
@@ -361,6 +363,7 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
value={note.content}
|
value={note.content}
|
||||||
storageKey={note.storage}
|
storageKey={note.storage}
|
||||||
noteKey={note.key}
|
noteKey={note.key}
|
||||||
|
linesHighlighted={note.linesHighlighted}
|
||||||
onChange={this.handleUpdateContent.bind(this)}
|
onChange={this.handleUpdateContent.bind(this)}
|
||||||
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
||||||
/>
|
/>
|
||||||
@@ -371,6 +374,7 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
value={note.content}
|
value={note.content}
|
||||||
storageKey={note.storage}
|
storageKey={note.storage}
|
||||||
noteKey={note.key}
|
noteKey={note.key}
|
||||||
|
linesHighlighted={note.linesHighlighted}
|
||||||
onChange={this.handleUpdateContent.bind(this)}
|
onChange={this.handleUpdateContent.bind(this)}
|
||||||
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
note: Object.assign({
|
note: Object.assign({
|
||||||
description: ''
|
description: ''
|
||||||
}, props.note, {
|
}, props.note, {
|
||||||
snippets: props.note.snippets.map((snippet) => Object.assign({}, snippet))
|
snippets: props.note.snippets.map((snippet) => Object.assign({linesHighlighted: []}, snippet))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,8 +76,9 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
const nextNote = Object.assign({
|
const nextNote = Object.assign({
|
||||||
description: ''
|
description: ''
|
||||||
}, nextProps.note, {
|
}, nextProps.note, {
|
||||||
snippets: nextProps.note.snippets.map((snippet) => Object.assign({}, snippet))
|
snippets: nextProps.note.snippets.map((snippet) => Object.assign({linesHighlighted: []}, snippet))
|
||||||
})
|
})
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
snippetIndex: 0,
|
snippetIndex: 0,
|
||||||
note: nextNote
|
note: nextNote
|
||||||
@@ -410,6 +411,8 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
return (e) => {
|
return (e) => {
|
||||||
const snippets = this.state.note.snippets.slice()
|
const snippets = this.state.note.snippets.slice()
|
||||||
snippets[index].content = this.refs['code-' + index].value
|
snippets[index].content = this.refs['code-' + index].value
|
||||||
|
snippets[index].linesHighlighted = e.options.linesHighlighted
|
||||||
|
|
||||||
this.setState(state => ({note: Object.assign(state.note, {snippets: snippets})}))
|
this.setState(state => ({note: Object.assign(state.note, {snippets: snippets})}))
|
||||||
this.setState(state => ({
|
this.setState(state => ({
|
||||||
note: state.note
|
note: state.note
|
||||||
@@ -596,13 +599,16 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
addSnippet () {
|
addSnippet () {
|
||||||
const { config } = this.props
|
const { config: { editor: { snippetDefaultLanguage } } } = this.props
|
||||||
const { note } = this.state
|
const { note } = this.state
|
||||||
|
|
||||||
|
const defaultLanguage = snippetDefaultLanguage === 'Auto Detect' ? null : snippetDefaultLanguage
|
||||||
|
|
||||||
note.snippets = note.snippets.concat([{
|
note.snippets = note.snippets.concat([{
|
||||||
name: '',
|
name: '',
|
||||||
mode: config.editor.snippetDefaultLanguage || 'text',
|
mode: defaultLanguage,
|
||||||
content: ''
|
content: '',
|
||||||
|
linesHighlighted: []
|
||||||
}])
|
}])
|
||||||
const snippetIndex = note.snippets.length - 1
|
const snippetIndex = note.snippets.length - 1
|
||||||
|
|
||||||
@@ -668,6 +674,8 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
const storageKey = note.storage
|
const storageKey = note.storage
|
||||||
const folderKey = note.folder
|
const folderKey = note.folder
|
||||||
|
|
||||||
|
const autoDetect = config.editor.snippetDefaultLanguage === 'Auto Detect'
|
||||||
|
|
||||||
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
||||||
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
||||||
let editorIndentSize = parseInt(config.editor.indentSize, 10)
|
let editorIndentSize = parseInt(config.editor.indentSize, 10)
|
||||||
@@ -692,10 +700,6 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
|
|
||||||
const viewList = note.snippets.map((snippet, index) => {
|
const viewList = note.snippets.map((snippet, index) => {
|
||||||
const isActive = this.state.snippetIndex === index
|
const isActive = this.state.snippetIndex === index
|
||||||
|
|
||||||
let syntax = CodeMirror.findModeByName(convertModeName(snippet.mode))
|
|
||||||
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
|
|
||||||
|
|
||||||
return <div styleName='tabView'
|
return <div styleName='tabView'
|
||||||
key={index}
|
key={index}
|
||||||
style={{zIndex: isActive ? 5 : 4}}
|
style={{zIndex: isActive ? 5 : 4}}
|
||||||
@@ -704,20 +708,25 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
? <MarkdownEditor styleName='tabView-content'
|
? <MarkdownEditor styleName='tabView-content'
|
||||||
value={snippet.content}
|
value={snippet.content}
|
||||||
config={config}
|
config={config}
|
||||||
|
linesHighlighted={snippet.linesHighlighted}
|
||||||
onChange={(e) => this.handleCodeChange(index)(e)}
|
onChange={(e) => this.handleCodeChange(index)(e)}
|
||||||
ref={'code-' + index}
|
ref={'code-' + index}
|
||||||
ignorePreviewPointerEvents={this.props.ignorePreviewPointerEvents}
|
ignorePreviewPointerEvents={this.props.ignorePreviewPointerEvents}
|
||||||
storageKey={storageKey}
|
storageKey={storageKey}
|
||||||
/>
|
/>
|
||||||
: <CodeEditor styleName='tabView-content'
|
: <CodeEditor styleName='tabView-content'
|
||||||
mode={snippet.mode}
|
mode={snippet.mode || (autoDetect ? null : config.editor.snippetDefaultLanguage)}
|
||||||
value={snippet.content}
|
value={snippet.content}
|
||||||
|
linesHighlighted={snippet.linesHighlighted}
|
||||||
theme={config.editor.theme}
|
theme={config.editor.theme}
|
||||||
fontFamily={config.editor.fontFamily}
|
fontFamily={config.editor.fontFamily}
|
||||||
fontSize={editorFontSize}
|
fontSize={editorFontSize}
|
||||||
indentType={config.editor.indentType}
|
indentType={config.editor.indentType}
|
||||||
indentSize={editorIndentSize}
|
indentSize={editorIndentSize}
|
||||||
displayLineNumbers={config.editor.displayLineNumbers}
|
displayLineNumbers={config.editor.displayLineNumbers}
|
||||||
|
matchingPairs={config.editor.matchingPairs}
|
||||||
|
matchingTriples={config.editor.matchingTriples}
|
||||||
|
explodingPairs={config.editor.explodingPairs}
|
||||||
keyMap={config.editor.keyMap}
|
keyMap={config.editor.keyMap}
|
||||||
scrollPastEnd={config.editor.scrollPastEnd}
|
scrollPastEnd={config.editor.scrollPastEnd}
|
||||||
fetchUrlTitle={config.editor.fetchUrlTitle}
|
fetchUrlTitle={config.editor.fetchUrlTitle}
|
||||||
@@ -726,6 +735,7 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
ref={'code-' + index}
|
ref={'code-' + index}
|
||||||
enableSmartPaste={config.editor.enableSmartPaste}
|
enableSmartPaste={config.editor.enableSmartPaste}
|
||||||
hotkey={config.hotkey}
|
hotkey={config.hotkey}
|
||||||
|
autoDetect={autoDetect}
|
||||||
/>
|
/>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -31,7 +31,7 @@
|
|||||||
|
|
||||||
.tabList
|
.tabList
|
||||||
absolute left right
|
absolute left right
|
||||||
top 55px
|
top 70px
|
||||||
height 30px
|
height 30px
|
||||||
display flex
|
display flex
|
||||||
background-color $ui-noteDetail-backgroundColor
|
background-color $ui-noteDetail-backgroundColor
|
||||||
@@ -57,6 +57,9 @@
|
|||||||
.tabList .tabButton
|
.tabList .tabButton
|
||||||
navWhiteButtonColor()
|
navWhiteButtonColor()
|
||||||
width 30px
|
width 30px
|
||||||
|
border-left 1px solid $ui-borderColor
|
||||||
|
border-top 1px solid $ui-borderColor
|
||||||
|
border-right 1px solid $ui-borderColor
|
||||||
|
|
||||||
.tabView
|
.tabView
|
||||||
absolute left right bottom
|
absolute left right bottom
|
||||||
@@ -98,17 +101,34 @@
|
|||||||
opacity 0
|
opacity 0
|
||||||
transition 0.1s
|
transition 0.1s
|
||||||
|
|
||||||
body[data-theme="white"]
|
body[data-theme="white"], body[data-theme="default"]
|
||||||
.root
|
.root
|
||||||
box-shadow $note-detail-box-shadow
|
box-shadow $note-detail-box-shadow
|
||||||
border none
|
border none
|
||||||
|
|
||||||
|
.tabButton
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||||
|
color $ui-text-color
|
||||||
|
transition 0.15s
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.root
|
.root
|
||||||
border-left 1px solid $ui-dark-borderColor
|
border-left 1px solid $ui-dark-borderColor
|
||||||
background-color $ui-dark-noteDetail-backgroundColor
|
background-color $ui-dark-noteDetail-backgroundColor
|
||||||
box-shadow none
|
box-shadow none
|
||||||
|
|
||||||
|
.tabList .tabButton
|
||||||
|
border-color $ui-dark-borderColor
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||||
|
|
||||||
|
.tabButton
|
||||||
|
&:hover
|
||||||
|
background-color alpha($ui-dark-button--active-backgroundColor, 20%)
|
||||||
|
color $ui-dark-text-color
|
||||||
|
transition 0.15s
|
||||||
|
|
||||||
.body
|
.body
|
||||||
background-color $ui-dark-noteDetail-backgroundColor
|
background-color $ui-dark-noteDetail-backgroundColor
|
||||||
|
|
||||||
@@ -118,7 +138,6 @@ body[data-theme="dark"]
|
|||||||
border 1px solid $ui-dark-borderColor
|
border 1px solid $ui-dark-borderColor
|
||||||
|
|
||||||
.tabList
|
.tabList
|
||||||
background-color $ui-button--active-backgroundColor
|
|
||||||
background-color $ui-dark-noteDetail-backgroundColor
|
background-color $ui-dark-noteDetail-backgroundColor
|
||||||
|
|
||||||
.tabList .list
|
.tabList .list
|
||||||
@@ -150,6 +169,15 @@ body[data-theme="solarized-dark"]
|
|||||||
color $ui-solarized-dark-text-color
|
color $ui-solarized-dark-text-color
|
||||||
border 1px solid $ui-solarized-dark-borderColor
|
border 1px solid $ui-solarized-dark-borderColor
|
||||||
|
|
||||||
|
.tabList .tabButton
|
||||||
|
border-color $ui-solarized-dark-borderColor
|
||||||
|
|
||||||
|
.tabButton
|
||||||
|
&:hover
|
||||||
|
color $ui-solarized-dark-button--active-color
|
||||||
|
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
||||||
|
transition 0.15s
|
||||||
|
|
||||||
.tabList
|
.tabList
|
||||||
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
background-color $ui-solarized-dark-noteDetail-backgroundColor
|
||||||
color $ui-solarized-dark-text-color
|
color $ui-solarized-dark-text-color
|
||||||
@@ -167,6 +195,14 @@ body[data-theme="monokai"]
|
|||||||
color $ui-monokai-text-color
|
color $ui-monokai-text-color
|
||||||
border 1px solid $ui-monokai-borderColor
|
border 1px solid $ui-monokai-borderColor
|
||||||
|
|
||||||
|
.tabList .tabButton
|
||||||
|
border-color $ui-monokai-borderColor
|
||||||
|
|
||||||
|
.tabButton
|
||||||
|
&:hover
|
||||||
|
color $ui-monokai-text-color
|
||||||
|
background-color $ui-monokai-noteDetail-backgroundColor
|
||||||
|
|
||||||
.tabList
|
.tabList
|
||||||
background-color $ui-monokai-noteDetail-backgroundColor
|
background-color $ui-monokai-noteDetail-backgroundColor
|
||||||
color $ui-monokai-text-color
|
color $ui-monokai-text-color
|
||||||
@@ -184,6 +220,14 @@ body[data-theme="dracula"]
|
|||||||
color $ui-dracula-text-color
|
color $ui-dracula-text-color
|
||||||
border 1px solid $ui-dracula-borderColor
|
border 1px solid $ui-dracula-borderColor
|
||||||
|
|
||||||
|
.tabList .tabButton
|
||||||
|
border-color $ui-dracula-borderColor
|
||||||
|
|
||||||
|
.tabButton
|
||||||
|
&:hover
|
||||||
|
color $ui-dracula-text-color
|
||||||
|
background-color $ui-dracula-noteDetail-backgroundColor
|
||||||
|
|
||||||
.tabList
|
.tabList
|
||||||
background-color $ui-dracula-noteDetail-backgroundColor
|
background-color $ui-dracula-noteDetail-backgroundColor
|
||||||
color $ui-dracula-text-color
|
color $ui-dracula-text-color
|
||||||
@@ -45,8 +45,14 @@ class TagSelect extends React.Component {
|
|||||||
value = _.isArray(value)
|
value = _.isArray(value)
|
||||||
? value.slice()
|
? value.slice()
|
||||||
: []
|
: []
|
||||||
value.push(newTag)
|
|
||||||
value = _.uniq(value)
|
if (!_.includes(value, newTag)) {
|
||||||
|
value.push(newTag)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.props.saveTagsAlphabetically) {
|
||||||
|
value = _.sortBy(value)
|
||||||
|
}
|
||||||
|
|
||||||
this.setState({
|
this.setState({
|
||||||
newTag: ''
|
newTag: ''
|
||||||
|
|||||||
@@ -96,12 +96,14 @@ 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>",
|
||||||
|
linesHighlighted: []
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
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)",
|
||||||
|
linesHighlighted: []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
@@ -234,8 +236,8 @@ class Main extends React.Component {
|
|||||||
if (this.state.isRightSliderFocused) {
|
if (this.state.isRightSliderFocused) {
|
||||||
const offset = this.refs.body.getBoundingClientRect().left
|
const offset = this.refs.body.getBoundingClientRect().left
|
||||||
let newListWidth = e.pageX - offset
|
let newListWidth = e.pageX - offset
|
||||||
if (newListWidth < 10) {
|
if (newListWidth < 180) {
|
||||||
newListWidth = 10
|
newListWidth = 180
|
||||||
} else if (newListWidth > 600) {
|
} else if (newListWidth > 600) {
|
||||||
newListWidth = 600
|
newListWidth = 600
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
import PropTypes from 'prop-types'
|
import PropTypes from 'prop-types'
|
||||||
import React from 'react'
|
import React from 'react'
|
||||||
import CSSModules from 'browser/lib/CSSModules'
|
import CSSModules from 'browser/lib/CSSModules'
|
||||||
import debounceRender from 'react-debounce-render'
|
|
||||||
import styles from './NoteList.styl'
|
import styles from './NoteList.styl'
|
||||||
import moment from 'moment'
|
import moment from 'moment'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
@@ -711,7 +710,8 @@ class NoteList extends React.Component {
|
|||||||
type: firstNote.type,
|
type: firstNote.type,
|
||||||
folder: folder.key,
|
folder: folder.key,
|
||||||
title: firstNote.title + ' ' + i18n.__('copy'),
|
title: firstNote.title + ' ' + i18n.__('copy'),
|
||||||
content: firstNote.content
|
content: firstNote.content,
|
||||||
|
linesHighlighted: firstNote.linesHighlighted
|
||||||
})
|
})
|
||||||
.then((note) => {
|
.then((note) => {
|
||||||
attachmentManagement.cloneAttachments(firstNote, note)
|
attachmentManagement.cloneAttachments(firstNote, note)
|
||||||
@@ -1129,4 +1129,4 @@ NoteList.propTypes = {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export default debounceRender(CSSModules(NoteList, styles))
|
export default CSSModules(NoteList, styles)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import _ from 'lodash'
|
|||||||
import ee from 'browser/main/lib/eventEmitter'
|
import ee from 'browser/main/lib/eventEmitter'
|
||||||
import NewNoteButton from 'browser/main/NewNoteButton'
|
import NewNoteButton from 'browser/main/NewNoteButton'
|
||||||
import i18n from 'browser/lib/i18n'
|
import i18n from 'browser/lib/i18n'
|
||||||
|
import debounce from 'lodash/debounce'
|
||||||
|
|
||||||
class TopBar extends React.Component {
|
class TopBar extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -25,6 +26,10 @@ class TopBar extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.codeInitHandler = this.handleCodeInit.bind(this)
|
this.codeInitHandler = this.handleCodeInit.bind(this)
|
||||||
|
|
||||||
|
this.updateKeyword = debounce(this.updateKeyword, 1000 / 60, {
|
||||||
|
maxWait: 1000 / 8
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
@@ -94,7 +99,6 @@ class TopBar extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleKeyUp (e) {
|
handleKeyUp (e) {
|
||||||
const { router } = this.context
|
|
||||||
// reset states
|
// reset states
|
||||||
this.setState({
|
this.setState({
|
||||||
isConfirmTranslation: false
|
isConfirmTranslation: false
|
||||||
@@ -106,21 +110,21 @@ class TopBar extends React.Component {
|
|||||||
isConfirmTranslation: true
|
isConfirmTranslation: true
|
||||||
})
|
})
|
||||||
const keyword = this.refs.searchInput.value
|
const keyword = this.refs.searchInput.value
|
||||||
router.push(`/searched/${encodeURIComponent(keyword)}`)
|
this.updateKeyword(keyword)
|
||||||
this.setState({
|
|
||||||
search: keyword
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSearchChange (e) {
|
handleSearchChange (e) {
|
||||||
const { router } = this.context
|
|
||||||
const keyword = this.refs.searchInput.value
|
|
||||||
if (this.state.isAlphabet || this.state.isConfirmTranslation) {
|
if (this.state.isAlphabet || this.state.isConfirmTranslation) {
|
||||||
router.push(`/searched/${encodeURIComponent(keyword)}`)
|
const keyword = this.refs.searchInput.value
|
||||||
|
this.updateKeyword(keyword)
|
||||||
} else {
|
} else {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
updateKeyword (keyword) {
|
||||||
|
this.context.router.push(`/searched/${encodeURIComponent(keyword)}`)
|
||||||
this.setState({
|
this.setState({
|
||||||
search: keyword
|
search: keyword
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -45,6 +45,9 @@ export const DEFAULT_CONFIG = {
|
|||||||
enableRulers: false,
|
enableRulers: false,
|
||||||
rulers: [80, 120],
|
rulers: [80, 120],
|
||||||
displayLineNumbers: true,
|
displayLineNumbers: true,
|
||||||
|
matchingPairs: '()[]{}\'\'""$$**``',
|
||||||
|
matchingTriples: '```"""\'\'\'',
|
||||||
|
explodingPairs: '[]{}``$$',
|
||||||
switchPreview: 'BLUR', // 'BLUR', 'DBL_CLICK', 'RIGHTCLICK'
|
switchPreview: 'BLUR', // 'BLUR', 'DBL_CLICK', 'RIGHTCLICK'
|
||||||
delfaultStatus: 'PREVIEW', // 'PREVIEW', 'CODE'
|
delfaultStatus: 'PREVIEW', // 'PREVIEW', 'CODE'
|
||||||
scrollPastEnd: false,
|
scrollPastEnd: false,
|
||||||
|
|||||||
@@ -227,7 +227,15 @@ function migrateAttachments (markdownContent, storagePath, noteKey) {
|
|||||||
* @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths.
|
* @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths.
|
||||||
*/
|
*/
|
||||||
function fixLocalURLS (renderedHTML, storagePath) {
|
function fixLocalURLS (renderedHTML, storagePath) {
|
||||||
return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '.*?"', 'g'), function (match) {
|
/*
|
||||||
|
A :storage reference is like `:storage/3b6f8bd6-4edd-4b15-96e0-eadc4475b564/f939b2c3.jpg`.
|
||||||
|
|
||||||
|
- `STORAGE_FOLDER_PLACEHOLDER` will match `:storage`
|
||||||
|
- `(?:(?:\\\/|%5C)[\\w.]+)+` will match `/3b6f8bd6-4edd-4b15-96e0-eadc4475b564/f939b2c3.jpg`
|
||||||
|
- `(?:\\\/|%5C)[\\w.]+` will either match `/3b6f8bd6-4edd-4b15-96e0-eadc4475b564` or `/f939b2c3.jpg`
|
||||||
|
- `(?:\\\/|%5C)` match the path seperator. `\\\/` for posix systems and `%5C` for windows.
|
||||||
|
*/
|
||||||
|
return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '(?:(?:\\\/|%5C)[\\w.]+)+', 'g'), function (match) {
|
||||||
var encodedPathSeparators = new RegExp(mdurl.encode(path.win32.sep) + '|' + mdurl.encode(path.posix.sep), 'g')
|
var encodedPathSeparators = new RegExp(mdurl.encode(path.win32.sep) + '|' + mdurl.encode(path.posix.sep), 'g')
|
||||||
return match.replace(encodedPathSeparators, path.sep).replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER))
|
return match.replace(encodedPathSeparators, path.sep).replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER))
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ function validateInput (input) {
|
|||||||
switch (input.type) {
|
switch (input.type) {
|
||||||
case 'MARKDOWN_NOTE':
|
case 'MARKDOWN_NOTE':
|
||||||
if (!_.isString(input.content)) input.content = ''
|
if (!_.isString(input.content)) input.content = ''
|
||||||
|
if (!_.isArray(input.linesHighlighted)) input.linesHighlighted = []
|
||||||
break
|
break
|
||||||
case 'SNIPPET_NOTE':
|
case 'SNIPPET_NOTE':
|
||||||
if (!_.isString(input.description)) input.description = ''
|
if (!_.isString(input.description)) input.description = ''
|
||||||
@@ -23,7 +24,8 @@ function validateInput (input) {
|
|||||||
input.snippets = [{
|
input.snippets = [{
|
||||||
name: '',
|
name: '',
|
||||||
mode: 'text',
|
mode: 'text',
|
||||||
content: ''
|
content: '',
|
||||||
|
linesHighlighted: []
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
break
|
break
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ function createSnippet (snippetFile) {
|
|||||||
id: crypto.randomBytes(16).toString('hex'),
|
id: crypto.randomBytes(16).toString('hex'),
|
||||||
name: 'Unnamed snippet',
|
name: 'Unnamed snippet',
|
||||||
prefix: [],
|
prefix: [],
|
||||||
content: ''
|
content: '',
|
||||||
|
linesHighlighted: []
|
||||||
}
|
}
|
||||||
fetchSnippet(null, snippetFile).then((snippets) => {
|
fetchSnippet(null, snippetFile).then((snippets) => {
|
||||||
snippets.push(newSnippet)
|
snippets.push(newSnippet)
|
||||||
|
|||||||
@@ -69,7 +69,8 @@ function importAll (storage, data) {
|
|||||||
isStarred: false,
|
isStarred: false,
|
||||||
title: article.title,
|
title: article.title,
|
||||||
content: '# ' + article.title + '\n\n' + article.content,
|
content: '# ' + article.title + '\n\n' + article.content,
|
||||||
key: noteKey
|
key: noteKey,
|
||||||
|
linesHighlighted: article.linesHighlighted
|
||||||
}
|
}
|
||||||
notes.push(newNote)
|
notes.push(newNote)
|
||||||
} else {
|
} else {
|
||||||
@@ -87,7 +88,8 @@ function importAll (storage, data) {
|
|||||||
snippets: [{
|
snippets: [{
|
||||||
name: article.mode,
|
name: article.mode,
|
||||||
mode: article.mode,
|
mode: article.mode,
|
||||||
content: article.content
|
content: article.content,
|
||||||
|
linesHighlighted: article.linesHighlighted
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
notes.push(newNote)
|
notes.push(newNote)
|
||||||
|
|||||||
@@ -39,6 +39,9 @@ function validateInput (input) {
|
|||||||
if (input.content != null) {
|
if (input.content != null) {
|
||||||
if (!_.isString(input.content)) validatedInput.content = ''
|
if (!_.isString(input.content)) validatedInput.content = ''
|
||||||
else validatedInput.content = input.content
|
else validatedInput.content = input.content
|
||||||
|
|
||||||
|
if (!_.isArray(input.linesHighlighted)) validatedInput.linesHighlighted = []
|
||||||
|
else validatedInput.linesHighlighted = input.linesHighlighted
|
||||||
}
|
}
|
||||||
return validatedInput
|
return validatedInput
|
||||||
case 'SNIPPET_NOTE':
|
case 'SNIPPET_NOTE':
|
||||||
@@ -51,7 +54,8 @@ function validateInput (input) {
|
|||||||
validatedInput.snippets = [{
|
validatedInput.snippets = [{
|
||||||
name: '',
|
name: '',
|
||||||
mode: 'text',
|
mode: 'text',
|
||||||
content: ''
|
content: '',
|
||||||
|
linesHighlighted: []
|
||||||
}]
|
}]
|
||||||
} else {
|
} else {
|
||||||
validatedInput.snippets = input.snippets
|
validatedInput.snippets = input.snippets
|
||||||
@@ -96,12 +100,14 @@ function updateNote (storageKey, noteKey, input) {
|
|||||||
snippets: [{
|
snippets: [{
|
||||||
name: '',
|
name: '',
|
||||||
mode: 'text',
|
mode: 'text',
|
||||||
content: ''
|
content: '',
|
||||||
|
linesHighlighted: []
|
||||||
}]
|
}]
|
||||||
}
|
}
|
||||||
: {
|
: {
|
||||||
type: 'MARKDOWN_NOTE',
|
type: 'MARKDOWN_NOTE',
|
||||||
content: ''
|
content: '',
|
||||||
|
linesHighlighted: []
|
||||||
}
|
}
|
||||||
noteData.title = ''
|
noteData.title = ''
|
||||||
if (storage.folders.length === 0) throw new Error('Failed to restore note: No folder exists.')
|
if (storage.folders.length === 0) throw new Error('Failed to restore note: No folder exists.')
|
||||||
|
|||||||
@@ -12,7 +12,8 @@ function updateSnippet (snippet, snippetFile) {
|
|||||||
if (
|
if (
|
||||||
currentSnippet.name === snippet.name &&
|
currentSnippet.name === snippet.name &&
|
||||||
currentSnippet.prefix === snippet.prefix &&
|
currentSnippet.prefix === snippet.prefix &&
|
||||||
currentSnippet.content === snippet.content
|
currentSnippet.content === snippet.content &&
|
||||||
|
currentSnippet.linesHighlighted === snippet.linesHighlighted
|
||||||
) {
|
) {
|
||||||
// if everything is the same then don't write to disk
|
// if everything is the same then don't write to disk
|
||||||
resolve(snippets)
|
resolve(snippets)
|
||||||
@@ -20,6 +21,7 @@ function updateSnippet (snippet, snippetFile) {
|
|||||||
currentSnippet.name = snippet.name
|
currentSnippet.name = snippet.name
|
||||||
currentSnippet.prefix = snippet.prefix
|
currentSnippet.prefix = snippet.prefix
|
||||||
currentSnippet.content = snippet.content
|
currentSnippet.content = snippet.content
|
||||||
|
currentSnippet.linesHighlighted = (snippet.linesHighlighted)
|
||||||
fs.writeFile(snippetFile || consts.SNIPPET_FILE, JSON.stringify(snippets, null, 4), (err) => {
|
fs.writeFile(snippetFile || consts.SNIPPET_FILE, JSON.stringify(snippets, null, 4), (err) => {
|
||||||
if (err) reject(err)
|
if (err) reject(err)
|
||||||
resolve(snippets)
|
resolve(snippets)
|
||||||
|
|||||||
@@ -151,7 +151,7 @@ class HotkeyTab extends React.Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div styleName='group-section'>
|
<div styleName='group-section'>
|
||||||
<div styleName='group-section-label'>{i18n.__('Paste Smartly')}</div>
|
<div styleName='group-section-label'>{i18n.__('Paste HTML')}</div>
|
||||||
<div styleName='group-section-control'>
|
<div styleName='group-section-control'>
|
||||||
<input styleName='group-section-control-input'
|
<input styleName='group-section-control-input'
|
||||||
onChange={(e) => this.handleHotkeyChange(e)}
|
onChange={(e) => this.handleHotkeyChange(e)}
|
||||||
|
|||||||
@@ -73,6 +73,11 @@ class InfoTab extends React.Component {
|
|||||||
<div styleName='header--sub'>{i18n.__('Community')}</div>
|
<div styleName='header--sub'>{i18n.__('Community')}</div>
|
||||||
<div styleName='top'>
|
<div styleName='top'>
|
||||||
<ul styleName='list'>
|
<ul styleName='list'>
|
||||||
|
<li>
|
||||||
|
<a href='https://issuehunt.io/repos/53266139'
|
||||||
|
onClick={(e) => this.handleLinkClick(e)}
|
||||||
|
>{i18n.__('Bounty on IssueHunt')}</a>
|
||||||
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<a href='https://boostnote.io/#subscribe'
|
<a href='https://boostnote.io/#subscribe'
|
||||||
onClick={(e) => this.handleLinkClick(e)}
|
onClick={(e) => this.handleLinkClick(e)}
|
||||||
|
|||||||
@@ -28,9 +28,9 @@ class SnippetEditor extends React.Component {
|
|||||||
foldGutter: true,
|
foldGutter: true,
|
||||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
||||||
autoCloseBrackets: {
|
autoCloseBrackets: {
|
||||||
pairs: '()[]{}\'\'""$$**``',
|
pairs: this.props.matchingPairs,
|
||||||
triples: '```"""\'\'\'',
|
triples: this.props.matchingTriples,
|
||||||
explode: '[]{}``$$',
|
explode: this.props.explodingPairs,
|
||||||
override: true
|
override: true
|
||||||
},
|
},
|
||||||
mode: 'null'
|
mode: 'null'
|
||||||
|
|||||||
@@ -136,6 +136,9 @@ class SnippetTab extends React.Component {
|
|||||||
enableRulers={config.editor.enableRulers}
|
enableRulers={config.editor.enableRulers}
|
||||||
rulers={config.editor.rulers}
|
rulers={config.editor.rulers}
|
||||||
displayLineNumbers={config.editor.displayLineNumbers}
|
displayLineNumbers={config.editor.displayLineNumbers}
|
||||||
|
matchingPairs={config.editor.matchingPairs}
|
||||||
|
matchingTriples={config.editor.matchingTriples}
|
||||||
|
explodingPairs={config.editor.explodingPairs}
|
||||||
scrollPastEnd={config.editor.scrollPastEnd}
|
scrollPastEnd={config.editor.scrollPastEnd}
|
||||||
onRef={ref => { this.snippetEditor = ref }} />
|
onRef={ref => { this.snippetEditor = ref }} />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -96,6 +96,9 @@ class UiTab extends React.Component {
|
|||||||
enableTableEditor: this.refs.enableTableEditor.checked,
|
enableTableEditor: this.refs.enableTableEditor.checked,
|
||||||
enableFrontMatterTitle: this.refs.enableFrontMatterTitle.checked,
|
enableFrontMatterTitle: this.refs.enableFrontMatterTitle.checked,
|
||||||
frontMatterTitleField: this.refs.frontMatterTitleField.value,
|
frontMatterTitleField: this.refs.frontMatterTitleField.value,
|
||||||
|
matchingPairs: this.refs.matchingPairs.value,
|
||||||
|
matchingTriples: this.refs.matchingTriples.value,
|
||||||
|
explodingPairs: this.refs.explodingPairs.value,
|
||||||
spellcheck: this.refs.spellcheck.checked,
|
spellcheck: this.refs.spellcheck.checked,
|
||||||
enableSmartPaste: this.refs.enableSmartPaste.checked
|
enableSmartPaste: this.refs.enableSmartPaste.checked
|
||||||
},
|
},
|
||||||
@@ -478,6 +481,7 @@ class UiTab extends React.Component {
|
|||||||
ref='editorSnippetDefaultLanguage'
|
ref='editorSnippetDefaultLanguage'
|
||||||
onChange={(e) => this.handleUIChange(e)}
|
onChange={(e) => this.handleUIChange(e)}
|
||||||
>
|
>
|
||||||
|
<option key='Auto Detect' value='Auto Detect'>Auto Detect</option>
|
||||||
{
|
{
|
||||||
_.sortBy(CodeMirror.modeInfo.map(mode => mode.name)).map(name => (<option key={name} value={name}>{name}</option>))
|
_.sortBy(CodeMirror.modeInfo.map(mode => mode.name)).map(name => (<option key={name} value={name}>{name}</option>))
|
||||||
}
|
}
|
||||||
@@ -561,7 +565,7 @@ class UiTab extends React.Component {
|
|||||||
ref='enableSmartPaste'
|
ref='enableSmartPaste'
|
||||||
type='checkbox'
|
type='checkbox'
|
||||||
/>
|
/>
|
||||||
{i18n.__('Enable smart paste')}
|
{i18n.__('Enable HTML paste')}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -576,6 +580,48 @@ class UiTab extends React.Component {
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div styleName='group-section'>
|
||||||
|
<div styleName='group-section-label'>
|
||||||
|
{i18n.__('Matching character pairs')}
|
||||||
|
</div>
|
||||||
|
<div styleName='group-section-control'>
|
||||||
|
<input styleName='group-section-control-input'
|
||||||
|
value={this.state.config.editor.matchingPairs}
|
||||||
|
ref='matchingPairs'
|
||||||
|
onChange={(e) => this.handleUIChange(e)}
|
||||||
|
type='text'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div styleName='group-section'>
|
||||||
|
<div styleName='group-section-label'>
|
||||||
|
{i18n.__('Matching character triples')}
|
||||||
|
</div>
|
||||||
|
<div styleName='group-section-control'>
|
||||||
|
<input styleName='group-section-control-input'
|
||||||
|
value={this.state.config.editor.matchingTriples}
|
||||||
|
ref='matchingTriples'
|
||||||
|
onChange={(e) => this.handleUIChange(e)}
|
||||||
|
type='text'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div styleName='group-section'>
|
||||||
|
<div styleName='group-section-label'>
|
||||||
|
{i18n.__('Exploding character pairs')}
|
||||||
|
</div>
|
||||||
|
<div styleName='group-section-control'>
|
||||||
|
<input styleName='group-section-control-input'
|
||||||
|
value={this.state.config.editor.explodingPairs}
|
||||||
|
ref='explodingPairs'
|
||||||
|
onChange={(e) => this.handleUIChange(e)}
|
||||||
|
type='text'
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div styleName='group-header2'>{i18n.__('Preview')}</div>
|
<div styleName='group-header2'>{i18n.__('Preview')}</div>
|
||||||
<div styleName='group-section'>
|
<div styleName='group-section'>
|
||||||
<div styleName='group-section-label'>
|
<div styleName='group-section-label'>
|
||||||
@@ -603,6 +649,7 @@ class UiTab extends React.Component {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div styleName='group-section'>
|
<div styleName='group-section'>
|
||||||
<div styleName='group-section-label'>{i18n.__('Code Block Theme')}</div>
|
<div styleName='group-section-label'>{i18n.__('Code Block Theme')}</div>
|
||||||
<div styleName='group-section-control'>
|
<div styleName='group-section-control'>
|
||||||
|
|||||||
@@ -240,10 +240,8 @@ navWhiteButtonColor()
|
|||||||
&:hover
|
&:hover
|
||||||
background-color alpha($ui-button--active-backgroundColor, 20%)
|
background-color alpha($ui-button--active-backgroundColor, 20%)
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
color $ui-text-color
|
|
||||||
&:active, &:active:hover
|
&:active, &:active:hover
|
||||||
background-color $ui-button--active-backgroundColor
|
background-color $ui-button--active-backgroundColor
|
||||||
color $ui-text-color
|
|
||||||
transition 0.15s
|
transition 0.15s
|
||||||
|
|
||||||
// UI Button
|
// UI Button
|
||||||
|
|||||||
11
package.json
11
package.json
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "boost",
|
"name": "boost",
|
||||||
"productName": "Boostnote",
|
"productName": "Boostnote",
|
||||||
"version": "0.11.11",
|
"version": "0.11.12",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"description": "Boostnote",
|
"description": "Boostnote",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
@@ -66,6 +66,7 @@
|
|||||||
"flowchart.js": "^1.6.5",
|
"flowchart.js": "^1.6.5",
|
||||||
"font-awesome": "^4.3.0",
|
"font-awesome": "^4.3.0",
|
||||||
"fs-extra": "^5.0.0",
|
"fs-extra": "^5.0.0",
|
||||||
|
"highlight.js": "^9.13.1",
|
||||||
"i18n-2": "^0.7.2",
|
"i18n-2": "^0.7.2",
|
||||||
"iconv-lite": "^0.4.19",
|
"iconv-lite": "^0.4.19",
|
||||||
"immutable": "^3.8.1",
|
"immutable": "^3.8.1",
|
||||||
@@ -99,8 +100,10 @@
|
|||||||
"react-codemirror": "^0.3.0",
|
"react-codemirror": "^0.3.0",
|
||||||
"react-debounce-render": "^4.0.1",
|
"react-debounce-render": "^4.0.1",
|
||||||
"react-dom": "^15.0.2",
|
"react-dom": "^15.0.2",
|
||||||
|
"react-image-carousel": "^2.0.18",
|
||||||
"react-redux": "^4.4.5",
|
"react-redux": "^4.4.5",
|
||||||
"react-sortable-hoc": "^0.6.7",
|
"react-sortable-hoc": "^0.6.7",
|
||||||
|
"react-transition-group": "^2.5.0",
|
||||||
"redux": "^3.5.2",
|
"redux": "^3.5.2",
|
||||||
"sander": "^0.5.1",
|
"sander": "^0.5.1",
|
||||||
"sanitize-html": "^1.18.2",
|
"sanitize-html": "^1.18.2",
|
||||||
@@ -142,6 +145,7 @@
|
|||||||
"grunt": "^0.4.5",
|
"grunt": "^0.4.5",
|
||||||
"grunt-electron-installer": "2.1.0",
|
"grunt-electron-installer": "2.1.0",
|
||||||
"history": "^1.17.0",
|
"history": "^1.17.0",
|
||||||
|
"husky": "^1.1.0",
|
||||||
"identity-obj-proxy": "^3.0.0",
|
"identity-obj-proxy": "^3.0.0",
|
||||||
"jest": "^22.4.3",
|
"jest": "^22.4.3",
|
||||||
"jest-localstorage-mock": "^2.2.0",
|
"jest-localstorage-mock": "^2.2.0",
|
||||||
@@ -189,5 +193,10 @@
|
|||||||
"<rootDir>/tests/jest.js",
|
"<rootDir>/tests/jest.js",
|
||||||
"jest-localstorage-mock"
|
"jest-localstorage-mock"
|
||||||
]
|
]
|
||||||
|
},
|
||||||
|
"husky": {
|
||||||
|
"hooks": {
|
||||||
|
"pre-commit": "npm run lint"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ Boostnote is an open source project. It's an independent project with its ongoin
|
|||||||
|
|
||||||
Issues on Boostnote can be funded by anyone and the money will be distributed to contributors and maintainers. If you use Boostnote please consider becoming a backer:
|
Issues on Boostnote can be funded by anyone and the money will be distributed to contributors and maintainers. If you use Boostnote please consider becoming a backer:
|
||||||
|
|
||||||
[](https://issuehunt.io/repos/53266139)
|
[](https://issuehunt.io/repos/53266139)
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
- [Facebook Group](https://www.facebook.com/groups/boostnote/)
|
- [Facebook Group](https://www.facebook.com/groups/boostnote/)
|
||||||
|
|||||||
@@ -25,13 +25,16 @@ test.serial('Create a note', (t) => {
|
|||||||
const storageKey = t.context.storage.cache.key
|
const storageKey = t.context.storage.cache.key
|
||||||
const folderKey = t.context.storage.json.folders[0].key
|
const folderKey = t.context.storage.json.folders[0].key
|
||||||
|
|
||||||
|
const randLinesHighlightedArray = new Array(10).fill().map(() => Math.round(Math.random() * 10))
|
||||||
|
|
||||||
const input1 = {
|
const input1 = {
|
||||||
type: 'SNIPPET_NOTE',
|
type: 'SNIPPET_NOTE',
|
||||||
description: faker.lorem.lines(),
|
description: faker.lorem.lines(),
|
||||||
snippets: [{
|
snippets: [{
|
||||||
name: faker.system.fileName(),
|
name: faker.system.fileName(),
|
||||||
mode: 'text',
|
mode: 'text',
|
||||||
content: faker.lorem.lines()
|
content: faker.lorem.lines(),
|
||||||
|
linesHighlighted: randLinesHighlightedArray
|
||||||
}],
|
}],
|
||||||
tags: faker.lorem.words().split(' '),
|
tags: faker.lorem.words().split(' '),
|
||||||
folder: folderKey
|
folder: folderKey
|
||||||
@@ -42,7 +45,8 @@ test.serial('Create a note', (t) => {
|
|||||||
type: 'MARKDOWN_NOTE',
|
type: 'MARKDOWN_NOTE',
|
||||||
content: faker.lorem.lines(),
|
content: faker.lorem.lines(),
|
||||||
tags: faker.lorem.words().split(' '),
|
tags: faker.lorem.words().split(' '),
|
||||||
folder: folderKey
|
folder: folderKey,
|
||||||
|
linesHighlighted: randLinesHighlightedArray
|
||||||
}
|
}
|
||||||
input2.title = input2.content.split('\n').shift()
|
input2.title = input2.content.split('\n').shift()
|
||||||
|
|
||||||
@@ -59,6 +63,7 @@ test.serial('Create a note', (t) => {
|
|||||||
|
|
||||||
t.is(storageKey, data1.storage)
|
t.is(storageKey, data1.storage)
|
||||||
const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
|
const jsonData1 = CSON.readFileSync(path.join(storagePath, 'notes', data1.key + '.cson'))
|
||||||
|
|
||||||
t.is(input1.title, data1.title)
|
t.is(input1.title, data1.title)
|
||||||
t.is(input1.title, jsonData1.title)
|
t.is(input1.title, jsonData1.title)
|
||||||
t.is(input1.description, data1.description)
|
t.is(input1.description, data1.description)
|
||||||
@@ -71,6 +76,8 @@ test.serial('Create a note', (t) => {
|
|||||||
t.is(input1.snippets[0].content, jsonData1.snippets[0].content)
|
t.is(input1.snippets[0].content, jsonData1.snippets[0].content)
|
||||||
t.is(input1.snippets[0].name, data1.snippets[0].name)
|
t.is(input1.snippets[0].name, data1.snippets[0].name)
|
||||||
t.is(input1.snippets[0].name, jsonData1.snippets[0].name)
|
t.is(input1.snippets[0].name, jsonData1.snippets[0].name)
|
||||||
|
t.deepEqual(input1.snippets[0].linesHighlighted, data1.snippets[0].linesHighlighted)
|
||||||
|
t.deepEqual(input1.snippets[0].linesHighlighted, jsonData1.snippets[0].linesHighlighted)
|
||||||
|
|
||||||
t.is(storageKey, data2.storage)
|
t.is(storageKey, data2.storage)
|
||||||
const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
|
const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
|
||||||
@@ -80,6 +87,8 @@ test.serial('Create a note', (t) => {
|
|||||||
t.is(input2.content, jsonData2.content)
|
t.is(input2.content, jsonData2.content)
|
||||||
t.is(input2.tags.length, data2.tags.length)
|
t.is(input2.tags.length, data2.tags.length)
|
||||||
t.is(input2.tags.length, jsonData2.tags.length)
|
t.is(input2.tags.length, jsonData2.tags.length)
|
||||||
|
t.deepEqual(input2.linesHighlighted, data2.linesHighlighted)
|
||||||
|
t.deepEqual(input2.linesHighlighted, jsonData2.linesHighlighted)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ test.serial('Create a snippet', (t) => {
|
|||||||
t.is(snippet.name, data.name)
|
t.is(snippet.name, data.name)
|
||||||
t.deepEqual(snippet.prefix, data.prefix)
|
t.deepEqual(snippet.prefix, data.prefix)
|
||||||
t.is(snippet.content, data.content)
|
t.is(snippet.content, data.content)
|
||||||
|
t.deepEqual(snippet.linesHighlighted, data.linesHighlighted)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
@@ -26,13 +26,17 @@ test.serial('Update a note', (t) => {
|
|||||||
const storageKey = t.context.storage.cache.key
|
const storageKey = t.context.storage.cache.key
|
||||||
const folderKey = t.context.storage.json.folders[0].key
|
const folderKey = t.context.storage.json.folders[0].key
|
||||||
|
|
||||||
|
const randLinesHighlightedArray = new Array(10).fill().map(() => Math.round(Math.random() * 10))
|
||||||
|
const randLinesHighlightedArray2 = new Array(15).fill().map(() => Math.round(Math.random() * 15))
|
||||||
|
|
||||||
const input1 = {
|
const input1 = {
|
||||||
type: 'SNIPPET_NOTE',
|
type: 'SNIPPET_NOTE',
|
||||||
description: faker.lorem.lines(),
|
description: faker.lorem.lines(),
|
||||||
snippets: [{
|
snippets: [{
|
||||||
name: faker.system.fileName(),
|
name: faker.system.fileName(),
|
||||||
mode: 'text',
|
mode: 'text',
|
||||||
content: faker.lorem.lines()
|
content: faker.lorem.lines(),
|
||||||
|
linesHighlighted: randLinesHighlightedArray
|
||||||
}],
|
}],
|
||||||
tags: faker.lorem.words().split(' '),
|
tags: faker.lorem.words().split(' '),
|
||||||
folder: folderKey
|
folder: folderKey
|
||||||
@@ -43,7 +47,8 @@ test.serial('Update a note', (t) => {
|
|||||||
type: 'MARKDOWN_NOTE',
|
type: 'MARKDOWN_NOTE',
|
||||||
content: faker.lorem.lines(),
|
content: faker.lorem.lines(),
|
||||||
tags: faker.lorem.words().split(' '),
|
tags: faker.lorem.words().split(' '),
|
||||||
folder: folderKey
|
folder: folderKey,
|
||||||
|
linesHighlighted: randLinesHighlightedArray
|
||||||
}
|
}
|
||||||
input2.title = input2.content.split('\n').shift()
|
input2.title = input2.content.split('\n').shift()
|
||||||
|
|
||||||
@@ -53,7 +58,8 @@ test.serial('Update a note', (t) => {
|
|||||||
snippets: [{
|
snippets: [{
|
||||||
name: faker.system.fileName(),
|
name: faker.system.fileName(),
|
||||||
mode: 'text',
|
mode: 'text',
|
||||||
content: faker.lorem.lines()
|
content: faker.lorem.lines(),
|
||||||
|
linesHighlighted: randLinesHighlightedArray2
|
||||||
}],
|
}],
|
||||||
tags: faker.lorem.words().split(' ')
|
tags: faker.lorem.words().split(' ')
|
||||||
}
|
}
|
||||||
@@ -62,7 +68,8 @@ test.serial('Update a note', (t) => {
|
|||||||
const input4 = {
|
const input4 = {
|
||||||
type: 'MARKDOWN_NOTE',
|
type: 'MARKDOWN_NOTE',
|
||||||
content: faker.lorem.lines(),
|
content: faker.lorem.lines(),
|
||||||
tags: faker.lorem.words().split(' ')
|
tags: faker.lorem.words().split(' '),
|
||||||
|
linesHighlighted: randLinesHighlightedArray2
|
||||||
}
|
}
|
||||||
input4.title = input4.content.split('\n').shift()
|
input4.title = input4.content.split('\n').shift()
|
||||||
|
|
||||||
@@ -99,6 +106,8 @@ test.serial('Update a note', (t) => {
|
|||||||
t.is(input3.snippets[0].content, jsonData1.snippets[0].content)
|
t.is(input3.snippets[0].content, jsonData1.snippets[0].content)
|
||||||
t.is(input3.snippets[0].name, data1.snippets[0].name)
|
t.is(input3.snippets[0].name, data1.snippets[0].name)
|
||||||
t.is(input3.snippets[0].name, jsonData1.snippets[0].name)
|
t.is(input3.snippets[0].name, jsonData1.snippets[0].name)
|
||||||
|
t.deepEqual(input3.snippets[0].linesHighlighted, data1.snippets[0].linesHighlighted)
|
||||||
|
t.deepEqual(input3.snippets[0].linesHighlighted, jsonData1.snippets[0].linesHighlighted)
|
||||||
|
|
||||||
const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
|
const jsonData2 = CSON.readFileSync(path.join(storagePath, 'notes', data2.key + '.cson'))
|
||||||
t.is(input4.title, data2.title)
|
t.is(input4.title, data2.title)
|
||||||
@@ -107,6 +116,8 @@ test.serial('Update a note', (t) => {
|
|||||||
t.is(input4.content, jsonData2.content)
|
t.is(input4.content, jsonData2.content)
|
||||||
t.is(input4.tags.length, data2.tags.length)
|
t.is(input4.tags.length, data2.tags.length)
|
||||||
t.is(input4.tags.length, jsonData2.tags.length)
|
t.is(input4.tags.length, jsonData2.tags.length)
|
||||||
|
t.deepEqual(input4.linesHighlighted, data2.linesHighlighted)
|
||||||
|
t.deepEqual(input4.linesHighlighted, jsonData2.linesHighlighted)
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
155
yarn.lock
155
yarn.lock
@@ -61,7 +61,6 @@
|
|||||||
"@enyaxu/markdown-it-anchor@^5.0.2":
|
"@enyaxu/markdown-it-anchor@^5.0.2":
|
||||||
version "5.0.2"
|
version "5.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/@enyaxu/markdown-it-anchor/-/markdown-it-anchor-5.0.2.tgz#d173f7b60b492aabc17dfba864c4d071f5595f72"
|
resolved "https://registry.yarnpkg.com/@enyaxu/markdown-it-anchor/-/markdown-it-anchor-5.0.2.tgz#d173f7b60b492aabc17dfba864c4d071f5595f72"
|
||||||
integrity sha512-HBQ+by3IFHh2i5nw8fzn9qrdA+6uwzre68EzHpBX/WrwgnKrfvckPzdi7MphKp2C617edfpeibucslHDNPYkvQ==
|
|
||||||
|
|
||||||
"@ladjs/time-require@^0.1.4":
|
"@ladjs/time-require@^0.1.4":
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
@@ -1690,6 +1689,10 @@ ci-info@^1.0.0:
|
|||||||
version "1.1.3"
|
version "1.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2"
|
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.1.3.tgz#710193264bb05c77b8c90d02f5aaf22216a667b2"
|
||||||
|
|
||||||
|
ci-info@^1.5.0:
|
||||||
|
version "1.6.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-1.6.0.tgz#2ca20dbb9ceb32d4524a683303313f0304b1e497"
|
||||||
|
|
||||||
circular-json@^0.3.1:
|
circular-json@^0.3.1:
|
||||||
version "0.3.3"
|
version "0.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
|
resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.3.3.tgz#815c99ea84f6809529d2f45791bdf82711352d66"
|
||||||
@@ -2107,6 +2110,14 @@ core-util-is@1.0.2, core-util-is@~1.0.0:
|
|||||||
version "1.0.2"
|
version "1.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7"
|
||||||
|
|
||||||
|
cosmiconfig@^5.0.6:
|
||||||
|
version "5.0.6"
|
||||||
|
resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.0.6.tgz#dca6cf680a0bd03589aff684700858c81abeeb39"
|
||||||
|
dependencies:
|
||||||
|
is-directory "^0.3.1"
|
||||||
|
js-yaml "^3.9.0"
|
||||||
|
parse-json "^4.0.0"
|
||||||
|
|
||||||
create-error-class@^3.0.0, create-error-class@^3.0.1:
|
create-error-class@^3.0.0, create-error-class@^3.0.1:
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
|
resolved "https://registry.yarnpkg.com/create-error-class/-/create-error-class-3.0.2.tgz#06be7abef947a3f14a30fd610671d401bca8b7b6"
|
||||||
@@ -2749,6 +2760,10 @@ doctrine@^2.0.0, doctrine@^2.0.2:
|
|||||||
dependencies:
|
dependencies:
|
||||||
esutils "^2.0.2"
|
esutils "^2.0.2"
|
||||||
|
|
||||||
|
dom-helpers@^3.3.1:
|
||||||
|
version "3.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-3.3.1.tgz#fc1a4e15ffdf60ddde03a480a9c0fece821dd4a6"
|
||||||
|
|
||||||
dom-serializer@0:
|
dom-serializer@0:
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
|
resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-0.1.0.tgz#073c697546ce0780ce23be4a28e293e40bc30c82"
|
||||||
@@ -3364,6 +3379,18 @@ execa@^0.7.0:
|
|||||||
signal-exit "^3.0.0"
|
signal-exit "^3.0.0"
|
||||||
strip-eof "^1.0.0"
|
strip-eof "^1.0.0"
|
||||||
|
|
||||||
|
execa@^0.9.0:
|
||||||
|
version "0.9.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/execa/-/execa-0.9.0.tgz#adb7ce62cf985071f60580deb4a88b9e34712d01"
|
||||||
|
dependencies:
|
||||||
|
cross-spawn "^5.0.1"
|
||||||
|
get-stream "^3.0.0"
|
||||||
|
is-stream "^1.1.0"
|
||||||
|
npm-run-path "^2.0.0"
|
||||||
|
p-finally "^1.0.0"
|
||||||
|
signal-exit "^3.0.0"
|
||||||
|
strip-eof "^1.0.0"
|
||||||
|
|
||||||
exit-hook@^1.0.0:
|
exit-hook@^1.0.0:
|
||||||
version "1.1.1"
|
version "1.1.1"
|
||||||
resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
|
resolved "https://registry.yarnpkg.com/exit-hook/-/exit-hook-1.1.1.tgz#f05ca233b48c05d54fff07765df8507e95c02ff8"
|
||||||
@@ -3670,6 +3697,12 @@ find-up@^2.0.0, find-up@^2.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
locate-path "^2.0.0"
|
locate-path "^2.0.0"
|
||||||
|
|
||||||
|
find-up@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73"
|
||||||
|
dependencies:
|
||||||
|
locate-path "^3.0.0"
|
||||||
|
|
||||||
findup-sync@~0.1.2:
|
findup-sync@~0.1.2:
|
||||||
version "0.1.3"
|
version "0.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.1.3.tgz#7f3e7a97b82392c653bf06589bd85190e93c3683"
|
resolved "https://registry.yarnpkg.com/findup-sync/-/findup-sync-0.1.3.tgz#7f3e7a97b82392c653bf06589bd85190e93c3683"
|
||||||
@@ -3915,6 +3948,10 @@ get-stdin@^5.0.1:
|
|||||||
version "5.0.1"
|
version "5.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
|
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-5.0.1.tgz#122e161591e21ff4c52530305693f20e6393a398"
|
||||||
|
|
||||||
|
get-stdin@^6.0.0:
|
||||||
|
version "6.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-6.0.0.tgz#9e09bf712b360ab9225e812048f71fde9c89657b"
|
||||||
|
|
||||||
get-stream@^3.0.0:
|
get-stream@^3.0.0:
|
||||||
version "3.0.0"
|
version "3.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
|
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-3.0.0.tgz#8e943d1358dc37555054ecbe2edb05aa174ede14"
|
||||||
@@ -4452,6 +4489,21 @@ humanize-plus@^1.8.1:
|
|||||||
version "1.8.2"
|
version "1.8.2"
|
||||||
resolved "https://registry.yarnpkg.com/humanize-plus/-/humanize-plus-1.8.2.tgz#a65b34459ad6367adbb3707a82a3c9f916167030"
|
resolved "https://registry.yarnpkg.com/humanize-plus/-/humanize-plus-1.8.2.tgz#a65b34459ad6367adbb3707a82a3c9f916167030"
|
||||||
|
|
||||||
|
husky@^1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/husky/-/husky-1.1.0.tgz#7271e85f5d98b54349788839b720c9a60cd95dba"
|
||||||
|
dependencies:
|
||||||
|
cosmiconfig "^5.0.6"
|
||||||
|
execa "^0.9.0"
|
||||||
|
find-up "^3.0.0"
|
||||||
|
get-stdin "^6.0.0"
|
||||||
|
is-ci "^1.2.1"
|
||||||
|
pkg-dir "^3.0.0"
|
||||||
|
please-upgrade-node "^3.1.1"
|
||||||
|
read-pkg "^4.0.1"
|
||||||
|
run-node "^1.0.0"
|
||||||
|
slash "^2.0.0"
|
||||||
|
|
||||||
i18n-2@^0.7.2:
|
i18n-2@^0.7.2:
|
||||||
version "0.7.2"
|
version "0.7.2"
|
||||||
resolved "https://registry.yarnpkg.com/i18n-2/-/i18n-2-0.7.2.tgz#7efb1a7adc67869adea0688951577464aa793aaf"
|
resolved "https://registry.yarnpkg.com/i18n-2/-/i18n-2-0.7.2.tgz#7efb1a7adc67869adea0688951577464aa793aaf"
|
||||||
@@ -4662,6 +4714,12 @@ is-ci@^1.0.10, is-ci@^1.0.7:
|
|||||||
dependencies:
|
dependencies:
|
||||||
ci-info "^1.0.0"
|
ci-info "^1.0.0"
|
||||||
|
|
||||||
|
is-ci@^1.2.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-1.2.1.tgz#e3779c8ee17fccf428488f6e281187f2e632841c"
|
||||||
|
dependencies:
|
||||||
|
ci-info "^1.5.0"
|
||||||
|
|
||||||
is-data-descriptor@^0.1.4:
|
is-data-descriptor@^0.1.4:
|
||||||
version "0.1.4"
|
version "0.1.4"
|
||||||
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
|
resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56"
|
||||||
@@ -4694,6 +4752,10 @@ is-descriptor@^1.0.0, is-descriptor@^1.0.2:
|
|||||||
is-data-descriptor "^1.0.0"
|
is-data-descriptor "^1.0.0"
|
||||||
kind-of "^6.0.2"
|
kind-of "^6.0.2"
|
||||||
|
|
||||||
|
is-directory@^0.3.1:
|
||||||
|
version "0.3.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1"
|
||||||
|
|
||||||
is-dotfile@^1.0.0:
|
is-dotfile@^1.0.0:
|
||||||
version "1.0.3"
|
version "1.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
|
resolved "https://registry.yarnpkg.com/is-dotfile/-/is-dotfile-1.0.3.tgz#a6a2f32ffd2dfb04f5ca25ecd0f6b83cf798a1e1"
|
||||||
@@ -5324,6 +5386,10 @@ js-tokens@^3.0.0, js-tokens@^3.0.2:
|
|||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-3.0.2.tgz#9866df395102130e38f7f996bceb65443209c25b"
|
||||||
|
|
||||||
|
"js-tokens@^3.0.0 || ^4.0.0":
|
||||||
|
version "4.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
|
||||||
|
|
||||||
js-yaml@^3.10.0, js-yaml@^3.5.1, js-yaml@^3.7.0:
|
js-yaml@^3.10.0, js-yaml@^3.5.1, js-yaml@^3.7.0:
|
||||||
version "3.11.0"
|
version "3.11.0"
|
||||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef"
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.11.0.tgz#597c1a8bd57152f26d622ce4117851a51f5ebaef"
|
||||||
@@ -5331,7 +5397,7 @@ js-yaml@^3.10.0, js-yaml@^3.5.1, js-yaml@^3.7.0:
|
|||||||
argparse "^1.0.7"
|
argparse "^1.0.7"
|
||||||
esprima "^4.0.0"
|
esprima "^4.0.0"
|
||||||
|
|
||||||
js-yaml@^3.12.0, js-yaml@^3.8.1:
|
js-yaml@^3.12.0, js-yaml@^3.8.1, js-yaml@^3.9.0:
|
||||||
version "3.12.0"
|
version "3.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
|
resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.12.0.tgz#eaed656ec8344f10f527c6bfa1b6e2244de167d1"
|
||||||
dependencies:
|
dependencies:
|
||||||
@@ -5688,6 +5754,13 @@ locate-path@^2.0.0:
|
|||||||
p-locate "^2.0.0"
|
p-locate "^2.0.0"
|
||||||
path-exists "^3.0.0"
|
path-exists "^3.0.0"
|
||||||
|
|
||||||
|
locate-path@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e"
|
||||||
|
dependencies:
|
||||||
|
p-locate "^3.0.0"
|
||||||
|
path-exists "^3.0.0"
|
||||||
|
|
||||||
lodash-es@^4.2.1:
|
lodash-es@^4.2.1:
|
||||||
version "4.17.10"
|
version "4.17.10"
|
||||||
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.10.tgz#62cd7104cdf5dd87f235a837f0ede0e8e5117e05"
|
resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.10.tgz#62cd7104cdf5dd87f235a837f0ede0e8e5117e05"
|
||||||
@@ -5805,6 +5878,12 @@ loose-envify@^1.0.0, loose-envify@^1.1.0, loose-envify@^1.2.0, loose-envify@^1.3
|
|||||||
dependencies:
|
dependencies:
|
||||||
js-tokens "^3.0.0"
|
js-tokens "^3.0.0"
|
||||||
|
|
||||||
|
loose-envify@^1.4.0:
|
||||||
|
version "1.4.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf"
|
||||||
|
dependencies:
|
||||||
|
js-tokens "^3.0.0 || ^4.0.0"
|
||||||
|
|
||||||
loud-rejection@^1.0.0, loud-rejection@^1.2.0:
|
loud-rejection@^1.0.0, loud-rejection@^1.2.0:
|
||||||
version "1.6.0"
|
version "1.6.0"
|
||||||
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
|
resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
|
||||||
@@ -6681,16 +6760,32 @@ p-limit@^1.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
p-try "^1.0.0"
|
p-try "^1.0.0"
|
||||||
|
|
||||||
|
p-limit@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.0.0.tgz#e624ed54ee8c460a778b3c9f3670496ff8a57aec"
|
||||||
|
dependencies:
|
||||||
|
p-try "^2.0.0"
|
||||||
|
|
||||||
p-locate@^2.0.0:
|
p-locate@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
|
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43"
|
||||||
dependencies:
|
dependencies:
|
||||||
p-limit "^1.1.0"
|
p-limit "^1.1.0"
|
||||||
|
|
||||||
|
p-locate@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4"
|
||||||
|
dependencies:
|
||||||
|
p-limit "^2.0.0"
|
||||||
|
|
||||||
p-try@^1.0.0:
|
p-try@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
|
resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3"
|
||||||
|
|
||||||
|
p-try@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.0.0.tgz#85080bb87c64688fa47996fe8f7dfbe8211760b1"
|
||||||
|
|
||||||
package-hash@^1.2.0:
|
package-hash@^1.2.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-1.2.0.tgz#003e56cd57b736a6ed6114cc2b81542672770e44"
|
resolved "https://registry.yarnpkg.com/package-hash/-/package-hash-1.2.0.tgz#003e56cd57b736a6ed6114cc2b81542672770e44"
|
||||||
@@ -6886,12 +6981,24 @@ pkg-dir@^2.0.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
find-up "^2.1.0"
|
find-up "^2.1.0"
|
||||||
|
|
||||||
|
pkg-dir@^3.0.0:
|
||||||
|
version "3.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3"
|
||||||
|
dependencies:
|
||||||
|
find-up "^3.0.0"
|
||||||
|
|
||||||
pkg-up@^2.0.0:
|
pkg-up@^2.0.0:
|
||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f"
|
resolved "https://registry.yarnpkg.com/pkg-up/-/pkg-up-2.0.0.tgz#c819ac728059a461cab1c3889a2be3c49a004d7f"
|
||||||
dependencies:
|
dependencies:
|
||||||
find-up "^2.1.0"
|
find-up "^2.1.0"
|
||||||
|
|
||||||
|
please-upgrade-node@^3.1.1:
|
||||||
|
version "3.1.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.1.1.tgz#ed320051dfcc5024fae696712c8288993595e8ac"
|
||||||
|
dependencies:
|
||||||
|
semver-compare "^1.0.0"
|
||||||
|
|
||||||
plist@^2.0.0, plist@^2.1.0:
|
plist@^2.0.0, plist@^2.1.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/plist/-/plist-2.1.0.tgz#57ccdb7a0821df21831217a3cad54e3e146a1025"
|
resolved "https://registry.yarnpkg.com/plist/-/plist-2.1.0.tgz#57ccdb7a0821df21831217a3cad54e3e146a1025"
|
||||||
@@ -7241,6 +7348,13 @@ prop-types@^15.5.10, prop-types@^15.5.4, prop-types@^15.5.7, prop-types@^15.5.8,
|
|||||||
loose-envify "^1.3.1"
|
loose-envify "^1.3.1"
|
||||||
object-assign "^4.1.1"
|
object-assign "^4.1.1"
|
||||||
|
|
||||||
|
prop-types@^15.6.2:
|
||||||
|
version "15.6.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.6.2.tgz#05d5ca77b4453e985d60fc7ff8c859094a497102"
|
||||||
|
dependencies:
|
||||||
|
loose-envify "^1.3.1"
|
||||||
|
object-assign "^4.1.1"
|
||||||
|
|
||||||
proxy-addr@~2.0.3:
|
proxy-addr@~2.0.3:
|
||||||
version "2.0.3"
|
version "2.0.3"
|
||||||
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341"
|
resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.3.tgz#355f262505a621646b3130a728eb647e22055341"
|
||||||
@@ -7420,6 +7534,10 @@ react-dom@^15.0.2:
|
|||||||
object-assign "^4.1.0"
|
object-assign "^4.1.0"
|
||||||
prop-types "^15.5.10"
|
prop-types "^15.5.10"
|
||||||
|
|
||||||
|
react-image-carousel@^2.0.18:
|
||||||
|
version "2.0.18"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-image-carousel/-/react-image-carousel-2.0.18.tgz#5868ea09bd9cca09c4467d3d02695cd4e7792f28"
|
||||||
|
|
||||||
react-input-autosize@^1.1.0:
|
react-input-autosize@^1.1.0:
|
||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-1.2.0.tgz#87241071159f742123897691da6796ec33b57d05"
|
resolved "https://registry.yarnpkg.com/react-input-autosize/-/react-input-autosize-1.2.0.tgz#87241071159f742123897691da6796ec33b57d05"
|
||||||
@@ -7427,6 +7545,10 @@ react-input-autosize@^1.1.0:
|
|||||||
create-react-class "^15.5.2"
|
create-react-class "^15.5.2"
|
||||||
prop-types "^15.5.8"
|
prop-types "^15.5.8"
|
||||||
|
|
||||||
|
react-lifecycles-compat@^3.0.4:
|
||||||
|
version "3.0.4"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
|
||||||
|
|
||||||
react-proxy@^1.1.7:
|
react-proxy@^1.1.7:
|
||||||
version "1.1.8"
|
version "1.1.8"
|
||||||
resolved "https://registry.yarnpkg.com/react-proxy/-/react-proxy-1.1.8.tgz#9dbfd9d927528c3aa9f444e4558c37830ab8c26a"
|
resolved "https://registry.yarnpkg.com/react-proxy/-/react-proxy-1.1.8.tgz#9dbfd9d927528c3aa9f444e4558c37830ab8c26a"
|
||||||
@@ -7492,6 +7614,15 @@ react-transform-hmr@^1.0.3:
|
|||||||
global "^4.3.0"
|
global "^4.3.0"
|
||||||
react-proxy "^1.1.7"
|
react-proxy "^1.1.7"
|
||||||
|
|
||||||
|
react-transition-group@^2.5.0:
|
||||||
|
version "2.5.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-2.5.0.tgz#70bca0e3546102c4dc5cf3f5f57f73447cce6874"
|
||||||
|
dependencies:
|
||||||
|
dom-helpers "^3.3.1"
|
||||||
|
loose-envify "^1.4.0"
|
||||||
|
prop-types "^15.6.2"
|
||||||
|
react-lifecycles-compat "^3.0.4"
|
||||||
|
|
||||||
react@^15.5.4:
|
react@^15.5.4:
|
||||||
version "15.6.2"
|
version "15.6.2"
|
||||||
resolved "https://registry.yarnpkg.com/react/-/react-15.6.2.tgz#dba0434ab439cfe82f108f0f511663908179aa72"
|
resolved "https://registry.yarnpkg.com/react/-/react-15.6.2.tgz#dba0434ab439cfe82f108f0f511663908179aa72"
|
||||||
@@ -7545,6 +7676,14 @@ read-pkg@^2.0.0:
|
|||||||
normalize-package-data "^2.3.2"
|
normalize-package-data "^2.3.2"
|
||||||
path-type "^2.0.0"
|
path-type "^2.0.0"
|
||||||
|
|
||||||
|
read-pkg@^4.0.1:
|
||||||
|
version "4.0.1"
|
||||||
|
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-4.0.1.tgz#963625378f3e1c4d48c85872b5a6ec7d5d093237"
|
||||||
|
dependencies:
|
||||||
|
normalize-package-data "^2.3.2"
|
||||||
|
parse-json "^4.0.0"
|
||||||
|
pify "^3.0.0"
|
||||||
|
|
||||||
readable-stream@^1.1.8, readable-stream@~1.1.9:
|
readable-stream@^1.1.8, readable-stream@~1.1.9:
|
||||||
version "1.1.14"
|
version "1.1.14"
|
||||||
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
|
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
|
||||||
@@ -7895,6 +8034,10 @@ run-async@^0.1.0:
|
|||||||
dependencies:
|
dependencies:
|
||||||
once "^1.3.0"
|
once "^1.3.0"
|
||||||
|
|
||||||
|
run-node@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/run-node/-/run-node-1.0.0.tgz#46b50b946a2aa2d4947ae1d886e9856fd9cabe5e"
|
||||||
|
|
||||||
run-parallel@^1.1.2:
|
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"
|
||||||
@@ -7994,6 +8137,10 @@ section-iterator@^2.0.0:
|
|||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/section-iterator/-/section-iterator-2.0.0.tgz#bf444d7afeeb94ad43c39ad2fb26151627ccba2a"
|
resolved "https://registry.yarnpkg.com/section-iterator/-/section-iterator-2.0.0.tgz#bf444d7afeeb94ad43c39ad2fb26151627ccba2a"
|
||||||
|
|
||||||
|
semver-compare@^1.0.0:
|
||||||
|
version "1.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc"
|
||||||
|
|
||||||
semver-diff@^2.0.0:
|
semver-diff@^2.0.0:
|
||||||
version "2.1.0"
|
version "2.1.0"
|
||||||
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
|
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
|
||||||
@@ -8153,6 +8300,10 @@ slash@^1.0.0:
|
|||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
|
resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55"
|
||||||
|
|
||||||
|
slash@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44"
|
||||||
|
|
||||||
slice-ansi@0.0.4:
|
slice-ansi@0.0.4:
|
||||||
version "0.0.4"
|
version "0.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
|
resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-0.0.4.tgz#edbf8903f66f7ce2f8eafd6ceed65e264c831b35"
|
||||||
|
|||||||
Reference in New Issue
Block a user