mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-14 18:26:26 +00:00
Compare commits
81 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6cad2ab4df | ||
|
|
856d52891c | ||
|
|
8de3b3bd8d | ||
|
|
0414483be2 | ||
|
|
22939aa472 | ||
|
|
0cb7c44985 | ||
|
|
b18a09e5eb | ||
|
|
ef3649b1d6 | ||
|
|
ac70a0d94d | ||
|
|
3b91f9b88b | ||
|
|
c37b780ca4 | ||
|
|
20061d2c65 | ||
|
|
f18fa77c1c | ||
|
|
a4c6869d4d | ||
|
|
f9a0070c82 | ||
|
|
5cc52f91cb | ||
|
|
a46b9fb2be | ||
|
|
933e38eca9 | ||
|
|
e182390480 | ||
|
|
563fdcba94 | ||
|
|
bc640834cd | ||
|
|
0e9e7d644a | ||
|
|
1d9b3ac2b5 | ||
|
|
aebed4a644 | ||
|
|
7bfb094a40 | ||
|
|
f90a44c1d0 | ||
|
|
dfcf6d2729 | ||
|
|
806a5daa86 | ||
|
|
4a3602099a | ||
|
|
c69be54655 | ||
|
|
680eaa1d4a | ||
|
|
9cc7b8bcc6 | ||
|
|
55d86d853a | ||
|
|
7d9f309e04 | ||
|
|
c2f0147cff | ||
|
|
05488e66ae | ||
|
|
09eac89086 | ||
|
|
866a0e7534 | ||
|
|
3c8337cf54 | ||
|
|
883b4c4c26 | ||
|
|
6bc42c564d | ||
|
|
d2b2e76a6a | ||
|
|
9d9109e9e5 | ||
|
|
18efb89b9a | ||
|
|
cefe883025 | ||
|
|
0ffa0b96d3 | ||
|
|
0429acfa1b | ||
|
|
827e3c1829 | ||
|
|
aa756ef194 | ||
|
|
d8aad65b24 | ||
|
|
1038e86196 | ||
|
|
47845fd4e3 | ||
|
|
294c3f10ab | ||
|
|
f6afc756dc | ||
|
|
64407e5ca6 | ||
|
|
0a42b0f61f | ||
|
|
ddd339851b | ||
|
|
82db986bd7 | ||
|
|
7bacd6f8f0 | ||
|
|
f0941f47dd | ||
|
|
c9d05b1117 | ||
|
|
7ee12752ec | ||
|
|
b44772441d | ||
|
|
72e3784fa5 | ||
|
|
8a6c86bf65 | ||
|
|
cc52cf60dc | ||
|
|
0095735841 | ||
|
|
95c10a1de7 | ||
|
|
8f4c92e251 | ||
|
|
58354061d8 | ||
|
|
7414d52dc2 | ||
|
|
c42b5c8806 | ||
|
|
5c60da0f8f | ||
|
|
0ae1263d9d | ||
|
|
31f1ebe801 | ||
|
|
c6a9c9c57d | ||
|
|
707356bffe | ||
|
|
1516807ed5 | ||
|
|
9893fd9ae5 | ||
|
|
d6c28da3a8 | ||
|
|
52f694a714 |
@@ -5,16 +5,18 @@ import CodeMirror from 'codemirror'
|
|||||||
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 } from '@susisu/mte-kernel'
|
||||||
|
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'
|
||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
import consts from 'browser/lib/consts'
|
import consts from 'browser/lib/consts'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
const { ipcRenderer } = require('electron')
|
const { ipcRenderer } = require('electron')
|
||||||
|
import normalizeEditorFontFamily from 'browser/lib/normalizeEditorFontFamily'
|
||||||
|
|
||||||
CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js'
|
CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js'
|
||||||
|
|
||||||
const defaultEditorFontFamily = ['Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'monospace']
|
|
||||||
const buildCMRulers = (rulers, enableRulers) =>
|
const buildCMRulers = (rulers, enableRulers) =>
|
||||||
enableRulers ? rulers.map(ruler => ({column: ruler})) : []
|
enableRulers ? rulers.map(ruler => ({column: ruler})) : []
|
||||||
|
|
||||||
@@ -48,6 +50,8 @@ export default class CodeEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
this.searchHandler = (e, msg) => this.handleSearch(msg)
|
this.searchHandler = (e, msg) => this.handleSearch(msg)
|
||||||
this.searchState = null
|
this.searchState = null
|
||||||
|
|
||||||
|
this.formatTable = () => this.handleFormatTable()
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSearch (msg) {
|
handleSearch (msg) {
|
||||||
@@ -81,6 +85,10 @@ export default class CodeEditor extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleFormatTable () {
|
||||||
|
this.tableEditor.formatAll(options({textWidthOptions: {}}))
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
const { rulers, enableRulers } = this.props
|
const { rulers, enableRulers } = this.props
|
||||||
const expandSnippet = this.expandSnippet.bind(this)
|
const expandSnippet = this.expandSnippet.bind(this)
|
||||||
@@ -113,7 +121,12 @@ export default class CodeEditor extends React.Component {
|
|||||||
dragDrop: false,
|
dragDrop: false,
|
||||||
foldGutter: true,
|
foldGutter: true,
|
||||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
||||||
autoCloseBrackets: true,
|
autoCloseBrackets: {
|
||||||
|
pairs: '()[]{}\'\'""$$**``',
|
||||||
|
triples: '```"""\'\'\'',
|
||||||
|
explode: '[]{}``$$',
|
||||||
|
override: true
|
||||||
|
},
|
||||||
extraKeys: {
|
extraKeys: {
|
||||||
Tab: function (cm) {
|
Tab: function (cm) {
|
||||||
const cursor = cm.getCursor()
|
const cursor = cm.getCursor()
|
||||||
@@ -182,6 +195,9 @@ export default class CodeEditor extends React.Component {
|
|||||||
CodeMirror.Vim.defineEx('wq', 'wq', this.quitEditor)
|
CodeMirror.Vim.defineEx('wq', 'wq', this.quitEditor)
|
||||||
CodeMirror.Vim.defineEx('qw', 'qw', this.quitEditor)
|
CodeMirror.Vim.defineEx('qw', 'qw', this.quitEditor)
|
||||||
CodeMirror.Vim.map('ZZ', ':q', 'normal')
|
CodeMirror.Vim.map('ZZ', ':q', 'normal')
|
||||||
|
|
||||||
|
this.tableEditor = new TableEditor(new TextEditorInterface(this.editor))
|
||||||
|
eventEmitter.on('code:format-table', this.formatTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
expandSnippet (line, cursor, cm, snippets) {
|
expandSnippet (line, cursor, cm, snippets) {
|
||||||
@@ -264,6 +280,8 @@ export default class CodeEditor extends React.Component {
|
|||||||
this.editor.off('scroll', this.scrollHandler)
|
this.editor.off('scroll', this.scrollHandler)
|
||||||
const editorTheme = document.getElementById('editorTheme')
|
const editorTheme = document.getElementById('editorTheme')
|
||||||
editorTheme.removeEventListener('load', this.loadStyleHandler)
|
editorTheme.removeEventListener('load', this.loadStyleHandler)
|
||||||
|
|
||||||
|
eventEmitter.off('code:format-table', this.formatTable)
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate (prevProps, prevState) {
|
componentDidUpdate (prevProps, prevState) {
|
||||||
@@ -495,10 +513,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
const {className, fontSize} = this.props
|
const {className, fontSize} = this.props
|
||||||
let fontFamily = this.props.fontFamily
|
const fontFamily = normalizeEditorFontFamily(this.props.fontFamily)
|
||||||
fontFamily = _.isString(fontFamily) && fontFamily.length > 0
|
|
||||||
? [fontFamily].concat(defaultEditorFontFamily)
|
|
||||||
: defaultEditorFontFamily
|
|
||||||
const width = this.props.width
|
const width = this.props.width
|
||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
@@ -509,7 +524,7 @@ export default class CodeEditor extends React.Component {
|
|||||||
ref='root'
|
ref='root'
|
||||||
tabIndex='-1'
|
tabIndex='-1'
|
||||||
style={{
|
style={{
|
||||||
fontFamily: fontFamily.join(', '),
|
fontFamily,
|
||||||
fontSize: fontSize,
|
fontSize: fontSize,
|
||||||
width: width
|
width: width
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -7,7 +7,9 @@ import 'codemirror-mode-elixir'
|
|||||||
import consts from 'browser/lib/consts'
|
import consts from 'browser/lib/consts'
|
||||||
import Raphael from 'raphael'
|
import Raphael from 'raphael'
|
||||||
import flowchart from 'flowchart'
|
import flowchart from 'flowchart'
|
||||||
|
import mermaidRender from './render/MermaidRender'
|
||||||
import SequenceDiagram from 'js-sequence-diagrams'
|
import SequenceDiagram from 'js-sequence-diagrams'
|
||||||
|
import Chart from 'chart.js'
|
||||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||||
import htmlTextHelper from 'browser/lib/htmlTextHelper'
|
import htmlTextHelper from 'browser/lib/htmlTextHelper'
|
||||||
import convertModeName from 'browser/lib/convertModeName'
|
import convertModeName from 'browser/lib/convertModeName'
|
||||||
@@ -131,6 +133,25 @@ body p {
|
|||||||
`
|
`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const scrollBarStyle = `
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background-color: rgba(0, 0, 0, 0.15);
|
||||||
|
}
|
||||||
|
`
|
||||||
|
const scrollBarDarkStyle = `
|
||||||
|
::-webkit-scrollbar {
|
||||||
|
width: 12px;
|
||||||
|
}
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb {
|
||||||
|
background-color: rgba(0, 0, 0, 0.3);
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
const { shell } = require('electron')
|
const { shell } = require('electron')
|
||||||
const OSX = global.process.platform === 'darwin'
|
const OSX = global.process.platform === 'darwin'
|
||||||
|
|
||||||
@@ -219,7 +240,7 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
const {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, scrollPastEnd, theme, allowCustomCSS, customCSS} = this.getStyleParams()
|
const {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, scrollPastEnd, theme, allowCustomCSS, customCSS} = this.getStyleParams()
|
||||||
|
|
||||||
const inlineStyles = buildStyle(fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd, theme, allowCustomCSS, customCSS)
|
const inlineStyles = buildStyle(fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd, theme, allowCustomCSS, customCSS)
|
||||||
let body = this.markdown.render(escapeHtmlCharacters(noteContent))
|
let body = this.markdown.render(escapeHtmlCharacters(noteContent, { detectCodeBlock: true }))
|
||||||
|
|
||||||
const files = [this.GetCodeThemeLink(codeBlockTheme), ...CSS_FILES]
|
const files = [this.GetCodeThemeLink(codeBlockTheme), ...CSS_FILES]
|
||||||
const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent(noteContent, this.props.storagePath)
|
const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent(noteContent, this.props.storagePath)
|
||||||
@@ -295,6 +316,21 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getScrollBarStyle () {
|
||||||
|
const {
|
||||||
|
theme
|
||||||
|
} = this.props
|
||||||
|
|
||||||
|
switch (theme) {
|
||||||
|
case 'dark':
|
||||||
|
case 'solarized-dark':
|
||||||
|
case 'monokai':
|
||||||
|
return scrollBarDarkStyle
|
||||||
|
default:
|
||||||
|
return scrollBarStyle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
this.refs.root.setAttribute('sandbox', 'allow-scripts')
|
this.refs.root.setAttribute('sandbox', 'allow-scripts')
|
||||||
this.refs.root.contentWindow.document.body.addEventListener('contextmenu', this.contextMenuHandler)
|
this.refs.root.contentWindow.document.body.addEventListener('contextmenu', this.contextMenuHandler)
|
||||||
@@ -303,6 +339,9 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
<style id='style'></style>
|
<style id='style'></style>
|
||||||
<link rel="stylesheet" id="codeTheme">
|
<link rel="stylesheet" id="codeTheme">
|
||||||
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
|
||||||
|
<style>
|
||||||
|
${this.getScrollBarStyle()}
|
||||||
|
</style>
|
||||||
`
|
`
|
||||||
|
|
||||||
CSS_FILES.forEach((file) => {
|
CSS_FILES.forEach((file) => {
|
||||||
@@ -412,8 +451,8 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
value = value.replace(codeBlock, htmlTextHelper.encodeEntities(codeBlock))
|
value = value.replace(codeBlock, htmlTextHelper.encodeEntities(codeBlock))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
let renderedHTML = this.markdown.render(value)
|
const renderedHTML = this.markdown.render(value)
|
||||||
attachmentManagement.migrateAttachments(renderedHTML, storagePath, noteKey)
|
attachmentManagement.migrateAttachments(value, storagePath, noteKey)
|
||||||
this.refs.root.contentWindow.document.body.innerHTML = attachmentManagement.fixLocalURLS(renderedHTML, storagePath)
|
this.refs.root.contentWindow.document.body.innerHTML = attachmentManagement.fixLocalURLS(renderedHTML, storagePath)
|
||||||
|
|
||||||
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('input[type="checkbox"]'), (el) => {
|
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('input[type="checkbox"]'), (el) => {
|
||||||
@@ -496,6 +535,30 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
el.innerHTML = 'Sequence diagram parse error: ' + e.message
|
el.innerHTML = 'Sequence diagram parse error: ' + e.message
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
_.forEach(
|
||||||
|
this.refs.root.contentWindow.document.querySelectorAll('.chart'),
|
||||||
|
(el) => {
|
||||||
|
try {
|
||||||
|
const chartConfig = JSON.parse(el.innerHTML)
|
||||||
|
el.innerHTML = ''
|
||||||
|
var canvas = document.createElement('canvas')
|
||||||
|
el.appendChild(canvas)
|
||||||
|
/* eslint-disable no-new */
|
||||||
|
new Chart(canvas, chartConfig)
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
el.className = 'chart-error'
|
||||||
|
el.innerHTML = 'chartjs diagram parse error: ' + e.message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
_.forEach(
|
||||||
|
this.refs.root.contentWindow.document.querySelectorAll('.mermaid'),
|
||||||
|
(el) => {
|
||||||
|
mermaidRender(el, htmlTextHelper.decodeEntities(el.innerHTML))
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
focus () {
|
focus () {
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ body
|
|||||||
padding 5px
|
padding 5px
|
||||||
margin -5px
|
margin -5px
|
||||||
border-radius 5px
|
border-radius 5px
|
||||||
.flowchart-error, .sequence-error
|
.flowchart-error, .sequence-error .chart-error
|
||||||
background-color errorBackgroundColor
|
background-color errorBackgroundColor
|
||||||
color errorTextColor
|
color errorTextColor
|
||||||
padding 5px
|
padding 5px
|
||||||
@@ -213,7 +213,7 @@ pre
|
|||||||
margin 0 0 1em
|
margin 0 0 1em
|
||||||
display flex
|
display flex
|
||||||
line-height 1.4em
|
line-height 1.4em
|
||||||
&.flowchart, &.sequence
|
&.flowchart, &.sequence, &.chart
|
||||||
display flex
|
display flex
|
||||||
justify-content center
|
justify-content center
|
||||||
background-color white
|
background-color white
|
||||||
|
|||||||
28
browser/components/render/MermaidRender.js
Normal file
28
browser/components/render/MermaidRender.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
import mermaidAPI from 'mermaid'
|
||||||
|
|
||||||
|
function getRandomInt (min, max) {
|
||||||
|
return Math.floor(Math.random() * (max - min)) + min
|
||||||
|
}
|
||||||
|
|
||||||
|
function getId () {
|
||||||
|
var pool = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789'
|
||||||
|
var id = 'm-'
|
||||||
|
for (var i = 0; i < 7; i++) {
|
||||||
|
id += pool[getRandomInt(0, 16)]
|
||||||
|
}
|
||||||
|
return id
|
||||||
|
}
|
||||||
|
|
||||||
|
function render (element, content) {
|
||||||
|
try {
|
||||||
|
mermaidAPI.render(getId(), content, (svgGraph) => {
|
||||||
|
element.innerHTML = svgGraph
|
||||||
|
})
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
element.className = 'mermaid-error'
|
||||||
|
element.innerHTML = 'mermaid diagram parse error: ' + e.message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default render
|
||||||
53
browser/lib/TextEditorInterface.js
Normal file
53
browser/lib/TextEditorInterface.js
Normal file
@@ -0,0 +1,53 @@
|
|||||||
|
import { Point } from '@susisu/mte-kernel'
|
||||||
|
|
||||||
|
export default class TextEditorInterface {
|
||||||
|
constructor (editor) {
|
||||||
|
this.editor = editor
|
||||||
|
}
|
||||||
|
|
||||||
|
getCursorPosition () {
|
||||||
|
const pos = this.editor.getCursor()
|
||||||
|
return new Point(pos.line, pos.ch)
|
||||||
|
}
|
||||||
|
|
||||||
|
setCursorPosition (pos) {
|
||||||
|
this.editor.setCursor({line: pos.row, ch: pos.column})
|
||||||
|
}
|
||||||
|
|
||||||
|
setSelectionRange (range) {
|
||||||
|
this.editor.setSelection({
|
||||||
|
anchor: {line: range.start.row, ch: range.start.column},
|
||||||
|
head: {line: range.end.row, ch: range.end.column}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
getLastRow () {
|
||||||
|
return this.editor.lastLine()
|
||||||
|
}
|
||||||
|
|
||||||
|
acceptsTableEdit (row) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
getLine (row) {
|
||||||
|
return this.editor.getLine(row)
|
||||||
|
}
|
||||||
|
|
||||||
|
insertLine (row, line) {
|
||||||
|
this.editor.replaceRange(line, {line: row, ch: 0})
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteLine (row) {
|
||||||
|
this.editor.replaceRange('', {line: row, ch: 0}, {line: row, ch: this.editor.getLine(row).length})
|
||||||
|
}
|
||||||
|
|
||||||
|
replaceLines (startRow, endRow, lines) {
|
||||||
|
endRow-- // because endRow is a first line after a table.
|
||||||
|
const endRowCh = this.editor.getLine(endRow).length
|
||||||
|
this.editor.replaceRange(lines, {line: startRow, ch: 0}, {line: endRow, ch: endRowCh})
|
||||||
|
}
|
||||||
|
|
||||||
|
transact (func) {
|
||||||
|
func()
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -36,7 +36,15 @@ const consts = {
|
|||||||
'Violet Eggplant'
|
'Violet Eggplant'
|
||||||
],
|
],
|
||||||
THEMES: ['default'].concat(themes),
|
THEMES: ['default'].concat(themes),
|
||||||
SNIPPET_FILE: snippetFile
|
SNIPPET_FILE: snippetFile,
|
||||||
|
DEFAULT_EDITOR_FONT_FAMILY: [
|
||||||
|
'Monaco',
|
||||||
|
'Menlo',
|
||||||
|
'Ubuntu Mono',
|
||||||
|
'Consolas',
|
||||||
|
'source-code-pro',
|
||||||
|
'monospace'
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = consts
|
module.exports = consts
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ module.exports = function sanitizePlugin (md, options) {
|
|||||||
if (state.tokens[tokenIdx].type === 'html_block') {
|
if (state.tokens[tokenIdx].type === 'html_block') {
|
||||||
state.tokens[tokenIdx].content = sanitizeHtml(state.tokens[tokenIdx].content, options)
|
state.tokens[tokenIdx].content = sanitizeHtml(state.tokens[tokenIdx].content, options)
|
||||||
}
|
}
|
||||||
|
if (state.tokens[tokenIdx].type === 'fence') {
|
||||||
|
state.tokens[tokenIdx].content = state.tokens[tokenIdx].content.replace(/&/g, '&').replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"')
|
||||||
|
}
|
||||||
if (state.tokens[tokenIdx].type === 'inline') {
|
if (state.tokens[tokenIdx].type === 'inline') {
|
||||||
const inlineTokens = state.tokens[tokenIdx].children
|
const inlineTokens = state.tokens[tokenIdx].children
|
||||||
for (let childIdx = 0; childIdx < inlineTokens.length; childIdx++) {
|
for (let childIdx = 0; childIdx < inlineTokens.length; childIdx++) {
|
||||||
|
|||||||
@@ -40,6 +40,12 @@ class Markdown {
|
|||||||
if (langType === 'sequence') {
|
if (langType === 'sequence') {
|
||||||
return `<pre class="sequence">${str}</pre>`
|
return `<pre class="sequence">${str}</pre>`
|
||||||
}
|
}
|
||||||
|
if (langType === 'chart') {
|
||||||
|
return `<pre class="chart">${str}</pre>`
|
||||||
|
}
|
||||||
|
if (langType === 'mermaid') {
|
||||||
|
return `<pre class="mermaid">${str}</pre>`
|
||||||
|
}
|
||||||
return '<pre class="code CodeMirror">' +
|
return '<pre class="code CodeMirror">' +
|
||||||
'<span class="filename">' + fileName + '</span>' +
|
'<span class="filename">' + fileName + '</span>' +
|
||||||
createGutter(str, firstLineNumber) +
|
createGutter(str, firstLineNumber) +
|
||||||
@@ -245,4 +251,3 @@ class Markdown {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export default Markdown
|
export default Markdown
|
||||||
|
|
||||||
|
|||||||
9
browser/lib/normalizeEditorFontFamily.js
Normal file
9
browser/lib/normalizeEditorFontFamily.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import consts from 'browser/lib/consts'
|
||||||
|
import isString from 'lodash/isString'
|
||||||
|
|
||||||
|
export default function normalizeEditorFontFamily (fontFamily) {
|
||||||
|
const defaultEditorFontFamily = consts.DEFAULT_EDITOR_FONT_FAMILY
|
||||||
|
return isString(fontFamily) && fontFamily.length > 0
|
||||||
|
? [fontFamily].concat(defaultEditorFontFamily).join(', ')
|
||||||
|
: defaultEditorFontFamily.join(', ')
|
||||||
|
}
|
||||||
@@ -6,52 +6,64 @@ export function lastFindInArray (array, callback) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function escapeHtmlCharacters (text) {
|
export function escapeHtmlCharacters (html, opt = { detectCodeBlock: false }) {
|
||||||
const matchHtmlRegExp = /["'&<>]/
|
const matchHtmlRegExp = /["'&<>]/g
|
||||||
const str = '' + text
|
const escapes = ['"', '&', ''', '<', '>']
|
||||||
const match = matchHtmlRegExp.exec(str)
|
let match = null
|
||||||
|
const replaceAt = (str, index, replace) =>
|
||||||
|
str.substr(0, index) +
|
||||||
|
replace +
|
||||||
|
str.substr(index + replace.length - (replace.length - 1))
|
||||||
|
|
||||||
if (!match) {
|
// detecting code block
|
||||||
return str
|
while ((match = matchHtmlRegExp.exec(html)) != null) {
|
||||||
}
|
const current = { char: match[0], index: match.index }
|
||||||
|
if (opt.detectCodeBlock) {
|
||||||
let escape
|
// position of the nearest line start
|
||||||
let html = ''
|
let previousLineEnd = current.index - 1
|
||||||
let index = 0
|
while (html[previousLineEnd] !== '\n' && previousLineEnd !== -1) {
|
||||||
let lastIndex = 0
|
previousLineEnd--
|
||||||
|
}
|
||||||
for (index = match.index; index < str.length; index++) {
|
// 4 spaces means this character is in a code block
|
||||||
switch (str.charCodeAt(index)) {
|
if (
|
||||||
case 34: // "
|
html[previousLineEnd + 1] === ' ' &&
|
||||||
escape = '"'
|
html[previousLineEnd + 2] === ' ' &&
|
||||||
break
|
html[previousLineEnd + 3] === ' ' &&
|
||||||
case 38: // &
|
html[previousLineEnd + 4] === ' '
|
||||||
escape = '&'
|
) {
|
||||||
break
|
// so skip it
|
||||||
case 39: // '
|
|
||||||
escape = '''
|
|
||||||
break
|
|
||||||
case 60: // <
|
|
||||||
escape = '<'
|
|
||||||
break
|
|
||||||
case 62: // >
|
|
||||||
escape = '>'
|
|
||||||
break
|
|
||||||
default:
|
|
||||||
continue
|
continue
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// otherwise, escape it !!!
|
||||||
if (lastIndex !== index) {
|
if (current.char === '&') {
|
||||||
html += str.substring(lastIndex, index)
|
let nextStr = ''
|
||||||
|
let nextIndex = current.index
|
||||||
|
let escapedStr = false
|
||||||
|
// maximum length of an escape string is 5. For example ('"')
|
||||||
|
while (nextStr.length <= 5) {
|
||||||
|
nextStr += html[nextIndex]
|
||||||
|
nextIndex++
|
||||||
|
if (escapes.indexOf(nextStr) !== -1) {
|
||||||
|
escapedStr = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!escapedStr) {
|
||||||
|
// this & char is not a part of an escaped string
|
||||||
|
html = replaceAt(html, current.index, '&')
|
||||||
|
}
|
||||||
|
} else if (current.char === '"') {
|
||||||
|
html = replaceAt(html, current.index, '"')
|
||||||
|
} else if (current.char === "'") {
|
||||||
|
html = replaceAt(html, current.index, ''')
|
||||||
|
} else if (current.char === '<') {
|
||||||
|
html = replaceAt(html, current.index, '<')
|
||||||
|
} else if (current.char === '>') {
|
||||||
|
html = replaceAt(html, current.index, '>')
|
||||||
}
|
}
|
||||||
|
|
||||||
lastIndex = index + 1
|
|
||||||
html += escape
|
|
||||||
}
|
}
|
||||||
|
return html
|
||||||
return lastIndex !== index
|
|
||||||
? html + str.substring(lastIndex, index)
|
|
||||||
: html
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function isObjectEqual (a, b) {
|
export function isObjectEqual (a, b) {
|
||||||
|
|||||||
@@ -4,12 +4,14 @@ import CSSModules from 'browser/lib/CSSModules'
|
|||||||
import styles from './FullscreenButton.styl'
|
import styles from './FullscreenButton.styl'
|
||||||
import i18n from 'browser/lib/i18n'
|
import i18n from 'browser/lib/i18n'
|
||||||
|
|
||||||
|
const OSX = global.process.platform === 'darwin'
|
||||||
|
const hotkey = (OSX ? i18n.__('Command(⌘)') : i18n.__('Ctrl(^)')) + '+B'
|
||||||
const FullscreenButton = ({
|
const FullscreenButton = ({
|
||||||
onClick
|
onClick
|
||||||
}) => (
|
}) => (
|
||||||
<button styleName='control-fullScreenButton' title={i18n.__('Fullscreen')} onMouseDown={(e) => onClick(e)}>
|
<button styleName='control-fullScreenButton' title={i18n.__('Fullscreen')} onMouseDown={(e) => onClick(e)}>
|
||||||
<img styleName='iconInfo' src='../resources/icon/icon-full.svg' />
|
<img styleName='iconInfo' src='../resources/icon/icon-full.svg' />
|
||||||
<span styleName='tooltip'>{i18n.__('Fullscreen')}</span>
|
<span styleName='tooltip'>{i18n.__('Fullscreen')}({hotkey})</span>
|
||||||
</button>
|
</button>
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ import { confirmDeleteNote } from 'browser/lib/confirmDeleteNote'
|
|||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const { remote } = electron
|
const { remote } = electron
|
||||||
const { Menu, MenuItem, dialog } = remote
|
const { dialog } = remote
|
||||||
|
|
||||||
class SnippetNoteDetail extends React.Component {
|
class SnippetNoteDetail extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -451,14 +451,14 @@ class SnippetNoteDetail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleModeButtonClick (e, index) {
|
handleModeButtonClick (e, index) {
|
||||||
const menu = new Menu()
|
const templetes = []
|
||||||
CodeMirror.modeInfo.sort(function (a, b) { return a.name.localeCompare(b.name) }).forEach((mode) => {
|
CodeMirror.modeInfo.sort(function (a, b) { return a.name.localeCompare(b.name) }).forEach((mode) => {
|
||||||
menu.append(new MenuItem({
|
templetes.push({
|
||||||
label: mode.name,
|
label: mode.name,
|
||||||
click: (e) => this.handleModeOptionClick(index, mode.name)(e)
|
click: (e) => this.handleModeOptionClick(index, mode.name)(e)
|
||||||
}))
|
})
|
||||||
})
|
})
|
||||||
menu.popup(remote.getCurrentWindow())
|
context.popup(templetes)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleIndentTypeButtonClick (e) {
|
handleIndentTypeButtonClick (e) {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import ee from 'browser/main/lib/eventEmitter'
|
|||||||
import StatusBar from '../StatusBar'
|
import StatusBar from '../StatusBar'
|
||||||
import i18n from 'browser/lib/i18n'
|
import i18n from 'browser/lib/i18n'
|
||||||
import debounceRender from 'react-debounce-render'
|
import debounceRender from 'react-debounce-render'
|
||||||
|
import searchFromNotes from 'browser/lib/search'
|
||||||
|
|
||||||
const OSX = global.process.platform === 'darwin'
|
const OSX = global.process.platform === 'darwin'
|
||||||
|
|
||||||
@@ -35,11 +36,38 @@ class Detail extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { location, data, config } = this.props
|
const { location, data, params, config } = this.props
|
||||||
let note = null
|
let note = null
|
||||||
|
|
||||||
if (location.query.key != null) {
|
if (location.query.key != null) {
|
||||||
const noteKey = location.query.key
|
const noteKey = location.query.key
|
||||||
note = data.noteMap.get(noteKey)
|
const allNotes = data.noteMap.map(note => note)
|
||||||
|
const trashedNotes = data.trashedSet.toJS().map(uniqueKey => data.noteMap.get(uniqueKey))
|
||||||
|
let displayedNotes = allNotes
|
||||||
|
|
||||||
|
if (location.pathname.match(/\/searched/)) {
|
||||||
|
const searchStr = params.searchword
|
||||||
|
displayedNotes = searchStr === undefined || searchStr === '' ? allNotes
|
||||||
|
: searchFromNotes(allNotes, searchStr)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location.pathname.match(/\/tags/)) {
|
||||||
|
const listOfTags = params.tagname.split(' ')
|
||||||
|
displayedNotes = data.noteMap.map(note => note).filter(note =>
|
||||||
|
listOfTags.every(tag => note.tags.includes(tag))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (location.pathname.match(/\/trashed/)) {
|
||||||
|
displayedNotes = trashedNotes
|
||||||
|
} else {
|
||||||
|
displayedNotes = _.differenceWith(displayedNotes, trashedNotes, (note, trashed) => note.key === trashed.key)
|
||||||
|
}
|
||||||
|
|
||||||
|
const noteKeys = displayedNotes.map(note => note.key)
|
||||||
|
if (noteKeys.includes(noteKey)) {
|
||||||
|
note = data.noteMap.get(noteKey)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (note == null) {
|
if (note == null) {
|
||||||
|
|||||||
@@ -21,9 +21,10 @@ import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
|
|||||||
import Markdown from '../../lib/markdown'
|
import Markdown from '../../lib/markdown'
|
||||||
import i18n from 'browser/lib/i18n'
|
import i18n from 'browser/lib/i18n'
|
||||||
import { confirmDeleteNote } from 'browser/lib/confirmDeleteNote'
|
import { confirmDeleteNote } from 'browser/lib/confirmDeleteNote'
|
||||||
|
import context from 'browser/lib/context'
|
||||||
|
|
||||||
const { remote } = require('electron')
|
const { remote } = require('electron')
|
||||||
const { Menu, MenuItem, dialog } = remote
|
const { dialog } = remote
|
||||||
const WP_POST_PATH = '/wp/v2/posts'
|
const WP_POST_PATH = '/wp/v2/posts'
|
||||||
|
|
||||||
function sortByCreatedAt (a, b) {
|
function sortByCreatedAt (a, b) {
|
||||||
@@ -491,55 +492,51 @@ class NoteList extends React.Component {
|
|||||||
const updateLabel = i18n.__('Update Blog')
|
const updateLabel = i18n.__('Update Blog')
|
||||||
const openBlogLabel = i18n.__('Open Blog')
|
const openBlogLabel = i18n.__('Open Blog')
|
||||||
|
|
||||||
const menu = new Menu()
|
const templates = []
|
||||||
|
|
||||||
if (location.pathname.match(/\/trash/)) {
|
if (location.pathname.match(/\/trash/)) {
|
||||||
menu.append(new MenuItem({
|
templates.push({
|
||||||
label: restoreNote,
|
label: restoreNote,
|
||||||
click: this.restoreNote
|
click: this.restoreNote
|
||||||
}))
|
}, {
|
||||||
menu.append(new MenuItem({
|
|
||||||
label: deleteLabel,
|
label: deleteLabel,
|
||||||
click: this.deleteNote
|
click: this.deleteNote
|
||||||
}))
|
})
|
||||||
} else {
|
} else {
|
||||||
if (!location.pathname.match(/\/starred/)) {
|
if (!location.pathname.match(/\/starred/)) {
|
||||||
menu.append(new MenuItem({
|
templates.push({
|
||||||
label: pinLabel,
|
label: pinLabel,
|
||||||
click: this.pinToTop
|
click: this.pinToTop
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
menu.append(new MenuItem({
|
templates.push({
|
||||||
label: deleteLabel,
|
label: deleteLabel,
|
||||||
click: this.deleteNote
|
click: this.deleteNote
|
||||||
}))
|
}, {
|
||||||
menu.append(new MenuItem({
|
|
||||||
label: cloneNote,
|
label: cloneNote,
|
||||||
click: this.cloneNote.bind(this)
|
click: this.cloneNote.bind(this)
|
||||||
}))
|
}, {
|
||||||
menu.append(new MenuItem({
|
|
||||||
label: copyNoteLink,
|
label: copyNoteLink,
|
||||||
click: this.copyNoteLink(note)
|
click: this.copyNoteLink(note)
|
||||||
}))
|
})
|
||||||
if (note.type === 'MARKDOWN_NOTE') {
|
if (note.type === 'MARKDOWN_NOTE') {
|
||||||
if (note.blog && note.blog.blogLink && note.blog.blogId) {
|
if (note.blog && note.blog.blogLink && note.blog.blogId) {
|
||||||
menu.append(new MenuItem({
|
templates.push({
|
||||||
label: updateLabel,
|
label: updateLabel,
|
||||||
click: this.publishMarkdown.bind(this)
|
click: this.publishMarkdown.bind(this)
|
||||||
}))
|
}, {
|
||||||
menu.append(new MenuItem({
|
|
||||||
label: openBlogLabel,
|
label: openBlogLabel,
|
||||||
click: () => this.openBlog.bind(this)(note)
|
click: () => this.openBlog.bind(this)(note)
|
||||||
}))
|
})
|
||||||
} else {
|
} else {
|
||||||
menu.append(new MenuItem({
|
templates.push({
|
||||||
label: publishLabel,
|
label: publishLabel,
|
||||||
click: this.publishMarkdown.bind(this)
|
click: this.publishMarkdown.bind(this)
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
menu.popup()
|
context.popup(templates)
|
||||||
}
|
}
|
||||||
|
|
||||||
updateSelectedNotes (updateFunc, cleanSelection = true) {
|
updateSelectedNotes (updateFunc, cleanSelection = true) {
|
||||||
|
|||||||
@@ -11,9 +11,10 @@ import StorageItemChild from 'browser/components/StorageItem'
|
|||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import { SortableElement } from 'react-sortable-hoc'
|
import { SortableElement } from 'react-sortable-hoc'
|
||||||
import i18n from 'browser/lib/i18n'
|
import i18n from 'browser/lib/i18n'
|
||||||
|
import context from 'browser/lib/context'
|
||||||
|
|
||||||
const { remote } = require('electron')
|
const { remote } = require('electron')
|
||||||
const { Menu, dialog } = remote
|
const { dialog } = remote
|
||||||
const escapeStringRegexp = require('escape-string-regexp')
|
const escapeStringRegexp = require('escape-string-regexp')
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
@@ -21,13 +22,15 @@ class StorageItem extends React.Component {
|
|||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
|
const { storage } = this.props
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
isOpen: true
|
isOpen: !!storage.isOpen
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
handleHeaderContextMenu (e) {
|
handleHeaderContextMenu (e) {
|
||||||
const menu = Menu.buildFromTemplate([
|
context.popup([
|
||||||
{
|
{
|
||||||
label: i18n.__('Add Folder'),
|
label: i18n.__('Add Folder'),
|
||||||
click: (e) => this.handleAddFolderButtonClick(e)
|
click: (e) => this.handleAddFolderButtonClick(e)
|
||||||
@@ -40,8 +43,6 @@ class StorageItem extends React.Component {
|
|||||||
click: (e) => this.handleUnlinkStorageClick(e)
|
click: (e) => this.handleUnlinkStorageClick(e)
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
menu.popup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleUnlinkStorageClick (e) {
|
handleUnlinkStorageClick (e) {
|
||||||
@@ -68,8 +69,18 @@ class StorageItem extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleToggleButtonClick (e) {
|
handleToggleButtonClick (e) {
|
||||||
|
const { storage, dispatch } = this.props
|
||||||
|
const isOpen = !this.state.isOpen
|
||||||
|
dataApi.toggleStorage(storage.key, isOpen)
|
||||||
|
.then((storage) => {
|
||||||
|
dispatch({
|
||||||
|
type: 'EXPAND_STORAGE',
|
||||||
|
storage,
|
||||||
|
isOpen
|
||||||
|
})
|
||||||
|
})
|
||||||
this.setState({
|
this.setState({
|
||||||
isOpen: !this.state.isOpen
|
isOpen: isOpen
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -94,7 +105,7 @@ class StorageItem extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleFolderButtonContextMenu (e, folder) {
|
handleFolderButtonContextMenu (e, folder) {
|
||||||
const menu = Menu.buildFromTemplate([
|
context.popup([
|
||||||
{
|
{
|
||||||
label: i18n.__('Rename Folder'),
|
label: i18n.__('Rename Folder'),
|
||||||
click: (e) => this.handleRenameFolderClick(e, folder)
|
click: (e) => this.handleRenameFolderClick(e, folder)
|
||||||
@@ -123,8 +134,6 @@ class StorageItem extends React.Component {
|
|||||||
click: (e) => this.handleFolderDeleteClick(e, folder)
|
click: (e) => this.handleFolderDeleteClick(e, folder)
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
|
|
||||||
menu.popup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
handleRenameFolderClick (e, folder) {
|
handleRenameFolderClick (e, folder) {
|
||||||
|
|||||||
@@ -1,8 +1,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'
|
||||||
const { remote } = require('electron')
|
|
||||||
const { Menu } = remote
|
|
||||||
import dataApi from 'browser/main/lib/dataApi'
|
import dataApi from 'browser/main/lib/dataApi'
|
||||||
import styles from './SideNav.styl'
|
import styles from './SideNav.styl'
|
||||||
import { openModal } from 'browser/main/lib/modal'
|
import { openModal } from 'browser/main/lib/modal'
|
||||||
@@ -19,6 +17,7 @@ import ListButton from './ListButton'
|
|||||||
import TagButton from './TagButton'
|
import TagButton from './TagButton'
|
||||||
import {SortableContainer} from 'react-sortable-hoc'
|
import {SortableContainer} from 'react-sortable-hoc'
|
||||||
import i18n from 'browser/lib/i18n'
|
import i18n from 'browser/lib/i18n'
|
||||||
|
import context from 'browser/lib/context'
|
||||||
|
|
||||||
class SideNav extends React.Component {
|
class SideNav extends React.Component {
|
||||||
// TODO: should not use electron stuff v0.7
|
// TODO: should not use electron stuff v0.7
|
||||||
@@ -254,10 +253,9 @@ class SideNav extends React.Component {
|
|||||||
handleFilterButtonContextMenu (event) {
|
handleFilterButtonContextMenu (event) {
|
||||||
const { data } = this.props
|
const { data } = this.props
|
||||||
const trashedNotes = data.trashedSet.toJS().map((uniqueKey) => data.noteMap.get(uniqueKey))
|
const trashedNotes = data.trashedSet.toJS().map((uniqueKey) => data.noteMap.get(uniqueKey))
|
||||||
const menu = Menu.buildFromTemplate([
|
context.popup([
|
||||||
{ label: i18n.__('Empty Trash'), click: () => this.emptyTrash(trashedNotes) }
|
{ label: i18n.__('Empty Trash'), click: () => this.emptyTrash(trashedNotes) }
|
||||||
])
|
])
|
||||||
menu.popup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
|
|||||||
@@ -4,10 +4,11 @@ import CSSModules from 'browser/lib/CSSModules'
|
|||||||
import styles from './StatusBar.styl'
|
import styles from './StatusBar.styl'
|
||||||
import ZoomManager from 'browser/main/lib/ZoomManager'
|
import ZoomManager from 'browser/main/lib/ZoomManager'
|
||||||
import i18n from 'browser/lib/i18n'
|
import i18n from 'browser/lib/i18n'
|
||||||
|
import context from 'browser/lib/context'
|
||||||
|
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const { remote, ipcRenderer } = electron
|
const { remote, ipcRenderer } = electron
|
||||||
const { Menu, MenuItem, dialog } = remote
|
const { dialog } = remote
|
||||||
|
|
||||||
const zoomOptions = [0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0]
|
const zoomOptions = [0.8, 0.9, 1, 1.1, 1.2, 1.3, 1.4, 1.5, 1.6, 1.7, 1.8, 1.9, 2.0]
|
||||||
|
|
||||||
@@ -26,16 +27,16 @@ class StatusBar extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleZoomButtonClick (e) {
|
handleZoomButtonClick (e) {
|
||||||
const menu = new Menu()
|
const templates = []
|
||||||
|
|
||||||
zoomOptions.forEach((zoom) => {
|
zoomOptions.forEach((zoom) => {
|
||||||
menu.append(new MenuItem({
|
templates.push({
|
||||||
label: Math.floor(zoom * 100) + '%',
|
label: Math.floor(zoom * 100) + '%',
|
||||||
click: () => this.handleZoomMenuItemClick(zoom)
|
click: () => this.handleZoomMenuItemClick(zoom)
|
||||||
}))
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
menu.popup(remote.getCurrentWindow())
|
context.popup(templates)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleZoomMenuItemClick (zoomFactor) {
|
handleZoomMenuItemClick (zoomFactor) {
|
||||||
|
|||||||
@@ -156,8 +156,7 @@ class TopBar extends React.Component {
|
|||||||
if (this.state.isSearching) {
|
if (this.state.isSearching) {
|
||||||
el.blur()
|
el.blur()
|
||||||
} else {
|
} else {
|
||||||
el.focus()
|
el.select()
|
||||||
el.setSelectionRange(0, el.value.length)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -15,6 +15,12 @@ body
|
|||||||
font-weight 200
|
font-weight 200
|
||||||
-webkit-font-smoothing antialiased
|
-webkit-font-smoothing antialiased
|
||||||
|
|
||||||
|
::-webkit-scrollbar
|
||||||
|
width 12px
|
||||||
|
|
||||||
|
::-webkit-scrollbar-thumb
|
||||||
|
background-color rgba(0, 0, 0, 0.15)
|
||||||
|
|
||||||
button, input, select, textarea
|
button, input, select, textarea
|
||||||
font-family DEFAULT_FONTS
|
font-family DEFAULT_FONTS
|
||||||
|
|
||||||
@@ -85,9 +91,11 @@ modalBackColor = white
|
|||||||
absolute top left bottom right
|
absolute top left bottom right
|
||||||
background-color modalBackColor
|
background-color modalBackColor
|
||||||
z-index modalZIndex + 1
|
z-index modalZIndex + 1
|
||||||
|
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
|
::-webkit-scrollbar-thumb
|
||||||
|
background-color rgba(0, 0, 0, 0.3)
|
||||||
.ModalBase
|
.ModalBase
|
||||||
.modalBack
|
.modalBack
|
||||||
background-color $ui-dark-backgroundColor
|
background-color $ui-dark-backgroundColor
|
||||||
@@ -128,6 +136,8 @@ body[data-theme="dark"]
|
|||||||
z-index modalZIndex + 5
|
z-index modalZIndex + 5
|
||||||
|
|
||||||
body[data-theme="solarized-dark"]
|
body[data-theme="solarized-dark"]
|
||||||
|
::-webkit-scrollbar-thumb
|
||||||
|
background-color rgba(0, 0, 0, 0.3)
|
||||||
.ModalBase
|
.ModalBase
|
||||||
.modalBack
|
.modalBack
|
||||||
background-color $ui-solarized-dark-backgroundColor
|
background-color $ui-solarized-dark-backgroundColor
|
||||||
@@ -135,9 +145,10 @@ body[data-theme="solarized-dark"]
|
|||||||
color: $ui-solarized-dark-text-color
|
color: $ui-solarized-dark-text-color
|
||||||
|
|
||||||
body[data-theme="monokai"]
|
body[data-theme="monokai"]
|
||||||
|
::-webkit-scrollbar-thumb
|
||||||
|
background-color rgba(0, 0, 0, 0.3)
|
||||||
.ModalBase
|
.ModalBase
|
||||||
.modalBack
|
.modalBack
|
||||||
background-color $ui-monokai-backgroundColor
|
background-color $ui-monokai-backgroundColor
|
||||||
.sortableItemHelper
|
.sortableItemHelper
|
||||||
color: $ui-monokai-text-color
|
color: $ui-monokai-text-color
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ function addStorage (input) {
|
|||||||
key,
|
key,
|
||||||
name: input.name,
|
name: input.name,
|
||||||
type: input.type,
|
type: input.type,
|
||||||
path: input.path
|
path: input.path,
|
||||||
|
isOpen: false
|
||||||
}
|
}
|
||||||
|
|
||||||
return Promise.resolve(newStorage)
|
return Promise.resolve(newStorage)
|
||||||
@@ -48,7 +49,8 @@ function addStorage (input) {
|
|||||||
key: newStorage.key,
|
key: newStorage.key,
|
||||||
type: newStorage.type,
|
type: newStorage.type,
|
||||||
name: newStorage.name,
|
name: newStorage.name,
|
||||||
path: newStorage.path
|
path: newStorage.path,
|
||||||
|
isOpen: false
|
||||||
})
|
})
|
||||||
|
|
||||||
localStorage.setItem('storages', JSON.stringify(rawStorages))
|
localStorage.setItem('storages', JSON.stringify(rawStorages))
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import i18n from 'browser/lib/i18n'
|
|||||||
|
|
||||||
const STORAGE_FOLDER_PLACEHOLDER = ':storage'
|
const STORAGE_FOLDER_PLACEHOLDER = ':storage'
|
||||||
const DESTINATION_FOLDER = 'attachments'
|
const DESTINATION_FOLDER = 'attachments'
|
||||||
|
const PATH_SEPARATORS = escapeStringRegexp(path.posix.sep) + escapeStringRegexp(path.win32.sep)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description
|
* @description
|
||||||
@@ -76,13 +77,13 @@ function createAttachmentDestinationFolder (destinationStoragePath, noteKey) {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Moves attachments from the old location ('/images') to the new one ('/attachments/noteKey)
|
* @description Moves attachments from the old location ('/images') to the new one ('/attachments/noteKey)
|
||||||
* @param renderedHTML HTML of the current note
|
* @param markdownContent of the current note
|
||||||
* @param storagePath Storage path of the current note
|
* @param storagePath Storage path of the current note
|
||||||
* @param noteKey Key of the current note
|
* @param noteKey Key of the current note
|
||||||
*/
|
*/
|
||||||
function migrateAttachments (renderedHTML, storagePath, noteKey) {
|
function migrateAttachments (markdownContent, storagePath, noteKey) {
|
||||||
if (sander.existsSync(path.join(storagePath, 'images'))) {
|
if (sander.existsSync(path.join(storagePath, 'images'))) {
|
||||||
const attachments = getAttachmentsInContent(renderedHTML) || []
|
const attachments = getAttachmentsInMarkdownContent(markdownContent) || []
|
||||||
if (attachments !== []) {
|
if (attachments !== []) {
|
||||||
createAttachmentDestinationFolder(storagePath, noteKey)
|
createAttachmentDestinationFolder(storagePath, noteKey)
|
||||||
}
|
}
|
||||||
@@ -106,7 +107,10 @@ function migrateAttachments (renderedHTML, 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(mdurl.encode(path.sep), 'g'), path.sep).replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER))
|
return renderedHTML.replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '.*?"', 'g'), function (match) {
|
||||||
|
var encodedPathSeparators = new RegExp(mdurl.encode(path.win32.sep) + '|' + mdurl.encode(path.posix.sep), 'g')
|
||||||
|
return match.replace(encodedPathSeparators, path.sep).replace(new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER))
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -186,13 +190,13 @@ function handlePastImageEvent (codeEditor, storageKey, noteKey, dataTransferItem
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Returns all attachment paths of the given markdown
|
* @description Returns all attachment paths of the given markdown
|
||||||
* @param {String} markdownContent content in which the attachment paths should be found
|
* @param {String} markdownContent content in which the attachment paths should be found
|
||||||
* @returns {String[]} Array of the relative paths (starting with :storage) of the attachments of the given markdown
|
* @returns {String[]} Array of the relative paths (starting with :storage) of the attachments of the given markdown
|
||||||
*/
|
*/
|
||||||
function getAttachmentsInContent (markdownContent) {
|
function getAttachmentsInMarkdownContent (markdownContent) {
|
||||||
const preparedInput = markdownContent.replace(new RegExp(mdurl.encode(path.sep), 'g'), path.sep)
|
const preparedInput = markdownContent.replace(new RegExp('[' + PATH_SEPARATORS + ']', 'g'), path.sep)
|
||||||
const regexp = new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '(' + escapeStringRegexp(path.sep) + '|/)' + '?([a-zA-Z0-9]|-)*' + '(' + escapeStringRegexp(path.sep) + '|/)' + '([a-zA-Z0-9]|\\.)+(\\.[a-zA-Z0-9]+)?', 'g')
|
const regexp = new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '(' + escapeStringRegexp(path.sep) + ')' + '?([a-zA-Z0-9]|-)*' + '(' + escapeStringRegexp(path.sep) + ')' + '([a-zA-Z0-9]|\\.)+(\\.[a-zA-Z0-9]+)?', 'g')
|
||||||
return preparedInput.match(regexp)
|
return preparedInput.match(regexp)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -203,7 +207,7 @@ function getAttachmentsInContent (markdownContent) {
|
|||||||
* @returns {String[]} Absolute paths of the referenced attachments
|
* @returns {String[]} Absolute paths of the referenced attachments
|
||||||
*/
|
*/
|
||||||
function getAbsolutePathsOfAttachmentsInContent (markdownContent, storagePath) {
|
function getAbsolutePathsOfAttachmentsInContent (markdownContent, storagePath) {
|
||||||
const temp = getAttachmentsInContent(markdownContent) || []
|
const temp = getAttachmentsInMarkdownContent(markdownContent) || []
|
||||||
const result = []
|
const result = []
|
||||||
for (const relativePath of temp) {
|
for (const relativePath of temp) {
|
||||||
result.push(relativePath.replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER, 'g'), path.join(storagePath, DESTINATION_FOLDER)))
|
result.push(relativePath.replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER, 'g'), path.join(storagePath, DESTINATION_FOLDER)))
|
||||||
@@ -239,7 +243,8 @@ function moveAttachments (oldPath, newPath, noteKey, newNoteKey, noteContent) {
|
|||||||
*/
|
*/
|
||||||
function replaceNoteKeyWithNewNoteKey (noteContent, oldNoteKey, newNoteKey) {
|
function replaceNoteKeyWithNewNoteKey (noteContent, oldNoteKey, newNoteKey) {
|
||||||
if (noteContent) {
|
if (noteContent) {
|
||||||
return noteContent.replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER + escapeStringRegexp(path.sep) + oldNoteKey, 'g'), path.join(STORAGE_FOLDER_PLACEHOLDER, newNoteKey))
|
const preparedInput = noteContent.replace(new RegExp('[' + PATH_SEPARATORS + ']', 'g'), path.sep)
|
||||||
|
return preparedInput.replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER + escapeStringRegexp(path.sep) + oldNoteKey, 'g'), path.join(STORAGE_FOLDER_PLACEHOLDER, newNoteKey))
|
||||||
}
|
}
|
||||||
return noteContent
|
return noteContent
|
||||||
}
|
}
|
||||||
@@ -277,7 +282,7 @@ function deleteAttachmentsNotPresentInNote (markdownContent, storageKey, noteKey
|
|||||||
}
|
}
|
||||||
const targetStorage = findStorage.findStorage(storageKey)
|
const targetStorage = findStorage.findStorage(storageKey)
|
||||||
const attachmentFolder = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey)
|
const attachmentFolder = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey)
|
||||||
const attachmentsInNote = getAttachmentsInContent(markdownContent)
|
const attachmentsInNote = getAttachmentsInMarkdownContent(markdownContent)
|
||||||
const attachmentsInNoteOnlyFileNames = []
|
const attachmentsInNoteOnlyFileNames = []
|
||||||
if (attachmentsInNote) {
|
if (attachmentsInNote) {
|
||||||
for (let i = 0; i < attachmentsInNote.length; i++) {
|
for (let i = 0; i < attachmentsInNote.length; i++) {
|
||||||
@@ -348,7 +353,7 @@ function generateFileNotFoundMarkdown () {
|
|||||||
*/
|
*/
|
||||||
function isAttachmentLink (text) {
|
function isAttachmentLink (text) {
|
||||||
if (text) {
|
if (text) {
|
||||||
return text.match(new RegExp('.*\\[.*\\]\\( *' + escapeStringRegexp(STORAGE_FOLDER_PLACEHOLDER) + escapeStringRegexp(path.sep) + '.*\\).*', 'gi')) != null
|
return text.match(new RegExp('.*\\[.*\\]\\( *' + escapeStringRegexp(STORAGE_FOLDER_PLACEHOLDER) + '[' + PATH_SEPARATORS + ']' + '.*\\).*', 'gi')) != null
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -364,7 +369,7 @@ function isAttachmentLink (text) {
|
|||||||
function handleAttachmentLinkPaste (storageKey, noteKey, linkText) {
|
function handleAttachmentLinkPaste (storageKey, noteKey, linkText) {
|
||||||
if (storageKey != null && noteKey != null && linkText != null) {
|
if (storageKey != null && noteKey != null && linkText != null) {
|
||||||
const storagePath = findStorage.findStorage(storageKey).path
|
const storagePath = findStorage.findStorage(storageKey).path
|
||||||
const attachments = getAttachmentsInContent(linkText) || []
|
const attachments = getAttachmentsInMarkdownContent(linkText) || []
|
||||||
const replaceInstructions = []
|
const replaceInstructions = []
|
||||||
const copies = []
|
const copies = []
|
||||||
for (const attachment of attachments) {
|
for (const attachment of attachments) {
|
||||||
@@ -373,13 +378,13 @@ function handleAttachmentLinkPaste (storageKey, noteKey, linkText) {
|
|||||||
sander.exists(absPathOfAttachment)
|
sander.exists(absPathOfAttachment)
|
||||||
.then((fileExists) => {
|
.then((fileExists) => {
|
||||||
if (!fileExists) {
|
if (!fileExists) {
|
||||||
const fileNotFoundRegexp = new RegExp('!?' + escapeStringRegexp('[') + '[\\w|\\d|\\s|\\.]*\\]\\(\\s*' + STORAGE_FOLDER_PLACEHOLDER + '[\\w|\\d|\\-|' + escapeStringRegexp(path.sep) + ']*' + escapeStringRegexp(path.basename(absPathOfAttachment)) + escapeStringRegexp(')'))
|
const fileNotFoundRegexp = new RegExp('!?' + escapeStringRegexp('[') + '[\\w|\\d|\\s|\\.]*\\]\\(\\s*' + STORAGE_FOLDER_PLACEHOLDER + '[\\w|\\d|\\-|' + PATH_SEPARATORS + ']*' + escapeStringRegexp(path.basename(absPathOfAttachment)) + escapeStringRegexp(')'))
|
||||||
replaceInstructions.push({regexp: fileNotFoundRegexp, replacement: this.generateFileNotFoundMarkdown()})
|
replaceInstructions.push({regexp: fileNotFoundRegexp, replacement: this.generateFileNotFoundMarkdown()})
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
return this.copyAttachment(absPathOfAttachment, storageKey, noteKey)
|
return this.copyAttachment(absPathOfAttachment, storageKey, noteKey)
|
||||||
.then((fileName) => {
|
.then((fileName) => {
|
||||||
const replaceLinkRegExp = new RegExp(escapeStringRegexp('(') + ' *' + STORAGE_FOLDER_PLACEHOLDER + '[\\w|\\d|\\-|' + escapeStringRegexp(path.sep) + ']*' + escapeStringRegexp(path.basename(absPathOfAttachment)) + ' *' + escapeStringRegexp(')'))
|
const replaceLinkRegExp = new RegExp(escapeStringRegexp('(') + ' *' + STORAGE_FOLDER_PLACEHOLDER + '[\\w|\\d|\\-|' + PATH_SEPARATORS + ']*' + escapeStringRegexp(path.basename(absPathOfAttachment)) + ' *' + escapeStringRegexp(')'))
|
||||||
replaceInstructions.push({
|
replaceInstructions.push({
|
||||||
regexp: replaceLinkRegExp,
|
regexp: replaceLinkRegExp,
|
||||||
replacement: '(' + path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, fileName) + ')'
|
replacement: '(' + path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, fileName) + ')'
|
||||||
@@ -408,7 +413,7 @@ module.exports = {
|
|||||||
generateAttachmentMarkdown,
|
generateAttachmentMarkdown,
|
||||||
handleAttachmentDrop,
|
handleAttachmentDrop,
|
||||||
handlePastImageEvent,
|
handlePastImageEvent,
|
||||||
getAttachmentsInContent,
|
getAttachmentsInMarkdownContent,
|
||||||
getAbsolutePathsOfAttachmentsInContent,
|
getAbsolutePathsOfAttachmentsInContent,
|
||||||
removeStorageAndNoteReferences,
|
removeStorageAndNoteReferences,
|
||||||
deleteAttachmentFolder,
|
deleteAttachmentFolder,
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
const dataApi = {
|
const dataApi = {
|
||||||
init: require('./init'),
|
init: require('./init'),
|
||||||
|
toggleStorage: require('./toggleStorage'),
|
||||||
addStorage: require('./addStorage'),
|
addStorage: require('./addStorage'),
|
||||||
renameStorage: require('./renameStorage'),
|
renameStorage: require('./renameStorage'),
|
||||||
removeStorage: require('./removeStorage'),
|
removeStorage: require('./removeStorage'),
|
||||||
|
|||||||
@@ -8,7 +8,8 @@ function resolveStorageData (storageCache) {
|
|||||||
key: storageCache.key,
|
key: storageCache.key,
|
||||||
name: storageCache.name,
|
name: storageCache.name,
|
||||||
type: storageCache.type,
|
type: storageCache.type,
|
||||||
path: storageCache.path
|
path: storageCache.path,
|
||||||
|
isOpen: storageCache.isOpen
|
||||||
}
|
}
|
||||||
|
|
||||||
const boostnoteJSONPath = path.join(storageCache.path, 'boostnote.json')
|
const boostnoteJSONPath = path.join(storageCache.path, 'boostnote.json')
|
||||||
|
|||||||
28
browser/main/lib/dataApi/toggleStorage.js
Normal file
28
browser/main/lib/dataApi/toggleStorage.js
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
const _ = require('lodash')
|
||||||
|
const resolveStorageData = require('./resolveStorageData')
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {String} key
|
||||||
|
* @param {Boolean} isOpen
|
||||||
|
* @return {Object} Storage meta data
|
||||||
|
*/
|
||||||
|
function toggleStorage (key, isOpen) {
|
||||||
|
let cachedStorageList
|
||||||
|
try {
|
||||||
|
cachedStorageList = JSON.parse(localStorage.getItem('storages'))
|
||||||
|
if (!_.isArray(cachedStorageList)) throw new Error('invalid storages')
|
||||||
|
} catch (err) {
|
||||||
|
console.log('error got')
|
||||||
|
console.error(err)
|
||||||
|
return Promise.reject(err)
|
||||||
|
}
|
||||||
|
const targetStorage = _.find(cachedStorageList, {key: key})
|
||||||
|
if (targetStorage == null) return Promise.reject('Storage')
|
||||||
|
|
||||||
|
targetStorage.isOpen = isOpen
|
||||||
|
localStorage.setItem('storages', JSON.stringify(cachedStorageList))
|
||||||
|
|
||||||
|
return resolveStorageData(targetStorage)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = toggleStorage
|
||||||
@@ -12,8 +12,7 @@ class NewNoteModal extends React.Component {
|
|||||||
constructor (props) {
|
constructor (props) {
|
||||||
super(props)
|
super(props)
|
||||||
|
|
||||||
this.state = {
|
this.state = {}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidMount () {
|
componentDidMount () {
|
||||||
@@ -35,19 +34,20 @@ class NewNoteModal extends React.Component {
|
|||||||
title: '',
|
title: '',
|
||||||
content: ''
|
content: ''
|
||||||
})
|
})
|
||||||
.then((note) => {
|
.then(note => {
|
||||||
const noteHash = note.key
|
const noteHash = note.key
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'UPDATE_NOTE',
|
type: 'UPDATE_NOTE',
|
||||||
note: note
|
note: note
|
||||||
})
|
})
|
||||||
|
|
||||||
hashHistory.push({
|
hashHistory.push({
|
||||||
pathname: location.pathname,
|
pathname: location.pathname,
|
||||||
query: {key: noteHash}
|
query: { key: noteHash }
|
||||||
})
|
})
|
||||||
ee.emit('list:jump', noteHash)
|
ee.emit('list:jump', noteHash)
|
||||||
ee.emit('detail:focus')
|
ee.emit('detail:focus')
|
||||||
this.props.close()
|
setTimeout(this.props.close, 200)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -69,13 +69,15 @@ class NewNoteModal extends React.Component {
|
|||||||
folder: folder,
|
folder: folder,
|
||||||
title: '',
|
title: '',
|
||||||
description: '',
|
description: '',
|
||||||
snippets: [{
|
snippets: [
|
||||||
name: '',
|
{
|
||||||
mode: 'text',
|
name: '',
|
||||||
content: ''
|
mode: 'text',
|
||||||
}]
|
content: ''
|
||||||
|
}
|
||||||
|
]
|
||||||
})
|
})
|
||||||
.then((note) => {
|
.then(note => {
|
||||||
const noteHash = note.key
|
const noteHash = note.key
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'UPDATE_NOTE',
|
type: 'UPDATE_NOTE',
|
||||||
@@ -83,11 +85,11 @@ class NewNoteModal extends React.Component {
|
|||||||
})
|
})
|
||||||
hashHistory.push({
|
hashHistory.push({
|
||||||
pathname: location.pathname,
|
pathname: location.pathname,
|
||||||
query: {key: noteHash}
|
query: { key: noteHash }
|
||||||
})
|
})
|
||||||
ee.emit('list:jump', noteHash)
|
ee.emit('list:jump', noteHash)
|
||||||
ee.emit('detail:focus')
|
ee.emit('detail:focus')
|
||||||
this.props.close()
|
setTimeout(this.props.close, 200)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,49 +108,65 @@ class NewNoteModal extends React.Component {
|
|||||||
|
|
||||||
render () {
|
render () {
|
||||||
return (
|
return (
|
||||||
<div styleName='root'
|
<div
|
||||||
|
styleName='root'
|
||||||
tabIndex='-1'
|
tabIndex='-1'
|
||||||
onKeyDown={(e) => this.handleKeyDown(e)}
|
onKeyDown={e => this.handleKeyDown(e)}
|
||||||
>
|
>
|
||||||
<div styleName='header'>
|
<div styleName='header'>
|
||||||
<div styleName='title'>{i18n.__('Make a note')}</div>
|
<div styleName='title'>{i18n.__('Make a note')}</div>
|
||||||
</div>
|
</div>
|
||||||
<ModalEscButton handleEscButtonClick={(e) => this.handleCloseButtonClick(e)} />
|
<ModalEscButton
|
||||||
|
handleEscButtonClick={e => this.handleCloseButtonClick(e)}
|
||||||
|
/>
|
||||||
<div styleName='control'>
|
<div styleName='control'>
|
||||||
<button styleName='control-button'
|
<button
|
||||||
onClick={(e) => this.handleMarkdownNoteButtonClick(e)}
|
styleName='control-button'
|
||||||
onKeyDown={(e) => this.handleMarkdownNoteButtonKeyDown(e)}
|
onClick={e => this.handleMarkdownNoteButtonClick(e)}
|
||||||
|
onKeyDown={e => this.handleMarkdownNoteButtonKeyDown(e)}
|
||||||
ref='markdownButton'
|
ref='markdownButton'
|
||||||
>
|
>
|
||||||
<i styleName='control-button-icon'
|
<i styleName='control-button-icon' className='fa fa-file-text-o' />
|
||||||
className='fa fa-file-text-o'
|
<br />
|
||||||
/><br />
|
<span styleName='control-button-label'>
|
||||||
<span styleName='control-button-label'>{i18n.__('Markdown Note')}</span><br />
|
{i18n.__('Markdown Note')}
|
||||||
<span styleName='control-button-description'>{i18n.__('This format is for creating text documents. Checklists, code blocks and Latex blocks are available.')}</span>
|
</span>
|
||||||
|
<br />
|
||||||
|
<span styleName='control-button-description'>
|
||||||
|
{i18n.__(
|
||||||
|
'This format is for creating text documents. Checklists, code blocks and Latex blocks are available.'
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button styleName='control-button'
|
<button
|
||||||
onClick={(e) => this.handleSnippetNoteButtonClick(e)}
|
styleName='control-button'
|
||||||
onKeyDown={(e) => this.handleSnippetNoteButtonKeyDown(e)}
|
onClick={e => this.handleSnippetNoteButtonClick(e)}
|
||||||
|
onKeyDown={e => this.handleSnippetNoteButtonKeyDown(e)}
|
||||||
ref='snippetButton'
|
ref='snippetButton'
|
||||||
>
|
>
|
||||||
<i styleName='control-button-icon'
|
<i styleName='control-button-icon' className='fa fa-code' /><br />
|
||||||
className='fa fa-code'
|
<span styleName='control-button-label'>
|
||||||
/><br />
|
{i18n.__('Snippet Note')}
|
||||||
<span styleName='control-button-label'>{i18n.__('Snippet Note')}</span><br />
|
</span>
|
||||||
<span styleName='control-button-description'>{i18n.__('This format is for creating code snippets. Multiple snippets can be grouped into a single note.')}
|
<br />
|
||||||
|
<span styleName='control-button-description'>
|
||||||
|
{i18n.__(
|
||||||
|
'This format is for creating code snippets. Multiple snippets can be grouped into a single note.'
|
||||||
|
)}
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
<div styleName='description'><i className='fa fa-arrows-h' />{i18n.__('Tab to switch format')}</div>
|
<div styleName='description'>
|
||||||
|
<i className='fa fa-arrows-h' />{i18n.__('Tab to switch format')}
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
NewNoteModal.propTypes = {
|
NewNoteModal.propTypes = {}
|
||||||
}
|
|
||||||
|
|
||||||
export default CSSModules(NewNoteModal, styles)
|
export default CSSModules(NewNoteModal, styles)
|
||||||
|
|||||||
@@ -27,7 +27,12 @@ class SnippetEditor extends React.Component {
|
|||||||
dragDrop: false,
|
dragDrop: false,
|
||||||
foldGutter: true,
|
foldGutter: true,
|
||||||
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
|
||||||
autoCloseBrackets: true,
|
autoCloseBrackets: {
|
||||||
|
pairs: '()[]{}\'\'""$$**``',
|
||||||
|
triples: '```"""\'\'\'',
|
||||||
|
explode: '[]{}``$$',
|
||||||
|
override: true
|
||||||
|
},
|
||||||
mode: 'null'
|
mode: 'null'
|
||||||
})
|
})
|
||||||
this.cm.setSize('100%', '100%')
|
this.cm.setSize('100%', '100%')
|
||||||
|
|||||||
@@ -4,8 +4,7 @@ import CSSModules from 'browser/lib/CSSModules'
|
|||||||
import dataApi from 'browser/main/lib/dataApi'
|
import dataApi from 'browser/main/lib/dataApi'
|
||||||
import i18n from 'browser/lib/i18n'
|
import i18n from 'browser/lib/i18n'
|
||||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||||
const { remote } = require('electron')
|
import context from 'browser/lib/context'
|
||||||
const { Menu, MenuItem } = remote
|
|
||||||
|
|
||||||
class SnippetList extends React.Component {
|
class SnippetList extends React.Component {
|
||||||
constructor (props) {
|
constructor (props) {
|
||||||
@@ -21,18 +20,17 @@ class SnippetList extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
reloadSnippetList () {
|
reloadSnippetList () {
|
||||||
dataApi.fetchSnippet().then(snippets => this.setState({snippets}))
|
dataApi.fetchSnippet().then(snippets => {
|
||||||
|
this.setState({snippets})
|
||||||
|
this.props.onSnippetSelect(snippets[0])
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSnippetContextMenu (snippet) {
|
handleSnippetContextMenu (snippet) {
|
||||||
const menu = new Menu()
|
context.popup([{
|
||||||
menu.append(new MenuItem({
|
|
||||||
label: i18n.__('Delete snippet'),
|
label: i18n.__('Delete snippet'),
|
||||||
click: () => {
|
click: () => this.deleteSnippet(snippet)
|
||||||
this.deleteSnippet(snippet)
|
}])
|
||||||
}
|
|
||||||
}))
|
|
||||||
menu.popup()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
deleteSnippet (snippet) {
|
deleteSnippet (snippet) {
|
||||||
@@ -43,7 +41,7 @@ class SnippetList extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handleSnippetClick (snippet) {
|
handleSnippetClick (snippet) {
|
||||||
this.props.onSnippetClick(snippet)
|
this.props.onSnippetSelect(snippet)
|
||||||
}
|
}
|
||||||
|
|
||||||
createSnippet () {
|
createSnippet () {
|
||||||
@@ -55,6 +53,16 @@ class SnippetList extends React.Component {
|
|||||||
}).catch(err => { throw err })
|
}).catch(err => { throw err })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defineSnippetStyleName (snippet) {
|
||||||
|
const { currentSnippet } = this.props
|
||||||
|
if (currentSnippet == null) return
|
||||||
|
if (currentSnippet.id === snippet.id) {
|
||||||
|
return 'snippet-item-selected'
|
||||||
|
} else {
|
||||||
|
return 'snippet-item'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { snippets } = this.state
|
const { snippets } = this.state
|
||||||
return (
|
return (
|
||||||
@@ -70,7 +78,7 @@ class SnippetList extends React.Component {
|
|||||||
{
|
{
|
||||||
snippets.map((snippet) => (
|
snippets.map((snippet) => (
|
||||||
<li
|
<li
|
||||||
styleName='snippet-item'
|
styleName={this.defineSnippetStyleName(snippet)}
|
||||||
key={snippet.id}
|
key={snippet.id}
|
||||||
onContextMenu={() => this.handleSnippetContextMenu(snippet)}
|
onContextMenu={() => this.handleSnippetContextMenu(snippet)}
|
||||||
onClick={() => this.handleSnippetClick(snippet)}>
|
onClick={() => this.handleSnippetClick(snippet)}>
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ class SnippetTab extends React.Component {
|
|||||||
}, 500)
|
}, 500)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleSnippetClick (snippet) {
|
handleSnippetSelect (snippet) {
|
||||||
const { currentSnippet } = this.state
|
const { currentSnippet } = this.state
|
||||||
if (currentSnippet === null || currentSnippet.id !== snippet.id) {
|
if (currentSnippet === null || currentSnippet.id !== snippet.id) {
|
||||||
dataApi.fetchSnippet(snippet.id).then(changedSnippet => {
|
dataApi.fetchSnippet(snippet.id).then(changedSnippet => {
|
||||||
@@ -66,8 +66,9 @@ class SnippetTab extends React.Component {
|
|||||||
<div styleName='root'>
|
<div styleName='root'>
|
||||||
<div styleName='header'>{i18n.__('Snippets')}</div>
|
<div styleName='header'>{i18n.__('Snippets')}</div>
|
||||||
<SnippetList
|
<SnippetList
|
||||||
onSnippetClick={this.handleSnippetClick.bind(this)}
|
onSnippetSelect={this.handleSnippetSelect.bind(this)}
|
||||||
onSnippetDeleted={this.handleDeleteSnippet.bind(this)} />
|
onSnippetDeleted={this.handleDeleteSnippet.bind(this)}
|
||||||
|
currentSnippet={currentSnippet} />
|
||||||
<div styleName='snippet-detail' style={{visibility: currentSnippet ? 'visible' : 'hidden'}}>
|
<div styleName='snippet-detail' style={{visibility: currentSnippet ? 'visible' : 'hidden'}}>
|
||||||
<div styleName='group-section'>
|
<div styleName='group-section'>
|
||||||
<div styleName='group-section-label'>{i18n.__('Snippet name')}</div>
|
<div styleName='group-section-label'>{i18n.__('Snippet name')}</div>
|
||||||
|
|||||||
@@ -122,6 +122,10 @@
|
|||||||
&:hover
|
&:hover
|
||||||
background darken(#f5f5f5, 5)
|
background darken(#f5f5f5, 5)
|
||||||
|
|
||||||
|
.snippet-item-selected
|
||||||
|
@extend .snippet-list .snippet-item
|
||||||
|
background darken(#f5f5f5, 5)
|
||||||
|
|
||||||
.snippet-detail
|
.snippet-detail
|
||||||
width 70%
|
width 70%
|
||||||
height calc(100% - 200px)
|
height calc(100% - 200px)
|
||||||
@@ -142,6 +146,8 @@ body[data-theme="default"], body[data-theme="white"]
|
|||||||
background $ui-borderColor
|
background $ui-borderColor
|
||||||
&:hover
|
&:hover
|
||||||
background darken($ui-backgroundColor, 5)
|
background darken($ui-backgroundColor, 5)
|
||||||
|
.snippet-item-selected
|
||||||
|
background darken($ui-backgroundColor, 5)
|
||||||
|
|
||||||
body[data-theme="dark"]
|
body[data-theme="dark"]
|
||||||
.snippets
|
.snippets
|
||||||
@@ -152,8 +158,12 @@ body[data-theme="dark"]
|
|||||||
background $ui-dark-borderColor
|
background $ui-dark-borderColor
|
||||||
&:hover
|
&:hover
|
||||||
background darken($ui-dark-backgroundColor, 5)
|
background darken($ui-dark-backgroundColor, 5)
|
||||||
|
.snippet-item-selected
|
||||||
|
background darken($ui-dark-backgroundColor, 5)
|
||||||
.snippet-detail
|
.snippet-detail
|
||||||
color white
|
color white
|
||||||
|
.group-control-button
|
||||||
|
colorDarkPrimaryButton()
|
||||||
|
|
||||||
body[data-theme="solarized-dark"]
|
body[data-theme="solarized-dark"]
|
||||||
.snippets
|
.snippets
|
||||||
@@ -164,8 +174,12 @@ body[data-theme="solarized-dark"]
|
|||||||
background $ui-solarized-dark-borderColor
|
background $ui-solarized-dark-borderColor
|
||||||
&:hover
|
&:hover
|
||||||
background darken($ui-solarized-dark-backgroundColor, 5)
|
background darken($ui-solarized-dark-backgroundColor, 5)
|
||||||
|
.snippet-item-selected
|
||||||
|
background darken($ui-solarized-dark-backgroundColor, 5)
|
||||||
.snippet-detail
|
.snippet-detail
|
||||||
color white
|
color white
|
||||||
|
.group-control-button
|
||||||
|
colorSolarizedDarkPrimaryButton()
|
||||||
|
|
||||||
body[data-theme="monokai"]
|
body[data-theme="monokai"]
|
||||||
.snippets
|
.snippets
|
||||||
@@ -176,5 +190,9 @@ body[data-theme="monokai"]
|
|||||||
background $ui-monokai-borderColor
|
background $ui-monokai-borderColor
|
||||||
&:hover
|
&:hover
|
||||||
background darken($ui-monokai-backgroundColor, 5)
|
background darken($ui-monokai-backgroundColor, 5)
|
||||||
|
.snippet-item-selected
|
||||||
|
background darken($ui-monokai-backgroundColor, 5)
|
||||||
.snippet-detail
|
.snippet-detail
|
||||||
color white
|
color white
|
||||||
|
.group-control-button
|
||||||
|
colorMonokaiPrimaryButton()
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import 'codemirror-mode-elixir'
|
|||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import i18n from 'browser/lib/i18n'
|
import i18n from 'browser/lib/i18n'
|
||||||
import { getLanguages } from 'browser/lib/Languages'
|
import { getLanguages } from 'browser/lib/Languages'
|
||||||
|
import normalizeEditorFontFamily from 'browser/lib/normalizeEditorFontFamily'
|
||||||
|
|
||||||
const OSX = global.process.platform === 'darwin'
|
const OSX = global.process.platform === 'darwin'
|
||||||
|
|
||||||
@@ -164,7 +165,7 @@ class UiTab extends React.Component {
|
|||||||
const { config, codemirrorTheme } = this.state
|
const { config, codemirrorTheme } = this.state
|
||||||
const codemirrorSampleCode = 'function iamHappy (happy) {\n\tif (happy) {\n\t console.log("I am Happy!")\n\t} else {\n\t console.log("I am not Happy!")\n\t}\n};'
|
const codemirrorSampleCode = 'function iamHappy (happy) {\n\tif (happy) {\n\t console.log("I am Happy!")\n\t} else {\n\t console.log("I am not Happy!")\n\t}\n};'
|
||||||
const enableEditRulersStyle = config.editor.enableRulers ? 'block' : 'none'
|
const enableEditRulersStyle = config.editor.enableRulers ? 'block' : 'none'
|
||||||
const customCSS = config.preview.customCSS
|
const fontFamily = normalizeEditorFontFamily(config.editor.fontFamily)
|
||||||
return (
|
return (
|
||||||
<div styleName='root'>
|
<div styleName='root'>
|
||||||
<div styleName='group'>
|
<div styleName='group'>
|
||||||
@@ -262,8 +263,16 @@ class UiTab extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
</select>
|
</select>
|
||||||
<div styleName='code-mirror'>
|
<div styleName='code-mirror' style={{fontFamily}}>
|
||||||
<ReactCodeMirror ref={e => (this.codeMirrorInstance = e)} value={codemirrorSampleCode} options={{ lineNumbers: true, readOnly: true, mode: 'javascript', theme: codemirrorTheme }} />
|
<ReactCodeMirror
|
||||||
|
ref={e => (this.codeMirrorInstance = e)}
|
||||||
|
value={codemirrorSampleCode}
|
||||||
|
options={{
|
||||||
|
lineNumbers: true,
|
||||||
|
readOnly: true,
|
||||||
|
mode: 'javascript',
|
||||||
|
theme: codemirrorTheme
|
||||||
|
}} />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -596,7 +605,19 @@ class UiTab extends React.Component {
|
|||||||
type='checkbox'
|
type='checkbox'
|
||||||
/>
|
/>
|
||||||
{i18n.__('Allow custom CSS for preview')}
|
{i18n.__('Allow custom CSS for preview')}
|
||||||
<ReactCodeMirror onChange={e => this.handleUIChange(e)} ref={e => (this.customCSSCM = e)} value={config.preview.customCSS} options={{ lineNumbers: true, mode: 'css', theme: codemirrorTheme }} />
|
<div style={{fontFamily}}>
|
||||||
|
<ReactCodeMirror
|
||||||
|
width='400px'
|
||||||
|
height='400px'
|
||||||
|
onChange={e => this.handleUIChange(e)}
|
||||||
|
ref={e => (this.customCSSCM = e)}
|
||||||
|
value={config.preview.customCSS}
|
||||||
|
options={{
|
||||||
|
lineNumbers: true,
|
||||||
|
mode: 'css',
|
||||||
|
theme: codemirrorTheme
|
||||||
|
}} />
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|||||||
@@ -360,6 +360,12 @@ function data (state = defaultDataMap(), action) {
|
|||||||
state.storageMap = new Map(state.storageMap)
|
state.storageMap = new Map(state.storageMap)
|
||||||
state.storageMap.set(action.storage.key, action.storage)
|
state.storageMap.set(action.storage.key, action.storage)
|
||||||
return state
|
return state
|
||||||
|
case 'EXPAND_STORAGE':
|
||||||
|
state = Object.assign({}, state)
|
||||||
|
state.storageMap = new Map(state.storageMap)
|
||||||
|
action.storage.isOpen = action.isOpen
|
||||||
|
state.storageMap.set(action.storage.key, action.storage)
|
||||||
|
return state
|
||||||
}
|
}
|
||||||
return state
|
return state
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -136,6 +136,15 @@ const file = {
|
|||||||
{
|
{
|
||||||
type: 'separator'
|
type: 'separator'
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
label: 'Format Table',
|
||||||
|
click () {
|
||||||
|
mainWindow.webContents.send('code:format-table')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
label: 'Print',
|
label: 'Print',
|
||||||
accelerator: 'CommandOrControl+P',
|
accelerator: 'CommandOrControl+P',
|
||||||
@@ -235,14 +244,14 @@ const view = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Next Note',
|
label: 'Next Note',
|
||||||
accelerator: 'Control+J',
|
accelerator: 'CommandOrControl+]',
|
||||||
click () {
|
click () {
|
||||||
mainWindow.webContents.send('list:next')
|
mainWindow.webContents.send('list:next')
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Previous Note',
|
label: 'Previous Note',
|
||||||
accelerator: 'Control+K',
|
accelerator: 'CommandOrControl+[',
|
||||||
click () {
|
click () {
|
||||||
mainWindow.webContents.send('list:prior')
|
mainWindow.webContents.send('list:prior')
|
||||||
}
|
}
|
||||||
@@ -267,6 +276,19 @@ const view = {
|
|||||||
mainWindow.setFullScreen(!mainWindow.isFullScreen())
|
mainWindow.setFullScreen(!mainWindow.isFullScreen())
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Toggle Side Bar',
|
||||||
|
accelerator: 'CommandOrControl+B',
|
||||||
|
click () {
|
||||||
|
mainWindow.webContents.send('editor:fullscreen')
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
{
|
{
|
||||||
role: 'zoomin',
|
role: 'zoomin',
|
||||||
accelerator: macOS ? 'CommandOrControl+Plus' : 'Control+='
|
accelerator: macOS ? 'CommandOrControl+Plus' : 'Control+='
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "boost",
|
"name": "boost",
|
||||||
"productName": "Boostnote",
|
"productName": "Boostnote",
|
||||||
"version": "0.11.7",
|
"version": "0.11.8",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"description": "Boostnote",
|
"description": "Boostnote",
|
||||||
"license": "GPL-3.0",
|
"license": "GPL-3.0",
|
||||||
@@ -51,9 +51,11 @@
|
|||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@rokt33r/markdown-it-math": "^4.0.1",
|
"@rokt33r/markdown-it-math": "^4.0.1",
|
||||||
"@rokt33r/season": "^5.3.0",
|
"@rokt33r/season": "^5.3.0",
|
||||||
|
"@susisu/mte-kernel": "^2.0.0",
|
||||||
"aws-sdk": "^2.48.0",
|
"aws-sdk": "^2.48.0",
|
||||||
"aws-sdk-mobile-analytics": "^0.9.2",
|
"aws-sdk-mobile-analytics": "^0.9.2",
|
||||||
"codemirror": "^5.37.0",
|
"chart.js": "^2.7.2",
|
||||||
|
"codemirror": "^5.39.0",
|
||||||
"codemirror-mode-elixir": "^1.1.1",
|
"codemirror-mode-elixir": "^1.1.1",
|
||||||
"electron-config": "^0.2.1",
|
"electron-config": "^0.2.1",
|
||||||
"electron-gh-releases": "^2.0.2",
|
"electron-gh-releases": "^2.0.2",
|
||||||
@@ -81,6 +83,7 @@
|
|||||||
"markdown-it-plantuml": "^1.1.0",
|
"markdown-it-plantuml": "^1.1.0",
|
||||||
"markdown-it-smartarrows": "^1.0.1",
|
"markdown-it-smartarrows": "^1.0.1",
|
||||||
"mdurl": "^1.0.1",
|
"mdurl": "^1.0.1",
|
||||||
|
"mermaid": "^8.0.0-rc.8",
|
||||||
"moment": "^2.10.3",
|
"moment": "^2.10.3",
|
||||||
"mousetrap": "^1.6.1",
|
"mousetrap": "^1.6.1",
|
||||||
"mousetrap-global-bind": "^1.1.0",
|
"mousetrap-global-bind": "^1.1.0",
|
||||||
|
|||||||
10
readme.md
10
readme.md
@@ -1,4 +1,4 @@
|
|||||||
:mega: We've launched [Boostnote Bounty Program](http://bit.ly/2I5Tpik).
|
:mega: The Boostnote team launches [IssueHunt](https://issuehunt.io/) for sustainable open-source ecosystem.
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
@@ -19,13 +19,15 @@ Thank you to all the people who already contributed to Boostnote!
|
|||||||
<a href="https://github.com/BoostIO/Boostnote/graphs/contributors"><img src="https://opencollective.com/boostnoteio/contributors.svg?width=890" /></a>
|
<a href="https://github.com/BoostIO/Boostnote/graphs/contributors"><img src="https://opencollective.com/boostnoteio/contributors.svg?width=890" /></a>
|
||||||
|
|
||||||
## Supporting Boostnote
|
## Supporting Boostnote
|
||||||
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](https://github.com/BoostIO/Boostnote/blob/master/Backers.md). If you'd like to join them, please consider:
|
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.
|
||||||
- [Become a backer or sponsor on Open Collective.](https://opencollective.com/boostnoteio)
|
|
||||||
|
Any issues on Boostnote can be funded by anyone and that money will be distributed to contributors and maintainers. If you'd like to join them, please consider:
|
||||||
|
- [Become a backer on IssueHunt](https://issuehunt.io/repos/53266139).
|
||||||
|
|
||||||
## Community
|
## Community
|
||||||
- [Facebook Group](https://www.facebook.com/groups/boostnote/)
|
- [Facebook Group](https://www.facebook.com/groups/boostnote/)
|
||||||
- [Twitter](https://twitter.com/boostnoteapp)
|
- [Twitter](https://twitter.com/boostnoteapp)
|
||||||
- [Slack Group](https://join.slack.com/t/boostnote-group/shared_invite/enQtMzcwNDU3NDU3ODI0LTU1ZDgwZDNiZTNmN2RhOTY4OTM5ODY0ODUzMTRiNmQ0ZDMzZDRiYzg2YmQ5ZDYzZTQxYjMxYzBlNTM4NjcyYjM)
|
- [Slack Group](https://join.slack.com/t/boostnote-group/shared_invite/enQtMzkxOTk4ODkyNzc0LThkNmMzY2VlZjVhYTNiYjE5YjQyZGVjNTJlYTY1OGMyZTFjNGU5YTUyYjUzOWZhYTU4OTVlNDYyNDFjYWMzNDM)
|
||||||
- [Blog](https://boostlog.io/tags/boostnote)
|
- [Blog](https://boostlog.io/tags/boostnote)
|
||||||
- [Reddit](https://www.reddit.com/r/Boostnote/)
|
- [Reddit](https://www.reddit.com/r/Boostnote/)
|
||||||
|
|
||||||
|
|||||||
@@ -169,6 +169,43 @@ it('should replace the all ":storage" path with the actual storage path', functi
|
|||||||
expect(actual).toEqual(expectedOutput)
|
expect(actual).toEqual(expectedOutput)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should replace the ":storage" path with the actual storage path when they have different path separators', function () {
|
||||||
|
const storageFolder = systemUnderTest.DESTINATION_FOLDER
|
||||||
|
const testInput =
|
||||||
|
'<html>\n' +
|
||||||
|
' <head>\n' +
|
||||||
|
' //header\n' +
|
||||||
|
' </head>\n' +
|
||||||
|
' <body data-theme="default">\n' +
|
||||||
|
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
|
||||||
|
' <p data-line="2">\n' +
|
||||||
|
' <img src=":storage' + mdurl.encode(path.win32.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
|
||||||
|
' </p>\n' +
|
||||||
|
' <p data-line="4">\n' +
|
||||||
|
' <a href=":storage' + mdurl.encode(path.posix.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
|
||||||
|
' </p>\n' +
|
||||||
|
' </body>\n' +
|
||||||
|
'</html>'
|
||||||
|
const storagePath = '<<dummyStoragePath>>'
|
||||||
|
const expectedOutput =
|
||||||
|
'<html>\n' +
|
||||||
|
' <head>\n' +
|
||||||
|
' //header\n' +
|
||||||
|
' </head>\n' +
|
||||||
|
' <body data-theme="default">\n' +
|
||||||
|
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
|
||||||
|
' <p data-line="2">\n' +
|
||||||
|
' <img src="file:///' + storagePath + path.sep + storageFolder + path.sep + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
|
||||||
|
' </p>\n' +
|
||||||
|
' <p data-line="4">\n' +
|
||||||
|
' <a href="file:///' + storagePath + path.sep + storageFolder + path.sep + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
|
||||||
|
' </p>\n' +
|
||||||
|
' </body>\n' +
|
||||||
|
'</html>'
|
||||||
|
const actual = systemUnderTest.fixLocalURLS(testInput, storagePath)
|
||||||
|
expect(actual).toEqual(expectedOutput)
|
||||||
|
})
|
||||||
|
|
||||||
it('should test that generateAttachmentMarkdown works correct both with previews and without', function () {
|
it('should test that generateAttachmentMarkdown works correct both with previews and without', function () {
|
||||||
const fileName = 'fileName'
|
const fileName = 'fileName'
|
||||||
const path = 'path'
|
const path = 'path'
|
||||||
@@ -180,27 +217,35 @@ it('should test that generateAttachmentMarkdown works correct both with previews
|
|||||||
expect(actual).toEqual(expected)
|
expect(actual).toEqual(expected)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('should test that getAttachmentsInContent finds all attachments', function () {
|
it('should test that migrateAttachments work when they have different path separators', function () {
|
||||||
const testInput =
|
sander.existsSync = jest.fn(() => true)
|
||||||
'<html>\n' +
|
const dummyStoragePath = 'dummyStoragePath'
|
||||||
' <head>\n' +
|
const imagesPath = path.join(dummyStoragePath, 'images')
|
||||||
' //header\n' +
|
const attachmentsPath = path.join(dummyStoragePath, 'attachments')
|
||||||
' </head>\n' +
|
const noteKey = 'noteKey'
|
||||||
' <body data-theme="default">\n' +
|
const testInput = '"# Test\n' +
|
||||||
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
|
'\n' +
|
||||||
' <p data-line="2">\n' +
|
'\n' +
|
||||||
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
|
'"'
|
||||||
' </p>\n' +
|
|
||||||
' <p data-line="4">\n' +
|
systemUnderTest.migrateAttachments(testInput, dummyStoragePath, noteKey)
|
||||||
' <a href=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
|
|
||||||
' </p>\n' +
|
expect(sander.existsSync.mock.calls[0][0]).toBe(imagesPath)
|
||||||
' <p data-line="6">\n' +
|
expect(sander.existsSync.mock.calls[1][0]).toBe(path.join(imagesPath, '0.3b88d0dc.png'))
|
||||||
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
|
expect(sander.existsSync.mock.calls[2][0]).toBe(path.join(attachmentsPath, '0.3b88d0dc.png'))
|
||||||
' </p>\n' +
|
expect(sander.existsSync.mock.calls[3][0]).toBe(path.join(imagesPath, '0.2cb8875c.pdf'))
|
||||||
' </body>\n' +
|
expect(sander.existsSync.mock.calls[4][0]).toBe(path.join(attachmentsPath, '0.2cb8875c.pdf'))
|
||||||
'</html>'
|
})
|
||||||
const actual = systemUnderTest.getAttachmentsInContent(testInput)
|
|
||||||
const expected = [':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.6r4zdgc22xp.png', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.q2i4iw0fyx.pdf', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + 'd6c5ee92.jpg']
|
it('should test that getAttachmentsInMarkdownContent finds all attachments when they have different path separators', function () {
|
||||||
|
const testInput = '"# Test\n' +
|
||||||
|
'\n' +
|
||||||
|
'\n' +
|
||||||
|
'\n' +
|
||||||
|
'"'
|
||||||
|
|
||||||
|
const actual = systemUnderTest.getAttachmentsInMarkdownContent(testInput)
|
||||||
|
const expected = [':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.3b88d0dc.png', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '2cb8875c.pdf', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + 'bbf49b02.jpg']
|
||||||
expect(actual).toEqual(expect.arrayContaining(expected))
|
expect(actual).toEqual(expect.arrayContaining(expected))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|||||||
38
tests/dataApi/toggleStorage-test.js
Normal file
38
tests/dataApi/toggleStorage-test.js
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
const test = require('ava')
|
||||||
|
const toggleStorage = require('browser/main/lib/dataApi/toggleStorage')
|
||||||
|
|
||||||
|
global.document = require('jsdom').jsdom('<body></body>')
|
||||||
|
global.window = document.defaultView
|
||||||
|
global.navigator = window.navigator
|
||||||
|
|
||||||
|
const Storage = require('dom-storage')
|
||||||
|
const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true })
|
||||||
|
const path = require('path')
|
||||||
|
const _ = require('lodash')
|
||||||
|
const TestDummy = require('../fixtures/TestDummy')
|
||||||
|
const sander = require('sander')
|
||||||
|
const os = require('os')
|
||||||
|
|
||||||
|
const storagePath = path.join(os.tmpdir(), 'test/toggle-storage')
|
||||||
|
|
||||||
|
test.beforeEach((t) => {
|
||||||
|
t.context.storage = TestDummy.dummyStorage(storagePath)
|
||||||
|
localStorage.setItem('storages', JSON.stringify([t.context.storage.cache]))
|
||||||
|
})
|
||||||
|
|
||||||
|
test.serial('Toggle a storage location', (t) => {
|
||||||
|
const storageKey = t.context.storage.cache.key
|
||||||
|
return Promise.resolve()
|
||||||
|
.then(function doTest () {
|
||||||
|
return toggleStorage(storageKey, true)
|
||||||
|
})
|
||||||
|
.then(function assert (data) {
|
||||||
|
const cachedStorageList = JSON.parse(localStorage.getItem('storages'))
|
||||||
|
t.true(_.find(cachedStorageList, {key: storageKey}).isOpen === true)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
test.after(function after () {
|
||||||
|
localStorage.clear()
|
||||||
|
sander.rimrafSync(storagePath)
|
||||||
|
})
|
||||||
48
tests/lib/escapeHtmlCharacters-test.js
Normal file
48
tests/lib/escapeHtmlCharacters-test.js
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
const { escapeHtmlCharacters } = require('browser/lib/utils')
|
||||||
|
const test = require('ava')
|
||||||
|
|
||||||
|
test('escapeHtmlCharacters should return the original string if nothing needed to escape', t => {
|
||||||
|
const input = 'Nothing to be escaped'
|
||||||
|
const expected = 'Nothing to be escaped'
|
||||||
|
const actual = escapeHtmlCharacters(input)
|
||||||
|
t.is(actual, expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('escapeHtmlCharacters should skip code block if that option is enabled', t => {
|
||||||
|
const input = ` <no escape>
|
||||||
|
<escapeMe>`
|
||||||
|
const expected = ` <no escape>
|
||||||
|
<escapeMe>`
|
||||||
|
const actual = escapeHtmlCharacters(input, { detectCodeBlock: true })
|
||||||
|
t.is(actual, expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('escapeHtmlCharacters should NOT skip character not in code block but start with 4 spaces', t => {
|
||||||
|
const input = '4 spaces &'
|
||||||
|
const expected = '4 spaces &'
|
||||||
|
const actual = escapeHtmlCharacters(input, { detectCodeBlock: true })
|
||||||
|
t.is(actual, expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('escapeHtmlCharacters should NOT skip code block if that option is NOT enabled', t => {
|
||||||
|
const input = ` <no escape>
|
||||||
|
<escapeMe>`
|
||||||
|
const expected = ` <no escape>
|
||||||
|
<escapeMe>`
|
||||||
|
const actual = escapeHtmlCharacters(input)
|
||||||
|
t.is(actual, expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('escapeHtmlCharacters should NOT escape & character if it\'s a part of an escaped character', t => {
|
||||||
|
const input = 'Do not escape & or " but do escape &'
|
||||||
|
const expected = 'Do not escape & or " but do escape &'
|
||||||
|
const actual = escapeHtmlCharacters(input)
|
||||||
|
t.is(actual, expected)
|
||||||
|
})
|
||||||
|
|
||||||
|
test('escapeHtmlCharacters should return the correct result', t => {
|
||||||
|
const input = '& < > " \''
|
||||||
|
const expected = '& < > " ''
|
||||||
|
const actual = escapeHtmlCharacters(input)
|
||||||
|
t.is(actual, expected)
|
||||||
|
})
|
||||||
16
tests/lib/normalize-editor-font-family-test.js
Normal file
16
tests/lib/normalize-editor-font-family-test.js
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
/**
|
||||||
|
* @fileoverview Unit test for browser/lib/normalizeEditorFontFamily
|
||||||
|
*/
|
||||||
|
import test from 'ava'
|
||||||
|
import normalizeEditorFontFamily from '../../browser/lib/normalizeEditorFontFamily'
|
||||||
|
import consts from '../../browser/lib/consts'
|
||||||
|
const defaultEditorFontFamily = consts.DEFAULT_EDITOR_FONT_FAMILY
|
||||||
|
|
||||||
|
test('normalizeEditorFontFamily() should return default font family (string[])', t => {
|
||||||
|
t.is(normalizeEditorFontFamily(), defaultEditorFontFamily.join(', '))
|
||||||
|
})
|
||||||
|
|
||||||
|
test('normalizeEditorFontFamily(["hoge", "huga"]) should return default font family connected with arg.', t => {
|
||||||
|
const arg = 'font1, font2'
|
||||||
|
t.is(normalizeEditorFontFamily(arg), `${arg}, ${defaultEditorFontFamily.join(', ')}`)
|
||||||
|
})
|
||||||
333
yarn.lock
333
yarn.lock
@@ -79,6 +79,12 @@
|
|||||||
fs-plus "2.x"
|
fs-plus "2.x"
|
||||||
optimist "~0.4.0"
|
optimist "~0.4.0"
|
||||||
|
|
||||||
|
"@susisu/mte-kernel@^2.0.0":
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/@susisu/mte-kernel/-/mte-kernel-2.0.0.tgz#da3354d6a07ea27f36ec91d9fccf6bfa9010d00e"
|
||||||
|
dependencies:
|
||||||
|
meaw "^2.0.0"
|
||||||
|
|
||||||
"@types/node@^8.0.24":
|
"@types/node@^8.0.24":
|
||||||
version "8.10.17"
|
version "8.10.17"
|
||||||
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.17.tgz#d48cf10f0dc6dcf59f827f5a3fc7a4a6004318d3"
|
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.17.tgz#d48cf10f0dc6dcf59f827f5a3fc7a4a6004318d3"
|
||||||
@@ -1574,6 +1580,26 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1:
|
|||||||
escape-string-regexp "^1.0.5"
|
escape-string-regexp "^1.0.5"
|
||||||
supports-color "^5.3.0"
|
supports-color "^5.3.0"
|
||||||
|
|
||||||
|
chart.js@^2.7.2:
|
||||||
|
version "2.7.2"
|
||||||
|
resolved "http://registry.npm.taobao.org/chart.js/download/chart.js-2.7.2.tgz#3c9fde4dc5b95608211bdefeda7e5d33dffa5714"
|
||||||
|
dependencies:
|
||||||
|
chartjs-color "^2.1.0"
|
||||||
|
moment "^2.10.2"
|
||||||
|
|
||||||
|
chartjs-color-string@^0.5.0:
|
||||||
|
version "0.5.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/chartjs-color-string/download/chartjs-color-string-0.5.0.tgz#8d3752d8581d86687c35bfe2cb80ac5213ceb8c1"
|
||||||
|
dependencies:
|
||||||
|
color-name "^1.0.0"
|
||||||
|
|
||||||
|
chartjs-color@^2.1.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/chartjs-color/download/chartjs-color-2.2.0.tgz#84a2fb755787ed85c39dd6dd8c7b1d88429baeae"
|
||||||
|
dependencies:
|
||||||
|
chartjs-color-string "^0.5.0"
|
||||||
|
color-convert "^0.5.3"
|
||||||
|
|
||||||
chokidar@^1.0.0, chokidar@^1.4.2:
|
chokidar@^1.0.0, chokidar@^1.4.2:
|
||||||
version "1.7.0"
|
version "1.7.0"
|
||||||
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
|
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-1.7.0.tgz#798e689778151c8076b4b360e5edd28cda2bb468"
|
||||||
@@ -1727,10 +1753,14 @@ codemirror-mode-elixir@^1.1.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
codemirror "^5.20.2"
|
codemirror "^5.20.2"
|
||||||
|
|
||||||
codemirror@^5.18.2, codemirror@^5.20.2, codemirror@^5.37.0:
|
codemirror@^5.18.2, codemirror@^5.20.2:
|
||||||
version "5.38.0"
|
version "5.38.0"
|
||||||
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.38.0.tgz#26a9551446e51dbdde36aabe60f72469724fd332"
|
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.38.0.tgz#26a9551446e51dbdde36aabe60f72469724fd332"
|
||||||
|
|
||||||
|
codemirror@^5.39.0:
|
||||||
|
version "5.39.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/codemirror/-/codemirror-5.39.0.tgz#4654f7d2f7e525e04a62e72d9482348ccb37dce5"
|
||||||
|
|
||||||
coffee-script@^1.10.0:
|
coffee-script@^1.10.0:
|
||||||
version "1.12.7"
|
version "1.12.7"
|
||||||
resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.7.tgz#c05dae0cb79591d05b3070a8433a98c9a89ccc53"
|
resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.7.tgz#c05dae0cb79591d05b3070a8433a98c9a89ccc53"
|
||||||
@@ -1746,6 +1776,10 @@ collection-visit@^1.0.0:
|
|||||||
map-visit "^1.0.0"
|
map-visit "^1.0.0"
|
||||||
object-visit "^1.0.0"
|
object-visit "^1.0.0"
|
||||||
|
|
||||||
|
color-convert@^0.5.3:
|
||||||
|
version "0.5.3"
|
||||||
|
resolved "http://registry.npm.taobao.org/color-convert/download/color-convert-0.5.3.tgz#bdb6c69ce660fadffe0b0007cc447e1b9f7282bd"
|
||||||
|
|
||||||
color-convert@^1.3.0, color-convert@^1.9.0:
|
color-convert@^1.3.0, color-convert@^1.9.0:
|
||||||
version "1.9.1"
|
version "1.9.1"
|
||||||
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed"
|
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed"
|
||||||
@@ -1802,6 +1836,10 @@ combined-stream@~0.0.4, combined-stream@~0.0.5:
|
|||||||
dependencies:
|
dependencies:
|
||||||
delayed-stream "0.0.5"
|
delayed-stream "0.0.5"
|
||||||
|
|
||||||
|
commander@2:
|
||||||
|
version "2.16.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/commander/download/commander-2.16.0.tgz#f16390593996ceb4f3eeb020b31d78528f7f8a50"
|
||||||
|
|
||||||
commander@2.3.0:
|
commander@2.3.0:
|
||||||
version "2.3.0"
|
version "2.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873"
|
resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873"
|
||||||
@@ -2142,12 +2180,250 @@ currently-unhandled@^0.4.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
array-find-index "^1.0.1"
|
array-find-index "^1.0.1"
|
||||||
|
|
||||||
|
d3-array@1, d3-array@1.2.1, d3-array@^1.2.0:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-array/download/d3-array-1.2.1.tgz#d1ca33de2f6ac31efadb8e050a021d7e2396d5dc"
|
||||||
|
|
||||||
|
d3-axis@1.0.8:
|
||||||
|
version "1.0.8"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-axis/download/d3-axis-1.0.8.tgz#31a705a0b535e65759de14173a31933137f18efa"
|
||||||
|
|
||||||
|
d3-brush@1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-brush/download/d3-brush-1.0.4.tgz#00c2f238019f24f6c0a194a26d41a1530ffe7bc4"
|
||||||
|
dependencies:
|
||||||
|
d3-dispatch "1"
|
||||||
|
d3-drag "1"
|
||||||
|
d3-interpolate "1"
|
||||||
|
d3-selection "1"
|
||||||
|
d3-transition "1"
|
||||||
|
|
||||||
|
d3-chord@1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-chord/download/d3-chord-1.0.4.tgz#7dec4f0ba886f713fe111c45f763414f6f74ca2c"
|
||||||
|
dependencies:
|
||||||
|
d3-array "1"
|
||||||
|
d3-path "1"
|
||||||
|
|
||||||
|
d3-collection@1, d3-collection@1.0.4:
|
||||||
|
version "1.0.4"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-collection/download/d3-collection-1.0.4.tgz#342dfd12837c90974f33f1cc0a785aea570dcdc2"
|
||||||
|
|
||||||
|
d3-color@1:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-color/download/d3-color-1.2.0.tgz#d1ea19db5859c86854586276ec892cf93148459a"
|
||||||
|
|
||||||
|
d3-color@1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-color/download/d3-color-1.0.3.tgz#bc7643fca8e53a8347e2fbdaffa236796b58509b"
|
||||||
|
|
||||||
|
d3-dispatch@1, d3-dispatch@1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-dispatch/download/d3-dispatch-1.0.3.tgz#46e1491eaa9b58c358fce5be4e8bed626e7871f8"
|
||||||
|
|
||||||
|
d3-drag@1, d3-drag@1.2.1:
|
||||||
|
version "1.2.1"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-drag/download/d3-drag-1.2.1.tgz#df8dd4c502fb490fc7462046a8ad98a5c479282d"
|
||||||
|
dependencies:
|
||||||
|
d3-dispatch "1"
|
||||||
|
d3-selection "1"
|
||||||
|
|
||||||
|
d3-dsv@1, d3-dsv@1.0.8:
|
||||||
|
version "1.0.8"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-dsv/download/d3-dsv-1.0.8.tgz#907e240d57b386618dc56468bacfe76bf19764ae"
|
||||||
|
dependencies:
|
||||||
|
commander "2"
|
||||||
|
iconv-lite "0.4"
|
||||||
|
rw "1"
|
||||||
|
|
||||||
|
d3-ease@1, d3-ease@1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-ease/download/d3-ease-1.0.3.tgz#68bfbc349338a380c44d8acc4fbc3304aa2d8c0e"
|
||||||
|
|
||||||
|
d3-force@1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-force/download/d3-force-1.1.0.tgz#cebf3c694f1078fcc3d4daf8e567b2fbd70d4ea3"
|
||||||
|
dependencies:
|
||||||
|
d3-collection "1"
|
||||||
|
d3-dispatch "1"
|
||||||
|
d3-quadtree "1"
|
||||||
|
d3-timer "1"
|
||||||
|
|
||||||
|
d3-format@1:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-format/download/d3-format-1.3.0.tgz#a3ac44269a2011cdb87c7b5693040c18cddfff11"
|
||||||
|
|
||||||
|
d3-format@1.2.2:
|
||||||
|
version "1.2.2"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-format/download/d3-format-1.2.2.tgz#1a39c479c8a57fe5051b2e67a3bee27061a74e7a"
|
||||||
|
|
||||||
|
d3-geo@1.9.1:
|
||||||
|
version "1.9.1"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-geo/download/d3-geo-1.9.1.tgz#157e3b0f917379d0f73bebfff3be537f49fa7356"
|
||||||
|
dependencies:
|
||||||
|
d3-array "1"
|
||||||
|
|
||||||
|
d3-hierarchy@1.1.5:
|
||||||
|
version "1.1.5"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-hierarchy/download/d3-hierarchy-1.1.5.tgz#a1c845c42f84a206bcf1c01c01098ea4ddaa7a26"
|
||||||
|
|
||||||
|
d3-interpolate@1:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-interpolate/download/d3-interpolate-1.2.0.tgz#40d81bd8e959ff021c5ea7545bc79b8d22331c41"
|
||||||
|
dependencies:
|
||||||
|
d3-color "1"
|
||||||
|
|
||||||
|
d3-interpolate@1.1.6:
|
||||||
|
version "1.1.6"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-interpolate/download/d3-interpolate-1.1.6.tgz#2cf395ae2381804df08aa1bf766b7f97b5f68fb6"
|
||||||
|
dependencies:
|
||||||
|
d3-color "1"
|
||||||
|
|
||||||
|
d3-path@1, d3-path@1.0.5:
|
||||||
|
version "1.0.5"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-path/download/d3-path-1.0.5.tgz#241eb1849bd9e9e8021c0d0a799f8a0e8e441764"
|
||||||
|
|
||||||
|
d3-polygon@1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-polygon/download/d3-polygon-1.0.3.tgz#16888e9026460933f2b179652ad378224d382c62"
|
||||||
|
|
||||||
|
d3-quadtree@1, d3-quadtree@1.0.3:
|
||||||
|
version "1.0.3"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-quadtree/download/d3-quadtree-1.0.3.tgz#ac7987e3e23fe805a990f28e1b50d38fcb822438"
|
||||||
|
|
||||||
|
d3-queue@3.0.7:
|
||||||
|
version "3.0.7"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-queue/download/d3-queue-3.0.7.tgz#c93a2e54b417c0959129d7d73f6cf7d4292e7618"
|
||||||
|
|
||||||
|
d3-random@1.1.0:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-random/download/d3-random-1.1.0.tgz#6642e506c6fa3a648595d2b2469788a8d12529d3"
|
||||||
|
|
||||||
|
d3-request@1.0.6:
|
||||||
|
version "1.0.6"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-request/download/d3-request-1.0.6.tgz#a1044a9ef4ec28c824171c9379fae6d79474b19f"
|
||||||
|
dependencies:
|
||||||
|
d3-collection "1"
|
||||||
|
d3-dispatch "1"
|
||||||
|
d3-dsv "1"
|
||||||
|
xmlhttprequest "1"
|
||||||
|
|
||||||
|
d3-scale@1.0.7:
|
||||||
|
version "1.0.7"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-scale/download/d3-scale-1.0.7.tgz#fa90324b3ea8a776422bd0472afab0b252a0945d"
|
||||||
|
dependencies:
|
||||||
|
d3-array "^1.2.0"
|
||||||
|
d3-collection "1"
|
||||||
|
d3-color "1"
|
||||||
|
d3-format "1"
|
||||||
|
d3-interpolate "1"
|
||||||
|
d3-time "1"
|
||||||
|
d3-time-format "2"
|
||||||
|
|
||||||
|
d3-selection@1, d3-selection@1.3.0, d3-selection@^1.1.0:
|
||||||
|
version "1.3.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-selection/download/d3-selection-1.3.0.tgz#d53772382d3dc4f7507bfb28bcd2d6aed2a0ad6d"
|
||||||
|
|
||||||
|
d3-shape@1.2.0:
|
||||||
|
version "1.2.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-shape/download/d3-shape-1.2.0.tgz#45d01538f064bafd05ea3d6d2cb748fd8c41f777"
|
||||||
|
dependencies:
|
||||||
|
d3-path "1"
|
||||||
|
|
||||||
|
d3-time-format@2, d3-time-format@2.1.1:
|
||||||
|
version "2.1.1"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-time-format/download/d3-time-format-2.1.1.tgz#85b7cdfbc9ffca187f14d3c456ffda268081bb31"
|
||||||
|
dependencies:
|
||||||
|
d3-time "1"
|
||||||
|
|
||||||
|
d3-time@1, d3-time@1.0.8:
|
||||||
|
version "1.0.8"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-time/download/d3-time-1.0.8.tgz#dbd2d6007bf416fe67a76d17947b784bffea1e84"
|
||||||
|
|
||||||
|
d3-timer@1, d3-timer@1.0.7:
|
||||||
|
version "1.0.7"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-timer/download/d3-timer-1.0.7.tgz#df9650ca587f6c96607ff4e60cc38229e8dd8531"
|
||||||
|
|
||||||
|
d3-transition@1, d3-transition@1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-transition/download/d3-transition-1.1.1.tgz#d8ef89c3b848735b060e54a39b32aaebaa421039"
|
||||||
|
dependencies:
|
||||||
|
d3-color "1"
|
||||||
|
d3-dispatch "1"
|
||||||
|
d3-ease "1"
|
||||||
|
d3-interpolate "1"
|
||||||
|
d3-selection "^1.1.0"
|
||||||
|
d3-timer "1"
|
||||||
|
|
||||||
|
d3-voronoi@1.1.2:
|
||||||
|
version "1.1.2"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-voronoi/download/d3-voronoi-1.1.2.tgz#1687667e8f13a2d158c80c1480c5a29cb0d8973c"
|
||||||
|
|
||||||
|
d3-zoom@1.7.1:
|
||||||
|
version "1.7.1"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3-zoom/download/d3-zoom-1.7.1.tgz#02f43b3c3e2db54f364582d7e4a236ccc5506b63"
|
||||||
|
dependencies:
|
||||||
|
d3-dispatch "1"
|
||||||
|
d3-drag "1"
|
||||||
|
d3-interpolate "1"
|
||||||
|
d3-selection "1"
|
||||||
|
d3-transition "1"
|
||||||
|
|
||||||
|
d3@^4.13.0:
|
||||||
|
version "4.13.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/d3/download/d3-4.13.0.tgz#ab236ff8cf0cfc27a81e69bf2fb7518bc9b4f33d"
|
||||||
|
dependencies:
|
||||||
|
d3-array "1.2.1"
|
||||||
|
d3-axis "1.0.8"
|
||||||
|
d3-brush "1.0.4"
|
||||||
|
d3-chord "1.0.4"
|
||||||
|
d3-collection "1.0.4"
|
||||||
|
d3-color "1.0.3"
|
||||||
|
d3-dispatch "1.0.3"
|
||||||
|
d3-drag "1.2.1"
|
||||||
|
d3-dsv "1.0.8"
|
||||||
|
d3-ease "1.0.3"
|
||||||
|
d3-force "1.1.0"
|
||||||
|
d3-format "1.2.2"
|
||||||
|
d3-geo "1.9.1"
|
||||||
|
d3-hierarchy "1.1.5"
|
||||||
|
d3-interpolate "1.1.6"
|
||||||
|
d3-path "1.0.5"
|
||||||
|
d3-polygon "1.0.3"
|
||||||
|
d3-quadtree "1.0.3"
|
||||||
|
d3-queue "3.0.7"
|
||||||
|
d3-random "1.1.0"
|
||||||
|
d3-request "1.0.6"
|
||||||
|
d3-scale "1.0.7"
|
||||||
|
d3-selection "1.3.0"
|
||||||
|
d3-shape "1.2.0"
|
||||||
|
d3-time "1.0.8"
|
||||||
|
d3-time-format "2.1.1"
|
||||||
|
d3-timer "1.0.7"
|
||||||
|
d3-transition "1.1.1"
|
||||||
|
d3-voronoi "1.1.2"
|
||||||
|
d3-zoom "1.7.1"
|
||||||
|
|
||||||
d@1:
|
d@1:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
|
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
|
||||||
dependencies:
|
dependencies:
|
||||||
es5-ext "^0.10.9"
|
es5-ext "^0.10.9"
|
||||||
|
|
||||||
|
dagre-d3-renderer@^0.5.8:
|
||||||
|
version "0.5.8"
|
||||||
|
resolved "http://registry.npm.taobao.org/dagre-d3-renderer/download/dagre-d3-renderer-0.5.8.tgz#aa071bb71d3c4d67426925906f3f6ddead49c1a3"
|
||||||
|
dependencies:
|
||||||
|
dagre-layout "^0.8.8"
|
||||||
|
lodash "^4.17.5"
|
||||||
|
|
||||||
|
dagre-layout@^0.8.8:
|
||||||
|
version "0.8.8"
|
||||||
|
resolved "http://registry.npm.taobao.org/dagre-layout/download/dagre-layout-0.8.8.tgz#9b6792f24229f402441c14162c1049e3f261f6d9"
|
||||||
|
dependencies:
|
||||||
|
graphlibrary "^2.2.0"
|
||||||
|
lodash "^4.17.5"
|
||||||
|
|
||||||
dashdash@^1.12.0:
|
dashdash@^1.12.0:
|
||||||
version "1.14.1"
|
version "1.14.1"
|
||||||
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
|
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
|
||||||
@@ -3681,6 +3957,12 @@ graceful-fs@~1.2.0:
|
|||||||
version "1.2.3"
|
version "1.2.3"
|
||||||
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364"
|
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-1.2.3.tgz#15a4806a57547cb2d2dbf27f42e89a8c3451b364"
|
||||||
|
|
||||||
|
graphlibrary@^2.2.0:
|
||||||
|
version "2.2.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/graphlibrary/download/graphlibrary-2.2.0.tgz#017a14899775228dec4497a39babfdd6bf56eac6"
|
||||||
|
dependencies:
|
||||||
|
lodash "^4.17.5"
|
||||||
|
|
||||||
growly@^1.3.0:
|
growly@^1.3.0:
|
||||||
version "1.3.0"
|
version "1.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
|
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
|
||||||
@@ -3870,6 +4152,10 @@ hawk@~2.3.0:
|
|||||||
hoek "2.x.x"
|
hoek "2.x.x"
|
||||||
sntp "1.x.x"
|
sntp "1.x.x"
|
||||||
|
|
||||||
|
he@^1.1.1:
|
||||||
|
version "1.1.1"
|
||||||
|
resolved "http://registry.npm.taobao.org/he/download/he-1.1.1.tgz#93410fd21b009735151f8868c2f271f3427e23fd"
|
||||||
|
|
||||||
highlight.js@^9.3.0:
|
highlight.js@^9.3.0:
|
||||||
version "9.12.0"
|
version "9.12.0"
|
||||||
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e"
|
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e"
|
||||||
@@ -4033,16 +4319,16 @@ i18n-2@^0.7.2:
|
|||||||
debug "^3.1.0"
|
debug "^3.1.0"
|
||||||
sprintf "^0.1.5"
|
sprintf "^0.1.5"
|
||||||
|
|
||||||
iconv-lite@0.4.19:
|
iconv-lite@0.4, iconv-lite@^0.4.19, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
|
||||||
version "0.4.19"
|
|
||||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
|
|
||||||
|
|
||||||
iconv-lite@^0.4.19, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
|
|
||||||
version "0.4.23"
|
version "0.4.23"
|
||||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
|
||||||
dependencies:
|
dependencies:
|
||||||
safer-buffer ">= 2.1.2 < 3"
|
safer-buffer ">= 2.1.2 < 3"
|
||||||
|
|
||||||
|
iconv-lite@0.4.19:
|
||||||
|
version "0.4.19"
|
||||||
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.19.tgz#f7468f60135f5e5dad3399c0a81be9a1603a082b"
|
||||||
|
|
||||||
iconv-lite@~0.2.11:
|
iconv-lite@~0.2.11:
|
||||||
version "0.2.11"
|
version "0.2.11"
|
||||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8"
|
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8"
|
||||||
@@ -5294,7 +5580,7 @@ lodash@^3.5.0:
|
|||||||
version "3.10.1"
|
version "3.10.1"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
|
||||||
|
|
||||||
lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.12.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1:
|
lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.12.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1:
|
||||||
version "4.17.10"
|
version "4.17.10"
|
||||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
|
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
|
||||||
|
|
||||||
@@ -5466,6 +5752,10 @@ mdurl@^1.0.1, mdurl@~1.0.1:
|
|||||||
version "1.0.1"
|
version "1.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
|
resolved "https://registry.yarnpkg.com/mdurl/-/mdurl-1.0.1.tgz#fe85b2ec75a59037f2adfec100fd6c601761152e"
|
||||||
|
|
||||||
|
meaw@^2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/meaw/-/meaw-2.0.0.tgz#7c3467efee5618cb865661dfaa38d6948dc23f7a"
|
||||||
|
|
||||||
media-typer@0.3.0:
|
media-typer@0.3.0:
|
||||||
version "0.3.0"
|
version "0.3.0"
|
||||||
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
|
||||||
@@ -5523,6 +5813,19 @@ merge@^1.1.3:
|
|||||||
version "1.2.0"
|
version "1.2.0"
|
||||||
resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
|
resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
|
||||||
|
|
||||||
|
mermaid@^8.0.0-rc.8:
|
||||||
|
version "8.0.0-rc.8"
|
||||||
|
resolved "http://registry.npm.taobao.org/mermaid/download/mermaid-8.0.0-rc.8.tgz#74ed54d0d46e9ee71c4db2730b2d83d516a21e72"
|
||||||
|
dependencies:
|
||||||
|
d3 "^4.13.0"
|
||||||
|
dagre-d3-renderer "^0.5.8"
|
||||||
|
dagre-layout "^0.8.8"
|
||||||
|
graphlibrary "^2.2.0"
|
||||||
|
he "^1.1.1"
|
||||||
|
lodash "^4.17.5"
|
||||||
|
moment "^2.21.0"
|
||||||
|
scope-css "^1.0.5"
|
||||||
|
|
||||||
methods@~1.1.2:
|
methods@~1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
|
||||||
@@ -5692,6 +5995,10 @@ mock-require@^3.0.1:
|
|||||||
get-caller-file "^1.0.2"
|
get-caller-file "^1.0.2"
|
||||||
normalize-path "^2.1.1"
|
normalize-path "^2.1.1"
|
||||||
|
|
||||||
|
moment@^2.10.2, moment@^2.21.0:
|
||||||
|
version "2.22.2"
|
||||||
|
resolved "http://registry.npm.taobao.org/moment/download/moment-2.22.2.tgz#3c257f9839fc0e93ff53149632239eb90783ff66"
|
||||||
|
|
||||||
moment@^2.10.3:
|
moment@^2.10.3:
|
||||||
version "2.22.1"
|
version "2.22.1"
|
||||||
resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.1.tgz#529a2e9bf973f259c9643d237fda84de3a26e8ad"
|
resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.1.tgz#529a2e9bf973f259c9643d237fda84de3a26e8ad"
|
||||||
@@ -7341,6 +7648,10 @@ run-series@^1.1.1:
|
|||||||
version "1.1.8"
|
version "1.1.8"
|
||||||
resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.8.tgz#2c4558f49221e01cd6371ff4e0a1e203e460fc36"
|
resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.8.tgz#2c4558f49221e01cd6371ff4e0a1e203e460fc36"
|
||||||
|
|
||||||
|
rw@1:
|
||||||
|
version "1.3.3"
|
||||||
|
resolved "http://registry.npm.taobao.org/rw/download/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
|
||||||
|
|
||||||
rx-lite@^3.1.2:
|
rx-lite@^3.1.2:
|
||||||
version "3.1.2"
|
version "3.1.2"
|
||||||
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
|
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
|
||||||
@@ -7418,6 +7729,10 @@ sax@>=0.6.0, sax@^1.2.1, sax@^1.2.4, sax@~1.2.1:
|
|||||||
version "1.2.4"
|
version "1.2.4"
|
||||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||||
|
|
||||||
|
scope-css@^1.0.5:
|
||||||
|
version "1.1.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/scope-css/download/scope-css-1.1.0.tgz#74eff45461bc9d3f3b29ed575b798cd722fa1256"
|
||||||
|
|
||||||
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"
|
||||||
@@ -8818,6 +9133,10 @@ xmldom@0.1.x:
|
|||||||
version "0.1.27"
|
version "0.1.27"
|
||||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9"
|
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9"
|
||||||
|
|
||||||
|
xmlhttprequest@1:
|
||||||
|
version "1.8.0"
|
||||||
|
resolved "http://registry.npm.taobao.org/xmlhttprequest/download/xmlhttprequest-1.8.0.tgz#67fe075c5c24fef39f9d65f5f7b7fe75171968fc"
|
||||||
|
|
||||||
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
|
xtend@^4.0.0, xtend@^4.0.1, xtend@~4.0.1:
|
||||||
version "4.0.1"
|
version "4.0.1"
|
||||||
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"
|
||||||
|
|||||||
Reference in New Issue
Block a user