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

Compare commits

...

100 Commits

Author SHA1 Message Date
Junyoung Choi
6cad2ab4df v0.11.8 2018-07-19 15:21:35 +09:00
Junyoung Choi (Sai)
856d52891c Merge pull request #2205 from saaguero/fix-attachment
Fix attachment interoperability between win and *nix
2018-07-17 16:23:16 +09:00
Junyoung Choi
8de3b3bd8d Update yarn.lock 2018-07-17 15:55:03 +09:00
Junyoung Choi (Sai)
0414483be2 Merge pull request #2178 from enyaxu/feature/2165
Hotkey for toggle editor fullscreen
2018-07-17 14:49:03 +09:00
Junyoung Choi (Sai)
22939aa472 Merge pull request #2145 from amedora/table-formatter
Markdown Table Formatter
2018-07-17 13:50:00 +09:00
Junyoung Choi (Sai)
0cb7c44985 Merge pull request #2168 from enyaxu/bug/2018
Fixed 'Focus Search' shortcut
2018-07-17 13:35:44 +09:00
Junyoung Choi (Sai)
b18a09e5eb Merge pull request #1935 from ZeroX-DG/allow-no-html-escape
Allow customizing html escape when export note
2018-07-17 12:38:14 +09:00
Junyoung Choi (Sai)
ef3649b1d6 Merge pull request #2172 from enyaxu/feature/862
Add chartjs support
2018-07-17 12:21:31 +09:00
Junyoung Choi (Sai)
ac70a0d94d Merge branch 'master' into feature/862 2018-07-17 12:21:17 +09:00
Junyoung Choi (Sai)
3b91f9b88b Merge pull request #2173 from enyaxu/feature/389
Add mermaid support
2018-07-17 12:15:36 +09:00
Santiago Agüero
c37b780ca4 Use markdown content for migrateAttachments 2018-07-17 00:13:13 -03:00
Junyoung Choi (Sai)
20061d2c65 Merge pull request #2183 from max-buranbaev/flickering-on-create-note
Flickering on create note
2018-07-17 11:54:33 +09:00
Junyoung Choi (Sai)
f18fa77c1c Merge pull request #2187 from ivanovserge/issue-2156
Issue 2156
2018-07-17 11:49:39 +09:00
Junyoung Choi (Sai)
a4c6869d4d Merge pull request #2192 from enyaxu/improvement/2133
Replace shortcut for 'Next Note' and 'Previous Note'
2018-07-17 11:46:08 +09:00
Junyoung Choi (Sai)
f9a0070c82 Merge pull request #2197 from chang/improve-bracket-completion
Improve bracket autoclosing
2018-07-17 11:20:27 +09:00
Santiago Agüero
5cc52f91cb Fix lint errors 2018-07-15 12:07:27 -03:00
Santiago Agüero
a46b9fb2be Fix attachment interop between win and nix 2018-07-15 01:37:47 -03:00
Eric
933e38eca9 improve bracket autoclosing 2018-07-09 18:37:54 -05:00
JianXu
e182390480 Replace shortcut for 'Next Note' and 'Previous Note' 2018-07-07 23:02:17 +08:00
Nguyễn Việt Hưng
563fdcba94 added tests escape html function 2018-07-07 00:07:17 +07:00
Nguyễn Việt Hưng
bc640834cd allow detect code block or not in escapeHtml function 2018-07-06 23:45:18 +07:00
Junyoung Choi (Sai)
0e9e7d644a Merge pull request #2191 from BoostIO/fix-codefence-xss
Add sanitization for code fence
2018-07-07 01:23:23 +09:00
Junyoung Choi
1d9b3ac2b5 Add sanitization for code fence 2018-07-07 01:22:11 +09:00
Junyoung Choi (Sai)
aebed4a644 Merge pull request #2033 from ZeroX-DG/fix-scrollbar-disappear
fixed disappearing scroll bar
2018-07-07 00:47:14 +09:00
Junyoung Choi
7bfb094a40 use lighter color for scroll bar 2018-07-06 22:07:06 +09:00
Kazz Yokomizo
f90a44c1d0 Merge pull request #2189 from BoostIO/update-readme
Update readme
2018-07-06 15:55:25 +09:00
Kazz Yokomizo
dfcf6d2729 Update readme 2018-07-06 15:37:10 +09:00
Сергей Иванов
806a5daa86 Processing all location's pathnames 2018-07-05 11:23:57 +03:00
Сергей Иванов
4a3602099a Difference home and searched notes from trashed units 2018-07-04 16:09:49 +03:00
Сергей Иванов
c69be54655 Fixing empty string searching 2018-07-04 14:02:26 +03:00
Сергей Иванов
680eaa1d4a Filtering displayed notes in Detail component 2018-07-04 13:33:47 +03:00
Nguyễn Việt Hưng
9cc7b8bcc6 fixed redundant code 2018-07-04 15:35:46 +07:00
Nguyễn Việt Hưng
55d86d853a improved escape function 2018-07-04 15:27:30 +07:00
Nguyễn Việt Hưng
7d9f309e04 Merge remote-tracking branch 'upstream/master' into allow-no-html-escape 2018-07-04 13:50:10 +07:00
Nguyễn Việt Hưng
c2f0147cff updated new escape html function 2018-07-04 13:50:05 +07:00
JianXu
05488e66ae Add tooltip(CommandOrCtrl+B) for fullscreen 2018-07-04 11:38:43 +08:00
JianXu
09eac89086 Hotkey for toggle editor fullscreen 2018-07-04 09:59:06 +08:00
JianXu
866a0e7534 Add mermaid support 2018-07-03 15:10:08 +08:00
Max Buranbaev
3c8337cf54 adding timeout one creating a snippet 2018-07-03 10:29:22 +05:00
Max Buranbaev
883b4c4c26 adding timeout on creating a note 2018-07-03 10:27:13 +05:00
JianXu
6bc42c564d Add chartjs 2018-07-03 12:58:45 +08:00
JianXu
d2b2e76a6a Fixed 'Focus Search' shortcut 2018-07-02 21:43:46 +08:00
Sosuke Suzuki
9d9109e9e5 Merge pull request #2158 from BoostIO/fix-contextmenu-bug
Fix contextmenu bug
2018-07-02 11:27:28 +09:00
Kazz Yokomizo
18efb89b9a Merge pull request #2163 from BoostIO/update-slack
Update slack invitation url
2018-07-01 22:02:52 +09:00
Kazz Yokomizo
cefe883025 Update slack invitation url 2018-07-01 21:59:08 +09:00
Sosuke Suzuki
0ffa0b96d3 Merge pull request #2135 from BoostIO/improve-snippets-ui
Improve snippets ui
2018-06-30 20:11:33 +09:00
Sosuke Suzuki
0429acfa1b Merge pull request #2138 from BoostIO/improve-uitab-editor
Improve uitab editor
2018-06-30 20:11:20 +09:00
Sosuke Suzuki
827e3c1829 Merge pull request #2144 from kelvin-wong/retain-collapsed-storage-state
Add collapsed state for storage
2018-06-30 20:11:01 +09:00
Sosuke Suzuki
aa756ef194 Merge pull request #2146 from BoostIO/update-codemirror
update codemirror
2018-06-30 20:10:13 +09:00
Sosuke Suzuki
d8aad65b24 fix from eslint 2018-06-30 16:28:17 +09:00
Sosuke Suzuki
1038e86196 use context.popup on StatusBar 2018-06-30 16:25:44 +09:00
Sosuke Suzuki
47845fd4e3 use context.popup on SideNav 2018-06-30 16:23:51 +09:00
Sosuke Suzuki
294c3f10ab use context.popup on StorageItem 2018-06-30 16:21:35 +09:00
Sosuke Suzuki
f6afc756dc use context.popup on SnippetList 2018-06-30 16:16:18 +09:00
Sosuke Suzuki
64407e5ca6 use context.popup on SnippetNoteDetai; 2018-06-30 16:12:23 +09:00
Sosuke Suzuki
0a42b0f61f use context.popup on NoteList 2018-06-30 16:08:13 +09:00
Junyoung Choi
ae493cbd0e v0.11.7 2018-06-30 00:51:15 +09:00
Kelvin Wong
ddd339851b Fix code style 2018-06-29 10:58:11 +08:00
amedora
82db986bd7 add 'Format Table' in the File menu 2018-06-28 18:16:38 +09:00
amedora
7bacd6f8f0 CodeEditor can handle 'code:format-table' event 2018-06-28 18:16:38 +09:00
amedora
f0941f47dd create TableEditor when CodeEditor mounted 2018-06-28 18:09:06 +09:00
amedora
c9d05b1117 CodeEditor use TableEditor 2018-06-28 18:09:06 +09:00
amedora
7ee12752ec CodeEditor use TextEditorInterface 2018-06-28 18:09:06 +09:00
amedora
b44772441d implement TextEditorInterface 2018-06-28 18:09:06 +09:00
Sosuke Suzuki
72e3784fa5 update codemirror 2018-06-28 17:37:36 +09:00
Kelvin Wong
8a6c86bf65 Add collapsed state for storage
The root cause of this issue is that when the folder is clicked,
the router pushed the path and the StorageItem component has been
refreshed and isOpen has been reset

- Add storing collapse state for storage
- Add tests
- Default as collapsed for fallback

fix BoostIo/Boostnote#1979 BoostIo/Boostnote#1911
2018-06-28 13:08:39 +08:00
amedora
cc52cf60dc add reference to @susisu/mte-kernel 2018-06-28 13:36:04 +09:00
Sosuke Suzuki
0095735841 fix from eslint 2018-06-27 20:42:19 +09:00
Sosuke Suzuki
95c10a1de7 add test 2018-06-27 20:42:01 +09:00
Sosuke Suzuki
8f4c92e251 extract normalizeEditorFonrFamily 2018-06-27 19:48:09 +09:00
Sosuke Suzuki
58354061d8 set font-family to editor in Preference > Interface 2018-06-27 19:34:58 +09:00
Sosuke Suzuki
7414d52dc2 selected snippet item background-color is darken 2018-06-27 16:27:55 +09:00
Sosuke Suzuki
c42b5c8806 First snippet is selected when open Snippets tab 2018-06-27 16:13:42 +09:00
Sosuke Suzuki
5c60da0f8f apply style to each themes button 2018-06-27 15:59:14 +09:00
Junyoung Choi (Sai)
70d02e9a6d Merge pull request #2125 from johannbre/admonition_bug_fix
Fix rendering of admonitions in Windows
2018-06-27 14:50:54 +09:00
Junyoung Choi (Sai)
6401016424 Merge pull request #2122 from yosmoc/plant_uml_improvement
plantuml non-english character support and timing diagram support
2018-06-27 04:54:21 +09:00
Junyoung Choi (Sai)
cd031a89fb Merge pull request #2105 from romainwn/docs/add-missing-translations-fr
update fr translation
2018-06-27 04:52:52 +09:00
Junyoung Choi (Sai)
aadba79002 Merge pull request #2106 from voidsatisfaction/fix-typo-on-main-app
fix tiny comment typo
2018-06-27 04:43:53 +09:00
Junyoung Choi (Sai)
4a017fd8ae Merge pull request #2066 from PeterDaveHello/patch-1
Improve Traditional Chinese translation
2018-06-27 04:43:27 +09:00
Junyoung Choi (Sai)
e6072c8fe9 Merge pull request #2131 from clone1612/updateElectron
Update Electron to v2.0.3
2018-06-27 04:41:36 +09:00
Jannick Hemelhof
f7fd99ec20 Update electron to v2.0.3 2018-06-26 11:27:37 +02:00
Junyoung Choi (Sai)
836fc13449 Merge pull request #2124 from clone1612/remove-unused
[Refactoring] - Removed unused packages
2018-06-26 06:01:30 +08:00
Junyoung Choi (Sai)
e1f78cd682 Merge pull request #2107 from ehhc/fix_images
One more try to fix the handling of images in the legacy location
2018-06-25 21:33:19 +08:00
ehhc
c69f34836a handle dot in file name 2018-06-25 15:18:45 +02:00
Junyoung Choi (Sai)
48a0db28d7 Merge pull request #2127 from BoostIO/update-issue-template
Update issue template
2018-06-25 20:22:11 +08:00
Johann Breytenbach
c36689934d Fix rendering of admonitions in Windows 2018-06-24 22:04:36 -07:00
yosmoc
653b985018 plantuml non-english character support and timing diagram support 2018-06-23 14:02:46 +09:00
ehhc
7970016fbf One more try to fix the handling of images in the legacy location 2018-06-20 08:48:55 +02:00
voidsatisfaction
129e3b283d fix tiny typo 2018-06-20 14:29:57 +09:00
Romain Le Quellec
868eefd2cf update fr translation 2018-06-19 22:20:17 +02:00
Jannick Hemelhof
68a328a364 Removed unused packages 2018-06-13 16:08:18 +02:00
Peter Dave Hello
29cd63d3a7 Improve Traditional Chinese translation 2018-06-11 18:40:55 +08:00
Nguyễn Việt Hưng
0ae1263d9d abort 2018-06-06 00:25:49 +07:00
Nguyễn Việt Hưng
31f1ebe801 removed unnecessary style 2018-06-05 21:31:50 +07:00
Nguyễn Việt Hưng
c6a9c9c57d fixed disappear scrollbar 2018-06-05 21:24:37 +07:00
Nguyễn Việt Hưng
707356bffe revert to the original function for better performance 2018-05-29 18:15:57 +07:00
Nguyễn Việt Hưng
1516807ed5 fixed double escape html 2018-05-20 19:24:36 +07:00
Nguyễn Việt Hưng
9893fd9ae5 fixed eslint 2018-05-19 19:52:47 +07:00
Nguyễn Việt Hưng
d6c28da3a8 added export escape html config 2018-05-19 19:39:08 +07:00
Nguyễn Việt Hưng
52f694a714 fixed null attachment 2018-05-19 18:58:44 +07:00
43 changed files with 1127 additions and 365 deletions

View File

@@ -5,16 +5,18 @@ import CodeMirror from 'codemirror'
import 'codemirror-mode-elixir'
import attachmentManagement from 'browser/main/lib/dataApi/attachmentManagement'
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 iconv from 'iconv-lite'
import crypto from 'crypto'
import consts from 'browser/lib/consts'
import fs from 'fs'
const { ipcRenderer } = require('electron')
import normalizeEditorFontFamily from 'browser/lib/normalizeEditorFontFamily'
CodeMirror.modeURL = '../node_modules/codemirror/mode/%N/%N.js'
const defaultEditorFontFamily = ['Monaco', 'Menlo', 'Ubuntu Mono', 'Consolas', 'source-code-pro', 'monospace']
const buildCMRulers = (rulers, enableRulers) =>
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.searchState = null
this.formatTable = () => this.handleFormatTable()
}
handleSearch (msg) {
@@ -81,6 +85,10 @@ export default class CodeEditor extends React.Component {
})
}
handleFormatTable () {
this.tableEditor.formatAll(options({textWidthOptions: {}}))
}
componentDidMount () {
const { rulers, enableRulers } = this.props
const expandSnippet = this.expandSnippet.bind(this)
@@ -113,7 +121,12 @@ export default class CodeEditor extends React.Component {
dragDrop: false,
foldGutter: true,
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
autoCloseBrackets: true,
autoCloseBrackets: {
pairs: '()[]{}\'\'""$$**``',
triples: '```"""\'\'\'',
explode: '[]{}``$$',
override: true
},
extraKeys: {
Tab: function (cm) {
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('qw', 'qw', this.quitEditor)
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) {
@@ -264,6 +280,8 @@ export default class CodeEditor extends React.Component {
this.editor.off('scroll', this.scrollHandler)
const editorTheme = document.getElementById('editorTheme')
editorTheme.removeEventListener('load', this.loadStyleHandler)
eventEmitter.off('code:format-table', this.formatTable)
}
componentDidUpdate (prevProps, prevState) {
@@ -495,10 +513,7 @@ export default class CodeEditor extends React.Component {
render () {
const {className, fontSize} = this.props
let fontFamily = this.props.fontFamily
fontFamily = _.isString(fontFamily) && fontFamily.length > 0
? [fontFamily].concat(defaultEditorFontFamily)
: defaultEditorFontFamily
const fontFamily = normalizeEditorFontFamily(this.props.fontFamily)
const width = this.props.width
return (
<div
@@ -509,7 +524,7 @@ export default class CodeEditor extends React.Component {
ref='root'
tabIndex='-1'
style={{
fontFamily: fontFamily.join(', '),
fontFamily,
fontSize: fontSize,
width: width
}}

View File

@@ -7,7 +7,9 @@ import 'codemirror-mode-elixir'
import consts from 'browser/lib/consts'
import Raphael from 'raphael'
import flowchart from 'flowchart'
import mermaidRender from './render/MermaidRender'
import SequenceDiagram from 'js-sequence-diagrams'
import Chart from 'chart.js'
import eventEmitter from 'browser/main/lib/eventEmitter'
import htmlTextHelper from 'browser/lib/htmlTextHelper'
import convertModeName from 'browser/lib/convertModeName'
@@ -21,10 +23,12 @@ const attachmentManagement = require('../main/lib/dataApi/attachmentManagement')
const { app } = remote
const path = require('path')
const fileUrl = require('file-url')
const dialog = remote.dialog
const markdownStyle = require('!!css!stylus?sourceMap!./markdown.styl')[0][1]
const appPath = 'file://' + (process.env.NODE_ENV === 'production'
const appPath = fileUrl(process.env.NODE_ENV === 'production'
? app.getAppPath()
: path.resolve())
const CSS_FILES = [
@@ -129,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 OSX = global.process.platform === 'darwin'
@@ -217,7 +240,7 @@ export default class MarkdownPreview extends React.Component {
const {fontFamily, fontSize, codeBlockFontFamily, lineNumber, codeBlockTheme, scrollPastEnd, theme, allowCustomCSS, customCSS} = this.getStyleParams()
const inlineStyles = buildStyle(fontFamily, fontSize, codeBlockFontFamily, lineNumber, scrollPastEnd, theme, allowCustomCSS, customCSS)
let body = this.markdown.render(escapeHtmlCharacters(noteContent))
let body = this.markdown.render(escapeHtmlCharacters(noteContent, { detectCodeBlock: true }))
const files = [this.GetCodeThemeLink(codeBlockTheme), ...CSS_FILES]
const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent(noteContent, this.props.storagePath)
@@ -293,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 () {
this.refs.root.setAttribute('sandbox', 'allow-scripts')
this.refs.root.contentWindow.document.body.addEventListener('contextmenu', this.contextMenuHandler)
@@ -301,6 +339,9 @@ export default class MarkdownPreview extends React.Component {
<style id='style'></style>
<link rel="stylesheet" id="codeTheme">
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<style>
${this.getScrollBarStyle()}
</style>
`
CSS_FILES.forEach((file) => {
@@ -410,8 +451,8 @@ export default class MarkdownPreview extends React.Component {
value = value.replace(codeBlock, htmlTextHelper.encodeEntities(codeBlock))
})
}
let renderedHTML = this.markdown.render(value)
attachmentManagement.migrateAttachments(renderedHTML, storagePath, noteKey)
const renderedHTML = this.markdown.render(value)
attachmentManagement.migrateAttachments(value, storagePath, noteKey)
this.refs.root.contentWindow.document.body.innerHTML = attachmentManagement.fixLocalURLS(renderedHTML, storagePath)
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('input[type="checkbox"]'), (el) => {
@@ -494,6 +535,30 @@ export default class MarkdownPreview extends React.Component {
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 () {

View File

@@ -68,7 +68,7 @@ body
padding 5px
margin -5px
border-radius 5px
.flowchart-error, .sequence-error
.flowchart-error, .sequence-error .chart-error
background-color errorBackgroundColor
color errorTextColor
padding 5px
@@ -213,7 +213,7 @@ pre
margin 0 0 1em
display flex
line-height 1.4em
&.flowchart, &.sequence
&.flowchart, &.sequence, &.chart
display flex
justify-content center
background-color white
@@ -315,6 +315,8 @@ $admonition-icon
position absolute
left 1.2rem
font-family: "Material Icons"
font-weight: normal;
font-style: normal;
font-size: 24px
display: inline-block;
line-height: 1;
@@ -346,27 +348,27 @@ $admonition-title
margin-bottom 0
admonition_types = {
note: {border-color: #448aff, title-color: rgba(68,138,255,.1), icon: "note"},
hint: {border-color: #00bfa5, title-color: rgba(0,191,165,.1), icon: "info"},
danger: {border-color: #ff1744, title-color: rgba(255,23,68,.1), icon: "block"},
caution: {border-color: #ff9100, title-color: rgba(255,145,0,.1), icon: "warning"},
error: {border-color: #ff1744, title-color: rgba(255,23,68,.1), icon: "error"},
attention: {border-color: #64dd17, title-color: rgba(100,221,23,.1), icon: "priority_high"}
note: {color: #0288D1, icon: "note"},
hint: {color: #009688, icon: "info_outline"},
danger: {color: #c2185b, icon: "block"},
caution: {color: #ffa726, icon: "warning"},
error: {color: #d32f2f, icon: "error_outline"},
attention: {color: #455a64, icon: "priority_high"}
}
for name, val in admonition_types
.admonition.{name}
@extend $admonition
border-left-color: val[border-color]
border-left-color: val[color]
.admonition.{name}>.admonition-title
@extend $admonition-title
border-bottom-color: .1rem solid val[title-color]
background-color: val[title-color]
border-bottom-color: .1rem solid rgba(val[color], 0.2)
background-color: rgba(val[color], 0.2)
.admonition.{name}>.admonition-title:before
@extend $admonition-icon
color: val[border-color]
color: val[color]
content: val[icon]
themeDarkBackground = darken(#21252B, 10%)

View 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

View 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()
}
}

View File

@@ -36,7 +36,15 @@ const consts = {
'Violet Eggplant'
],
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

View File

@@ -10,6 +10,9 @@ module.exports = function sanitizePlugin (md, options) {
if (state.tokens[tokenIdx].type === 'html_block') {
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, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/"/g, '&quot;')
}
if (state.tokens[tokenIdx].type === 'inline') {
const inlineTokens = state.tokens[tokenIdx].children
for (let childIdx = 0; childIdx < inlineTokens.length; childIdx++) {

View File

@@ -40,6 +40,12 @@ class Markdown {
if (langType === 'sequence') {
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">' +
'<span class="filename">' + fileName + '</span>' +
createGutter(str, firstLineNumber) +
@@ -245,4 +251,3 @@ class Markdown {
}
export default Markdown

View 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(', ')
}

View File

@@ -6,52 +6,64 @@ export function lastFindInArray (array, callback) {
}
}
export function escapeHtmlCharacters (text) {
const matchHtmlRegExp = /["'&<>]/
const str = '' + text
const match = matchHtmlRegExp.exec(str)
export function escapeHtmlCharacters (html, opt = { detectCodeBlock: false }) {
const matchHtmlRegExp = /["'&<>]/g
const escapes = ['&quot;', '&amp;', '&#39;', '&lt;', '&gt;']
let match = null
const replaceAt = (str, index, replace) =>
str.substr(0, index) +
replace +
str.substr(index + replace.length - (replace.length - 1))
if (!match) {
return str
// detecting code block
while ((match = matchHtmlRegExp.exec(html)) != null) {
const current = { char: match[0], index: match.index }
if (opt.detectCodeBlock) {
// position of the nearest line start
let previousLineEnd = current.index - 1
while (html[previousLineEnd] !== '\n' && previousLineEnd !== -1) {
previousLineEnd--
}
let escape
let html = ''
let index = 0
let lastIndex = 0
for (index = match.index; index < str.length; index++) {
switch (str.charCodeAt(index)) {
case 34: // "
escape = '&quot;'
break
case 38: // &
escape = '&amp;'
break
case 39: // '
escape = '&#39;'
break
case 60: // <
escape = '&lt;'
break
case 62: // >
escape = '&gt;'
break
default:
// 4 spaces means this character is in a code block
if (
html[previousLineEnd + 1] === ' ' &&
html[previousLineEnd + 2] === ' ' &&
html[previousLineEnd + 3] === ' ' &&
html[previousLineEnd + 4] === ' '
) {
// so skip it
continue
}
if (lastIndex !== index) {
html += str.substring(lastIndex, index)
}
lastIndex = index + 1
html += escape
// otherwise, escape it !!!
if (current.char === '&') {
let nextStr = ''
let nextIndex = current.index
let escapedStr = false
// maximum length of an escape string is 5. For example ('&quot;')
while (nextStr.length <= 5) {
nextStr += html[nextIndex]
nextIndex++
if (escapes.indexOf(nextStr) !== -1) {
escapedStr = true
break
}
return lastIndex !== index
? html + str.substring(lastIndex, index)
: html
}
if (!escapedStr) {
// this & char is not a part of an escaped string
html = replaceAt(html, current.index, '&amp;')
}
} else if (current.char === '"') {
html = replaceAt(html, current.index, '&quot;')
} else if (current.char === "'") {
html = replaceAt(html, current.index, '&#39;')
} else if (current.char === '<') {
html = replaceAt(html, current.index, '&lt;')
} else if (current.char === '>') {
html = replaceAt(html, current.index, '&gt;')
}
}
return html
}
export function isObjectEqual (a, b) {

View File

@@ -4,12 +4,14 @@ import CSSModules from 'browser/lib/CSSModules'
import styles from './FullscreenButton.styl'
import i18n from 'browser/lib/i18n'
const OSX = global.process.platform === 'darwin'
const hotkey = (OSX ? i18n.__('Command(⌘)') : i18n.__('Ctrl(^)')) + '+B'
const FullscreenButton = ({
onClick
}) => (
<button styleName='control-fullScreenButton' title={i18n.__('Fullscreen')} onMouseDown={(e) => onClick(e)}>
<img styleName='iconInfo' src='../resources/icon/icon-full.svg' />
<span styleName='tooltip'>{i18n.__('Fullscreen')}</span>
<span styleName='tooltip'>{i18n.__('Fullscreen')}({hotkey})</span>
</button>
)

View File

@@ -32,7 +32,7 @@ import { confirmDeleteNote } from 'browser/lib/confirmDeleteNote'
const electron = require('electron')
const { remote } = electron
const { Menu, MenuItem, dialog } = remote
const { dialog } = remote
class SnippetNoteDetail extends React.Component {
constructor (props) {
@@ -451,14 +451,14 @@ class SnippetNoteDetail extends React.Component {
}
handleModeButtonClick (e, index) {
const menu = new Menu()
const templetes = []
CodeMirror.modeInfo.sort(function (a, b) { return a.name.localeCompare(b.name) }).forEach((mode) => {
menu.append(new MenuItem({
templetes.push({
label: mode.name,
click: (e) => this.handleModeOptionClick(index, mode.name)(e)
}))
})
menu.popup(remote.getCurrentWindow())
})
context.popup(templetes)
}
handleIndentTypeButtonClick (e) {

View File

@@ -9,6 +9,7 @@ import ee from 'browser/main/lib/eventEmitter'
import StatusBar from '../StatusBar'
import i18n from 'browser/lib/i18n'
import debounceRender from 'react-debounce-render'
import searchFromNotes from 'browser/lib/search'
const OSX = global.process.platform === 'darwin'
@@ -35,12 +36,39 @@ class Detail extends React.Component {
}
render () {
const { location, data, config } = this.props
const { location, data, params, config } = this.props
let note = null
if (location.query.key != null) {
const noteKey = location.query.key
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) {
return (

View File

@@ -21,9 +21,10 @@ import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig'
import Markdown from '../../lib/markdown'
import i18n from 'browser/lib/i18n'
import { confirmDeleteNote } from 'browser/lib/confirmDeleteNote'
import context from 'browser/lib/context'
const { remote } = require('electron')
const { Menu, MenuItem, dialog } = remote
const { dialog } = remote
const WP_POST_PATH = '/wp/v2/posts'
function sortByCreatedAt (a, b) {
@@ -491,55 +492,51 @@ class NoteList extends React.Component {
const updateLabel = i18n.__('Update Blog')
const openBlogLabel = i18n.__('Open Blog')
const menu = new Menu()
const templates = []
if (location.pathname.match(/\/trash/)) {
menu.append(new MenuItem({
templates.push({
label: restoreNote,
click: this.restoreNote
}))
menu.append(new MenuItem({
}, {
label: deleteLabel,
click: this.deleteNote
}))
})
} else {
if (!location.pathname.match(/\/starred/)) {
menu.append(new MenuItem({
templates.push({
label: pinLabel,
click: this.pinToTop
}))
})
}
menu.append(new MenuItem({
templates.push({
label: deleteLabel,
click: this.deleteNote
}))
menu.append(new MenuItem({
}, {
label: cloneNote,
click: this.cloneNote.bind(this)
}))
menu.append(new MenuItem({
}, {
label: copyNoteLink,
click: this.copyNoteLink(note)
}))
})
if (note.type === 'MARKDOWN_NOTE') {
if (note.blog && note.blog.blogLink && note.blog.blogId) {
menu.append(new MenuItem({
templates.push({
label: updateLabel,
click: this.publishMarkdown.bind(this)
}))
menu.append(new MenuItem({
}, {
label: openBlogLabel,
click: () => this.openBlog.bind(this)(note)
}))
})
} else {
menu.append(new MenuItem({
templates.push({
label: publishLabel,
click: this.publishMarkdown.bind(this)
}))
})
}
}
}
menu.popup()
context.popup(templates)
}
updateSelectedNotes (updateFunc, cleanSelection = true) {

View File

@@ -11,9 +11,10 @@ import StorageItemChild from 'browser/components/StorageItem'
import _ from 'lodash'
import { SortableElement } from 'react-sortable-hoc'
import i18n from 'browser/lib/i18n'
import context from 'browser/lib/context'
const { remote } = require('electron')
const { Menu, dialog } = remote
const { dialog } = remote
const escapeStringRegexp = require('escape-string-regexp')
const path = require('path')
@@ -21,13 +22,15 @@ class StorageItem extends React.Component {
constructor (props) {
super(props)
const { storage } = this.props
this.state = {
isOpen: true
isOpen: !!storage.isOpen
}
}
handleHeaderContextMenu (e) {
const menu = Menu.buildFromTemplate([
context.popup([
{
label: i18n.__('Add Folder'),
click: (e) => this.handleAddFolderButtonClick(e)
@@ -40,8 +43,6 @@ class StorageItem extends React.Component {
click: (e) => this.handleUnlinkStorageClick(e)
}
])
menu.popup()
}
handleUnlinkStorageClick (e) {
@@ -68,8 +69,18 @@ class StorageItem extends React.Component {
}
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({
isOpen: !this.state.isOpen
isOpen: isOpen
})
}
@@ -94,7 +105,7 @@ class StorageItem extends React.Component {
}
handleFolderButtonContextMenu (e, folder) {
const menu = Menu.buildFromTemplate([
context.popup([
{
label: i18n.__('Rename Folder'),
click: (e) => this.handleRenameFolderClick(e, folder)
@@ -123,8 +134,6 @@ class StorageItem extends React.Component {
click: (e) => this.handleFolderDeleteClick(e, folder)
}
])
menu.popup()
}
handleRenameFolderClick (e, folder) {

View File

@@ -1,8 +1,6 @@
import PropTypes from 'prop-types'
import React from 'react'
import CSSModules from 'browser/lib/CSSModules'
const { remote } = require('electron')
const { Menu } = remote
import dataApi from 'browser/main/lib/dataApi'
import styles from './SideNav.styl'
import { openModal } from 'browser/main/lib/modal'
@@ -19,6 +17,7 @@ import ListButton from './ListButton'
import TagButton from './TagButton'
import {SortableContainer} from 'react-sortable-hoc'
import i18n from 'browser/lib/i18n'
import context from 'browser/lib/context'
class SideNav extends React.Component {
// TODO: should not use electron stuff v0.7
@@ -254,10 +253,9 @@ class SideNav extends React.Component {
handleFilterButtonContextMenu (event) {
const { data } = this.props
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) }
])
menu.popup()
}
render () {

View File

@@ -4,10 +4,11 @@ import CSSModules from 'browser/lib/CSSModules'
import styles from './StatusBar.styl'
import ZoomManager from 'browser/main/lib/ZoomManager'
import i18n from 'browser/lib/i18n'
import context from 'browser/lib/context'
const electron = require('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]
@@ -26,16 +27,16 @@ class StatusBar extends React.Component {
}
handleZoomButtonClick (e) {
const menu = new Menu()
const templates = []
zoomOptions.forEach((zoom) => {
menu.append(new MenuItem({
templates.push({
label: Math.floor(zoom * 100) + '%',
click: () => this.handleZoomMenuItemClick(zoom)
}))
})
})
menu.popup(remote.getCurrentWindow())
context.popup(templates)
}
handleZoomMenuItemClick (zoomFactor) {

View File

@@ -156,8 +156,7 @@ class TopBar extends React.Component {
if (this.state.isSearching) {
el.blur()
} else {
el.focus()
el.setSelectionRange(0, el.value.length)
el.select()
}
}

View File

@@ -15,6 +15,12 @@ body
font-weight 200
-webkit-font-smoothing antialiased
::-webkit-scrollbar
width 12px
::-webkit-scrollbar-thumb
background-color rgba(0, 0, 0, 0.15)
button, input, select, textarea
font-family DEFAULT_FONTS
@@ -88,6 +94,8 @@ modalBackColor = white
body[data-theme="dark"]
::-webkit-scrollbar-thumb
background-color rgba(0, 0, 0, 0.3)
.ModalBase
.modalBack
background-color $ui-dark-backgroundColor
@@ -128,6 +136,8 @@ body[data-theme="dark"]
z-index modalZIndex + 5
body[data-theme="solarized-dark"]
::-webkit-scrollbar-thumb
background-color rgba(0, 0, 0, 0.3)
.ModalBase
.modalBack
background-color $ui-solarized-dark-backgroundColor
@@ -135,9 +145,10 @@ body[data-theme="solarized-dark"]
color: $ui-solarized-dark-text-color
body[data-theme="monokai"]
::-webkit-scrollbar-thumb
background-color rgba(0, 0, 0, 0.3)
.ModalBase
.modalBack
background-color $ui-monokai-backgroundColor
.sortableItemHelper
color: $ui-monokai-text-color

View File

@@ -37,7 +37,8 @@ function addStorage (input) {
key,
name: input.name,
type: input.type,
path: input.path
path: input.path,
isOpen: false
}
return Promise.resolve(newStorage)
@@ -48,7 +49,8 @@ function addStorage (input) {
key: newStorage.key,
type: newStorage.type,
name: newStorage.name,
path: newStorage.path
path: newStorage.path,
isOpen: false
})
localStorage.setItem('storages', JSON.stringify(rawStorages))

View File

@@ -10,6 +10,7 @@ import i18n from 'browser/lib/i18n'
const STORAGE_FOLDER_PLACEHOLDER = ':storage'
const DESTINATION_FOLDER = 'attachments'
const PATH_SEPARATORS = escapeStringRegexp(path.posix.sep) + escapeStringRegexp(path.win32.sep)
/**
* @description
@@ -76,13 +77,13 @@ function createAttachmentDestinationFolder (destinationStoragePath, 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 noteKey Key of the current note
*/
function migrateAttachments (renderedHTML, storagePath, noteKey) {
function migrateAttachments (markdownContent, storagePath, noteKey) {
if (sander.existsSync(path.join(storagePath, 'images'))) {
const attachments = getAttachmentsInContent(renderedHTML) || []
const attachments = getAttachmentsInMarkdownContent(markdownContent) || []
if (attachments !== []) {
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.
*/
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
* @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
*/
function getAttachmentsInContent (markdownContent) {
const preparedInput = markdownContent.replace(new RegExp(mdurl.encode(path.sep), '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')
* @description Returns all attachment paths of the given markdown
* @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
*/
function getAttachmentsInMarkdownContent (markdownContent) {
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')
return preparedInput.match(regexp)
}
@@ -203,7 +207,7 @@ function getAttachmentsInContent (markdownContent) {
* @returns {String[]} Absolute paths of the referenced attachments
*/
function getAbsolutePathsOfAttachmentsInContent (markdownContent, storagePath) {
const temp = getAttachmentsInContent(markdownContent) || []
const temp = getAttachmentsInMarkdownContent(markdownContent) || []
const result = []
for (const relativePath of temp) {
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) {
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
}
@@ -277,7 +282,7 @@ function deleteAttachmentsNotPresentInNote (markdownContent, storageKey, noteKey
}
const targetStorage = findStorage.findStorage(storageKey)
const attachmentFolder = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey)
const attachmentsInNote = getAttachmentsInContent(markdownContent)
const attachmentsInNote = getAttachmentsInMarkdownContent(markdownContent)
const attachmentsInNoteOnlyFileNames = []
if (attachmentsInNote) {
for (let i = 0; i < attachmentsInNote.length; i++) {
@@ -348,7 +353,7 @@ function generateFileNotFoundMarkdown () {
*/
function isAttachmentLink (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
}
@@ -364,7 +369,7 @@ function isAttachmentLink (text) {
function handleAttachmentLinkPaste (storageKey, noteKey, linkText) {
if (storageKey != null && noteKey != null && linkText != null) {
const storagePath = findStorage.findStorage(storageKey).path
const attachments = getAttachmentsInContent(linkText) || []
const attachments = getAttachmentsInMarkdownContent(linkText) || []
const replaceInstructions = []
const copies = []
for (const attachment of attachments) {
@@ -373,13 +378,13 @@ function handleAttachmentLinkPaste (storageKey, noteKey, linkText) {
sander.exists(absPathOfAttachment)
.then((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()})
return Promise.resolve()
}
return this.copyAttachment(absPathOfAttachment, storageKey, noteKey)
.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({
regexp: replaceLinkRegExp,
replacement: '(' + path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, fileName) + ')'
@@ -408,7 +413,7 @@ module.exports = {
generateAttachmentMarkdown,
handleAttachmentDrop,
handlePastImageEvent,
getAttachmentsInContent,
getAttachmentsInMarkdownContent,
getAbsolutePathsOfAttachmentsInContent,
removeStorageAndNoteReferences,
deleteAttachmentFolder,

View File

@@ -1,5 +1,6 @@
const dataApi = {
init: require('./init'),
toggleStorage: require('./toggleStorage'),
addStorage: require('./addStorage'),
renameStorage: require('./renameStorage'),
removeStorage: require('./removeStorage'),

View File

@@ -8,7 +8,8 @@ function resolveStorageData (storageCache) {
key: storageCache.key,
name: storageCache.name,
type: storageCache.type,
path: storageCache.path
path: storageCache.path,
isOpen: storageCache.isOpen
}
const boostnoteJSONPath = path.join(storageCache.path, 'boostnote.json')

View 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

View File

@@ -12,8 +12,7 @@ class NewNoteModal extends React.Component {
constructor (props) {
super(props)
this.state = {
}
this.state = {}
}
componentDidMount () {
@@ -35,19 +34,20 @@ class NewNoteModal extends React.Component {
title: '',
content: ''
})
.then((note) => {
.then(note => {
const noteHash = note.key
dispatch({
type: 'UPDATE_NOTE',
note: note
})
hashHistory.push({
pathname: location.pathname,
query: {key: noteHash}
query: { key: noteHash }
})
ee.emit('list:jump', noteHash)
ee.emit('detail:focus')
this.props.close()
setTimeout(this.props.close, 200)
})
}
@@ -69,13 +69,15 @@ class NewNoteModal extends React.Component {
folder: folder,
title: '',
description: '',
snippets: [{
snippets: [
{
name: '',
mode: 'text',
content: ''
}]
}
]
})
.then((note) => {
.then(note => {
const noteHash = note.key
dispatch({
type: 'UPDATE_NOTE',
@@ -83,11 +85,11 @@ class NewNoteModal extends React.Component {
})
hashHistory.push({
pathname: location.pathname,
query: {key: noteHash}
query: { key: noteHash }
})
ee.emit('list:jump', noteHash)
ee.emit('detail:focus')
this.props.close()
setTimeout(this.props.close, 200)
})
}
@@ -106,49 +108,65 @@ class NewNoteModal extends React.Component {
render () {
return (
<div styleName='root'
<div
styleName='root'
tabIndex='-1'
onKeyDown={(e) => this.handleKeyDown(e)}
onKeyDown={e => this.handleKeyDown(e)}
>
<div styleName='header'>
<div styleName='title'>{i18n.__('Make a note')}</div>
</div>
<ModalEscButton handleEscButtonClick={(e) => this.handleCloseButtonClick(e)} />
<ModalEscButton
handleEscButtonClick={e => this.handleCloseButtonClick(e)}
/>
<div styleName='control'>
<button styleName='control-button'
onClick={(e) => this.handleMarkdownNoteButtonClick(e)}
onKeyDown={(e) => this.handleMarkdownNoteButtonKeyDown(e)}
<button
styleName='control-button'
onClick={e => this.handleMarkdownNoteButtonClick(e)}
onKeyDown={e => this.handleMarkdownNoteButtonKeyDown(e)}
ref='markdownButton'
>
<i styleName='control-button-icon'
className='fa fa-file-text-o'
/><br />
<span styleName='control-button-label'>{i18n.__('Markdown Note')}</span><br />
<span styleName='control-button-description'>{i18n.__('This format is for creating text documents. Checklists, code blocks and Latex blocks are available.')}</span>
<i styleName='control-button-icon' className='fa fa-file-text-o' />
<br />
<span styleName='control-button-label'>
{i18n.__('Markdown Note')}
</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 styleName='control-button'
onClick={(e) => this.handleSnippetNoteButtonClick(e)}
onKeyDown={(e) => this.handleSnippetNoteButtonKeyDown(e)}
<button
styleName='control-button'
onClick={e => this.handleSnippetNoteButtonClick(e)}
onKeyDown={e => this.handleSnippetNoteButtonKeyDown(e)}
ref='snippetButton'
>
<i styleName='control-button-icon'
className='fa fa-code'
/><br />
<span styleName='control-button-label'>{i18n.__('Snippet Note')}</span><br />
<span styleName='control-button-description'>{i18n.__('This format is for creating code snippets. Multiple snippets can be grouped into a single note.')}
<i styleName='control-button-icon' className='fa fa-code' /><br />
<span styleName='control-button-label'>
{i18n.__('Snippet Note')}
</span>
<br />
<span styleName='control-button-description'>
{i18n.__(
'This format is for creating code snippets. Multiple snippets can be grouped into a single note.'
)}
</span>
</button>
</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>
)
}
}
NewNoteModal.propTypes = {
}
NewNoteModal.propTypes = {}
export default CSSModules(NewNoteModal, styles)

View File

@@ -27,7 +27,12 @@ class SnippetEditor extends React.Component {
dragDrop: false,
foldGutter: true,
gutters: ['CodeMirror-linenumbers', 'CodeMirror-foldgutter'],
autoCloseBrackets: true,
autoCloseBrackets: {
pairs: '()[]{}\'\'""$$**``',
triples: '```"""\'\'\'',
explode: '[]{}``$$',
override: true
},
mode: 'null'
})
this.cm.setSize('100%', '100%')

View File

@@ -4,8 +4,7 @@ import CSSModules from 'browser/lib/CSSModules'
import dataApi from 'browser/main/lib/dataApi'
import i18n from 'browser/lib/i18n'
import eventEmitter from 'browser/main/lib/eventEmitter'
const { remote } = require('electron')
const { Menu, MenuItem } = remote
import context from 'browser/lib/context'
class SnippetList extends React.Component {
constructor (props) {
@@ -21,18 +20,17 @@ class SnippetList extends React.Component {
}
reloadSnippetList () {
dataApi.fetchSnippet().then(snippets => this.setState({snippets}))
dataApi.fetchSnippet().then(snippets => {
this.setState({snippets})
this.props.onSnippetSelect(snippets[0])
})
}
handleSnippetContextMenu (snippet) {
const menu = new Menu()
menu.append(new MenuItem({
context.popup([{
label: i18n.__('Delete snippet'),
click: () => {
this.deleteSnippet(snippet)
}
}))
menu.popup()
click: () => this.deleteSnippet(snippet)
}])
}
deleteSnippet (snippet) {
@@ -43,7 +41,7 @@ class SnippetList extends React.Component {
}
handleSnippetClick (snippet) {
this.props.onSnippetClick(snippet)
this.props.onSnippetSelect(snippet)
}
createSnippet () {
@@ -55,6 +53,16 @@ class SnippetList extends React.Component {
}).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 () {
const { snippets } = this.state
return (
@@ -70,7 +78,7 @@ class SnippetList extends React.Component {
{
snippets.map((snippet) => (
<li
styleName='snippet-item'
styleName={this.defineSnippetStyleName(snippet)}
key={snippet.id}
onContextMenu={() => this.handleSnippetContextMenu(snippet)}
onClick={() => this.handleSnippetClick(snippet)}>

View File

@@ -25,7 +25,7 @@ class SnippetTab extends React.Component {
}, 500)
}
handleSnippetClick (snippet) {
handleSnippetSelect (snippet) {
const { currentSnippet } = this.state
if (currentSnippet === null || currentSnippet.id !== snippet.id) {
dataApi.fetchSnippet(snippet.id).then(changedSnippet => {
@@ -66,8 +66,9 @@ class SnippetTab extends React.Component {
<div styleName='root'>
<div styleName='header'>{i18n.__('Snippets')}</div>
<SnippetList
onSnippetClick={this.handleSnippetClick.bind(this)}
onSnippetDeleted={this.handleDeleteSnippet.bind(this)} />
onSnippetSelect={this.handleSnippetSelect.bind(this)}
onSnippetDeleted={this.handleDeleteSnippet.bind(this)}
currentSnippet={currentSnippet} />
<div styleName='snippet-detail' style={{visibility: currentSnippet ? 'visible' : 'hidden'}}>
<div styleName='group-section'>
<div styleName='group-section-label'>{i18n.__('Snippet name')}</div>

View File

@@ -122,6 +122,10 @@
&:hover
background darken(#f5f5f5, 5)
.snippet-item-selected
@extend .snippet-list .snippet-item
background darken(#f5f5f5, 5)
.snippet-detail
width 70%
height calc(100% - 200px)
@@ -142,6 +146,8 @@ body[data-theme="default"], body[data-theme="white"]
background $ui-borderColor
&:hover
background darken($ui-backgroundColor, 5)
.snippet-item-selected
background darken($ui-backgroundColor, 5)
body[data-theme="dark"]
.snippets
@@ -152,8 +158,12 @@ body[data-theme="dark"]
background $ui-dark-borderColor
&:hover
background darken($ui-dark-backgroundColor, 5)
.snippet-item-selected
background darken($ui-dark-backgroundColor, 5)
.snippet-detail
color white
.group-control-button
colorDarkPrimaryButton()
body[data-theme="solarized-dark"]
.snippets
@@ -164,8 +174,12 @@ body[data-theme="solarized-dark"]
background $ui-solarized-dark-borderColor
&:hover
background darken($ui-solarized-dark-backgroundColor, 5)
.snippet-item-selected
background darken($ui-solarized-dark-backgroundColor, 5)
.snippet-detail
color white
.group-control-button
colorSolarizedDarkPrimaryButton()
body[data-theme="monokai"]
.snippets
@@ -176,5 +190,9 @@ body[data-theme="monokai"]
background $ui-monokai-borderColor
&:hover
background darken($ui-monokai-backgroundColor, 5)
.snippet-item-selected
background darken($ui-monokai-backgroundColor, 5)
.snippet-detail
color white
.group-control-button
colorMonokaiPrimaryButton()

View File

@@ -11,6 +11,7 @@ import 'codemirror-mode-elixir'
import _ from 'lodash'
import i18n from 'browser/lib/i18n'
import { getLanguages } from 'browser/lib/Languages'
import normalizeEditorFontFamily from 'browser/lib/normalizeEditorFontFamily'
const OSX = global.process.platform === 'darwin'
@@ -164,7 +165,7 @@ class UiTab extends React.Component {
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 enableEditRulersStyle = config.editor.enableRulers ? 'block' : 'none'
const customCSS = config.preview.customCSS
const fontFamily = normalizeEditorFontFamily(config.editor.fontFamily)
return (
<div styleName='root'>
<div styleName='group'>
@@ -262,8 +263,16 @@ class UiTab extends React.Component {
})
}
</select>
<div styleName='code-mirror'>
<ReactCodeMirror ref={e => (this.codeMirrorInstance = e)} value={codemirrorSampleCode} options={{ lineNumbers: true, readOnly: true, mode: 'javascript', theme: codemirrorTheme }} />
<div styleName='code-mirror' style={{fontFamily}}>
<ReactCodeMirror
ref={e => (this.codeMirrorInstance = e)}
value={codemirrorSampleCode}
options={{
lineNumbers: true,
readOnly: true,
mode: 'javascript',
theme: codemirrorTheme
}} />
</div>
</div>
</div>
@@ -596,7 +605,19 @@ class UiTab extends React.Component {
type='checkbox'
/>&nbsp;
{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>

View File

@@ -360,6 +360,12 @@ function data (state = defaultDataMap(), action) {
state.storageMap = new Map(state.storageMap)
state.storageMap.set(action.storage.key, action.storage)
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
}

View File

@@ -90,7 +90,7 @@ app.on('ready', function () {
mainWindow.setMenu(menu)
}
// Check update every hour
// Check update every day
setInterval(function () {
checkUpdate()
}, 1000 * 60 * 60 * 24)
@@ -106,7 +106,7 @@ app.on('ready', function () {
checkUpdate()
}
})
}, 10000)
}, 10 * 1000)
ipcServer = require('./ipcServer')
ipcServer.server.start()
})

View File

@@ -136,6 +136,15 @@ const file = {
{
type: 'separator'
},
{
label: 'Format Table',
click () {
mainWindow.webContents.send('code:format-table')
}
},
{
type: 'separator'
},
{
label: 'Print',
accelerator: 'CommandOrControl+P',
@@ -235,14 +244,14 @@ const view = {
},
{
label: 'Next Note',
accelerator: 'Control+J',
accelerator: 'CommandOrControl+]',
click () {
mainWindow.webContents.send('list:next')
}
},
{
label: 'Previous Note',
accelerator: 'Control+K',
accelerator: 'CommandOrControl+[',
click () {
mainWindow.webContents.send('list:prior')
}
@@ -267,6 +276,19 @@ const view = {
mainWindow.setFullScreen(!mainWindow.isFullScreen())
}
},
{
type: 'separator'
},
{
label: 'Toggle Side Bar',
accelerator: 'CommandOrControl+B',
click () {
mainWindow.webContents.send('editor:fullscreen')
}
},
{
type: 'separator'
},
{
role: 'zoomin',
accelerator: macOS ? 'CommandOrControl+Plus' : 'Control+='

View File

@@ -141,16 +141,16 @@
"Portuguese": "Portugais",
"Spanish": "Espagnol",
"You have to save!": "Il faut sauvegarder !",
"Russian": "Russian",
"Russian": "Russe",
"Command(⌘)": "Command(⌘)",
"Editor Rulers": "Editor Rulers",
"Enable": "Enable",
"Disable": "Disable",
"Allow preview to scroll past the last line": "Allow preview to scroll past the last line",
"Editor Rulers": "Règles dans l'éditeur",
"Enable": "Activer",
"Disable": "Désactiver",
"Allow preview to scroll past the last line": "Permettre de scroller après la dernière ligne dans l'aperçu",
"Sanitization": "Sanitization",
"Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)",
"Allow styles": "Allow styles",
"Allow dangerous html tags": "Allow dangerous html tags",
"Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.",
"⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠"
"Only allow secure html tags (recommended)": "N'accepter que les tags html sécurisés (recommandé)",
"Allow styles": "Accepter les styles",
"Allow dangerous html tags": "Accepter les tags html dangereux",
"Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "Convertir des flèches textuelles en jolis signes. ⚠ Cela va interferérer avec les éventuels commentaires HTML dans votre Markdown.",
"⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ Vous avez collé un lien qui référence une pièce-jointe qui n'a pas pu être récupéré dans le dossier de stockage de la note. Coller des liens qui font référence à des pièces-jointes ne fonctionne que si la source et la destination et la même. Veuillez plutôt utiliser du Drag & Drop ! ⚠"
}

View File

@@ -4,10 +4,10 @@
"Preferences": "偏好設定",
"Make a note": "做點筆記",
"Ctrl": "Ctrl",
"Ctrl(^)": "Ctrl",
"Ctrl(^)": "Ctrl(^)",
"to create a new note": "新增筆記",
"Toggle Mode": "切換模式",
"Trash": "廢紙簍",
"Trash": "垃圾桶",
"MODIFICATION DATE": "修改時間",
"Words": "單字",
"Letters": "字數",
@@ -20,8 +20,8 @@
".html": ".html",
"Print": "列印",
"Your preferences for Boostnote": "Boostnote 偏好設定",
"Storages": "本機儲存空間",
"Add Storage Location": "新增一個本機儲存位置",
"Storages": "儲存空間",
"Add Storage Location": "新增儲存位置",
"Add Folder": "新增資料夾",
"Open Storage folder": "開啟儲存資料夾",
"Unlink": "解除連結",
@@ -43,12 +43,12 @@
"Switch to Preview": "切回預覽頁面的時機",
"When Editor Blurred": "當編輯器失去焦點時",
"When Editor Blurred, Edit On Double Click": "當編輯器失去焦點時,雙擊切換到編輯畫面",
"On Right Click": "點右鍵切換兩個頁面",
"On Right Click": "點右鍵切換兩個頁面",
"Editor Keymap": "編輯器 Keymap",
"default": "預設",
"vim": "vim",
"emacs": "emacs",
"⚠️ Please restart boostnote after you change the keymap": "⚠️ 請重新開啟 Boostnote 以完成設定。",
"⚠️ Please restart boostnote after you change the keymap": "⚠️ 修改鍵盤配置請重新開啟 Boostnote ",
"Show line numbers in the editor": "在編輯器中顯示行號",
"Allow editor to scroll past the last line": "允許編輯器捲軸捲動超過最後一行",
"Bring in web page title when pasting URL on editor": "在編輯器貼上網址的時候,自動加上網頁標題",
@@ -79,7 +79,7 @@
"Analytics": "分析",
"Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.": "Boostnote 收集匿名資料單純只為了提升軟體使用體驗,絕對不收集任何個人資料(包括筆記內容)",
"You can see how it works on ": "你可以看看它的程式碼是如何運作 ",
"You can choose to enable or disable this option.": "你可以選擇啟用或用這項功能",
"You can choose to enable or disable this option.": "你可以選擇啟用或用這項功能",
"Enable analytics to help improve Boostnote": "允許數據分析以協助我們改進 Boostnote",
"Crowdfunding": "群眾募資",
"Dear everyone,": "親愛的用戶:",
@@ -104,9 +104,9 @@
"Confirm": "確認",
"Cancel": "取消",
"Markdown Note": "Markdown 筆記",
"This format is for creating text documents. Checklists, code blocks and Latex blocks are available.": "建立文件、清單,也可以使用程式碼區塊甚至是 Latex 區塊。",
"This format is for creating text documents. Checklists, code blocks and Latex blocks are available.": "建立文件、清單,也可以使用程式碼區塊 Latex 區塊。",
"Snippet Note": "程式碼片段筆記",
"This format is for creating code snippets. Multiple snippets can be grouped into a single note.": "建立程式碼區塊片段。個程式碼區塊可以合在同一個筆記。",
"This format is for creating code snippets. Multiple snippets can be grouped into a single note.": "建立程式碼區塊片段。個程式碼區塊可以分組爲同一個筆記。",
"Tab to switch format": "使用 Tab 鍵切換格式",
"Updated": "依更新時間排序",
"Created": "依建立時間排序",
@@ -117,12 +117,12 @@
"Blog Type": "部落格類型",
"Blog Address": "部落格網址",
"Save": "儲存",
"Auth": "Auth",
"Auth": "驗證",
"Authentication Method": "認證方法",
"JWT": "JWT",
"USER": "USER",
"Token": "Token",
"Storage": "本機儲存空間",
"Storage": "儲存空間",
"Hotkeys": "快捷鍵",
"Show/Hide Boostnote": "顯示/隱藏 Boostnote",
"Restore": "還原",
@@ -144,7 +144,7 @@
"Russian": "Russian",
"Editor Rulers": "編輯器中顯示垂直尺規",
"Enable": "啟用",
"Disable": "用",
"Disable": "用",
"Sanitization": "過濾 HTML 程式碼",
"Only allow secure html tags (recommended)": "只允許安全的 HTML 標籤 (建議)",
"Allow styles": "允許樣式",

View File

@@ -1,7 +1,7 @@
{
"name": "boost",
"productName": "Boostnote",
"version": "0.11.6",
"version": "0.11.8",
"main": "index.js",
"description": "Boostnote",
"license": "GPL-3.0",
@@ -17,7 +17,7 @@
"dev-start": "concurrently --kill-others \"npm run webpack\" \"npm run hot\""
},
"config": {
"electron-version": "1.8.7"
"electron-version": "2.0.3"
},
"repository": {
"type": "git",
@@ -51,13 +51,16 @@
"dependencies": {
"@rokt33r/markdown-it-math": "^4.0.1",
"@rokt33r/season": "^5.3.0",
"@susisu/mte-kernel": "^2.0.0",
"aws-sdk": "^2.48.0",
"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",
"electron-config": "^0.2.1",
"electron-gh-releases": "^2.0.2",
"escape-string-regexp": "^1.0.5",
"file-url": "^2.0.2",
"filenamify": "^2.0.0",
"flowchart.js": "^1.6.5",
"font-awesome": "^4.3.0",
@@ -71,17 +74,16 @@
"lodash-move": "^1.1.1",
"markdown-it": "^6.0.1",
"markdown-it-admonition": "https://github.com/johannbre/markdown-it-admonition.git",
"markdown-it-checkbox": "^1.1.0",
"markdown-it-emoji": "^1.1.1",
"markdown-it-footnote": "^3.0.0",
"markdown-it-imsize": "^2.0.1",
"markdown-it-kbd": "^1.1.1",
"markdown-it-multimd-table": "^2.0.1",
"markdown-it-named-headers": "^0.0.4",
"markdown-it-plantuml": "^0.3.0",
"markdown-it-plantuml": "^1.1.0",
"markdown-it-smartarrows": "^1.0.1",
"md5": "^2.0.0",
"mdurl": "^1.0.1",
"mermaid": "^8.0.0-rc.8",
"moment": "^2.10.3",
"mousetrap": "^1.6.1",
"mousetrap-global-bind": "^1.1.0",
@@ -97,8 +99,6 @@
"sander": "^0.5.1",
"sanitize-html": "^1.18.2",
"striptags": "^2.2.1",
"superagent": "^1.2.0",
"superagent-promise": "^1.0.3",
"unique-slug": "2.0.0",
"uuid": "^3.2.1"
},
@@ -120,7 +120,7 @@
"css-loader": "^0.19.0",
"devtron": "^1.1.0",
"dom-storage": "^2.0.2",
"electron": "2.0.2",
"electron": "2.0.3",
"electron-packager": "^6.0.0",
"eslint": "^3.13.1",
"eslint-config-standard": "^6.2.1",

View File

@@ -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.
![Boostnote app screenshot](./resources/repository/top.png)
@@ -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>
## 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:
- [Become a backer or sponsor on Open Collective.](https://opencollective.com/boostnoteio)
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.
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
- [Facebook Group](https://www.facebook.com/groups/boostnote/)
- [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)
- [Reddit](https://www.reddit.com/r/Boostnote/)

View File

@@ -169,6 +169,43 @@ it('should replace the all ":storage" path with the actual storage path', functi
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 () {
const fileName = 'fileName'
const path = 'path'
@@ -180,27 +217,35 @@ it('should test that generateAttachmentMarkdown works correct both with previews
expect(actual).toEqual(expected)
})
it('should test that getAttachmentsInContent finds all attachments', function () {
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.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
' </p>\n' +
' <p data-line="4">\n' +
' <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' +
' <p data-line="6">\n' +
' <img src=":storage' + mdurl.encode(path.sep) + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + mdurl.encode(path.sep) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
' </p>\n' +
' </body>\n' +
'</html>'
const actual = systemUnderTest.getAttachmentsInContent(testInput)
const expected = [':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.6r4zdgc22xp', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.q2i4iw0fyx', ':storage' + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + 'd6c5ee92.jpg']
it('should test that migrateAttachments work when they have different path separators', function () {
sander.existsSync = jest.fn(() => true)
const dummyStoragePath = 'dummyStoragePath'
const imagesPath = path.join(dummyStoragePath, 'images')
const attachmentsPath = path.join(dummyStoragePath, 'attachments')
const noteKey = 'noteKey'
const testInput = '"# Test\n' +
'\n' +
'![Screenshot1](:storage' + path.win32.sep + '0.3b88d0dc.png)\n' +
'![Screenshot2](:storage' + path.posix.sep + '0.2cb8875c.pdf)"'
systemUnderTest.migrateAttachments(testInput, dummyStoragePath, noteKey)
expect(sander.existsSync.mock.calls[0][0]).toBe(imagesPath)
expect(sander.existsSync.mock.calls[1][0]).toBe(path.join(imagesPath, '0.3b88d0dc.png'))
expect(sander.existsSync.mock.calls[2][0]).toBe(path.join(attachmentsPath, '0.3b88d0dc.png'))
expect(sander.existsSync.mock.calls[3][0]).toBe(path.join(imagesPath, '0.2cb8875c.pdf'))
expect(sander.existsSync.mock.calls[4][0]).toBe(path.join(attachmentsPath, '0.2cb8875c.pdf'))
})
it('should test that getAttachmentsInMarkdownContent finds all attachments when they have different path separators', function () {
const testInput = '"# Test\n' +
'\n' +
'![Screenshot1](:storage' + path.win32.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.win32.sep + '0.3b88d0dc.png)\n' +
'![Screenshot2](:storage' + path.posix.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.posix.sep + '2cb8875c.pdf)\n' +
'![Screenshot3](:storage' + path.win32.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.posix.sep + 'bbf49b02.jpg)"'
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))
})
@@ -225,8 +270,8 @@ it('should test that getAbsolutePathsOfAttachmentsInContent returns all absolute
' </body>\n' +
'</html>'
const actual = systemUnderTest.getAbsolutePathsOfAttachmentsInContent(testInput, dummyStoragePath)
const expected = [dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.6r4zdgc22xp',
dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.q2i4iw0fyx',
const expected = [dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.6r4zdgc22xp.png',
dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + '0.q2i4iw0fyx.pdf',
dummyStoragePath + path.sep + systemUnderTest.DESTINATION_FOLDER + path.sep + '9c9c4ba3-bc1e-441f-9866-c1e9a806e31c' + path.sep + 'd6c5ee92.jpg']
expect(actual).toEqual(expect.arrayContaining(expected))
})

View 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)
})

View 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>
&lt;escapeMe&gt;`
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 &amp;'
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 = ` &lt;no escape&gt;
&lt;escapeMe&gt;`
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 &amp; or &quot; but do escape &'
const expected = 'Do not escape &amp; or &quot; but do escape &amp;'
const actual = escapeHtmlCharacters(input)
t.is(actual, expected)
})
test('escapeHtmlCharacters should return the correct result', t => {
const input = '& < > " \''
const expected = '&amp; &lt; &gt; &quot; &#39;'
const actual = escapeHtmlCharacters(input)
t.is(actual, expected)
})

View 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(', ')}`)
})

View File

@@ -28,16 +28,12 @@ var config = {
externals: [
'node-ipc',
'electron',
'md5',
'superagent',
'superagent-promise',
'lodash',
'markdown-it',
'moment',
'markdown-it-emoji',
'fs-jetpack',
'@rokt33r/markdown-it-math',
'markdown-it-checkbox',
'markdown-it-kbd',
'markdown-it-plantuml',
'markdown-it-admonition',

446
yarn.lock
View File

@@ -79,6 +79,12 @@
fs-plus "2.x"
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":
version "8.10.17"
resolved "https://registry.yarnpkg.com/@types/node/-/node-8.10.17.tgz#d48cf10f0dc6dcf59f827f5a3fc7a4a6004318d3"
@@ -1574,9 +1580,25 @@ chalk@^2.0.0, chalk@^2.0.1, chalk@^2.3.0, chalk@^2.4.1:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
charenc@~0.0.1:
version "0.0.2"
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
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:
version "1.7.0"
@@ -1731,10 +1753,14 @@ codemirror-mode-elixir@^1.1.1:
dependencies:
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"
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:
version "1.12.7"
resolved "https://registry.yarnpkg.com/coffee-script/-/coffee-script-1.12.7.tgz#c05dae0cb79591d05b3070a8433a98c9a89ccc53"
@@ -1750,6 +1776,10 @@ collection-visit@^1.0.0:
map-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:
version "1.9.1"
resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.1.tgz#c1261107aeb2f294ebffec9ed9ecad529a6097ed"
@@ -1794,7 +1824,7 @@ colors@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/colors/-/colors-1.1.2.tgz#168a4701756b6a7f51a12ce0c97bfa28c084ed63"
combined-stream@1.0.6, combined-stream@^1.0.5, combined-stream@~1.0.5:
combined-stream@1.0.6, combined-stream@~1.0.5:
version "1.0.6"
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
dependencies:
@@ -1806,6 +1836,10 @@ combined-stream@~0.0.4, combined-stream@~0.0.5:
dependencies:
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:
version "2.3.0"
resolved "https://registry.yarnpkg.com/commander/-/commander-2.3.0.tgz#fd430e889832ec353b9acd1de217c11cb3eef873"
@@ -1830,7 +1864,7 @@ compare-versions@^3.1.0:
version "3.2.1"
resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-3.2.1.tgz#a49eb7689d4caaf0b6db5220173fd279614000f7"
component-emitter@^1.2.1, component-emitter@~1.2.0:
component-emitter@^1.2.1:
version "1.2.1"
resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.2.1.tgz#137918d6d78283f7df7a6b7c5a63e140e69425e6"
@@ -1960,10 +1994,6 @@ cookie@0.3.1:
version "0.3.1"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.3.1.tgz#e7e0a1f9ef43b4c8ba925c5c5a96e806d16873bb"
cookiejar@2.0.6:
version "2.0.6"
resolved "https://registry.yarnpkg.com/cookiejar/-/cookiejar-2.0.6.tgz#0abf356ad00d1c5a219d88d44518046dd026acfe"
copy-descriptor@^0.1.0:
version "0.1.1"
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
@@ -2015,10 +2045,6 @@ cross-spawn@^5.0.1:
shebang-command "^1.2.0"
which "^1.2.9"
crypt@~0.0.1:
version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
cryptiles@2.x.x:
version "2.0.5"
resolved "https://registry.yarnpkg.com/cryptiles/-/cryptiles-2.0.5.tgz#3bdfecdc608147c1c67202fa291e7dca59eaa3b8"
@@ -2154,12 +2180,250 @@ currently-unhandled@^0.4.1:
dependencies:
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:
version "1.0.0"
resolved "https://registry.yarnpkg.com/d/-/d-1.0.0.tgz#754bb5bfe55451da69a58b94d45f4c5b0462d58f"
dependencies:
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:
version "1.14.1"
resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0"
@@ -2206,7 +2470,7 @@ debug@*, debug@^3.0.1, debug@^3.1.0:
dependencies:
ms "2.0.0"
debug@2, debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9:
debug@2.6.9, debug@^2.1.1, debug@^2.1.2, debug@^2.1.3, debug@^2.2.0, debug@^2.3.3, debug@^2.6.6, debug@^2.6.8, debug@^2.6.9:
version "2.6.9"
resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f"
dependencies:
@@ -2577,9 +2841,9 @@ electron-winstaller@^2.2.0:
lodash.template "^4.2.2"
temp "^0.8.3"
electron@2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/electron/-/electron-2.0.2.tgz#b77e05f83419cc5ec921a2d21f35b55e4bfc3d68"
electron@2.0.3:
version "2.0.3"
resolved "https://registry.yarnpkg.com/electron/-/electron-2.0.3.tgz#8e591e820cae2ccdb0c3fd74c6d07834913fc133"
dependencies:
"@types/node" "^8.0.24"
electron-download "^3.0.1"
@@ -3082,10 +3346,6 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
extend@3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.0.tgz#5a474353b9f3353ddd8176dfd37b91c83a46f1d4"
extend@~3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.1.tgz#a755ea7bc1adfcc5a31ce7e762dbaadc5e636444"
@@ -3206,6 +3466,10 @@ file-entry-cache@^2.0.0:
flat-cache "^1.2.1"
object-assign "^4.0.1"
file-url@^2.0.2:
version "2.0.2"
resolved "https://registry.yarnpkg.com/file-url/-/file-url-2.0.2.tgz#e951784d79095127d3713029ab063f40818ca2ae"
filename-regex@^2.0.0:
version "2.0.1"
resolved "https://registry.yarnpkg.com/filename-regex/-/filename-regex-2.0.1.tgz#c1c4b9bee3e09725ddb106b75c1e301fe2f18b26"
@@ -3351,14 +3615,6 @@ forever-agent@~0.6.0, forever-agent@~0.6.1:
version "0.6.1"
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
form-data@1.0.0-rc3:
version "1.0.0-rc3"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-1.0.0-rc3.tgz#d35bc62e7fbc2937ae78f948aaa0d38d90607577"
dependencies:
async "^1.4.0"
combined-stream "^1.0.5"
mime-types "^2.1.3"
form-data@~0.2.0:
version "0.2.0"
resolved "https://registry.yarnpkg.com/form-data/-/form-data-0.2.0.tgz#26f8bc26da6440e299cbdcfb69035c4f77a6e466"
@@ -3375,10 +3631,6 @@ form-data@~2.3.1:
combined-stream "1.0.6"
mime-types "^2.1.12"
formidable@~1.0.14:
version "1.0.17"
resolved "https://registry.yarnpkg.com/formidable/-/formidable-1.0.17.tgz#ef5491490f9433b705faa77249c99029ae348559"
forwarded@~0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84"
@@ -3705,6 +3957,12 @@ graceful-fs@~1.2.0:
version "1.2.3"
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:
version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
@@ -3894,6 +4152,10 @@ hawk@~2.3.0:
hoek "2.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:
version "9.12.0"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.12.0.tgz#e6d9dbe57cbefe60751f02af336195870c90c01e"
@@ -4057,16 +4319,16 @@ i18n-2@^0.7.2:
debug "^3.1.0"
sprintf "^0.1.5"
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.4.19, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
iconv-lite@0.4, iconv-lite@^0.4.19, iconv-lite@^0.4.4, iconv-lite@~0.4.13:
version "0.4.23"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.23.tgz#297871f63be507adcfbfca715d0cd0eed84e9a63"
dependencies:
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:
version "0.2.11"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.2.11.tgz#1ce60a3a57864a292d1321ff4609ca4bb965adc8"
@@ -4236,7 +4498,7 @@ is-binary-path@^1.0.0:
dependencies:
binary-extensions "^1.0.0"
is-buffer@^1.1.5, is-buffer@~1.1.1:
is-buffer@^1.1.5:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
@@ -5318,7 +5580,7 @@ lodash@^3.5.0:
version "3.10.1"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-3.10.1.tgz#5bf45e8e49ba4189e17d482789dfd15bd140b7b6"
lodash@^4.0.0, lodash@^4.0.1, lodash@^4.11.1, lodash@^4.12.0, lodash@^4.13.1, lodash@^4.17.10, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.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"
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.10.tgz#1b7793cf7259ea38fb3661d4d38b3260af8ae4e7"
@@ -5392,12 +5654,6 @@ map-visit@^1.0.0:
version "1.0.2"
resolved "https://github.com/johannbre/markdown-it-admonition.git#e0c0fcd59e9119d6d60ed209aa3d0f1177ec0166"
markdown-it-checkbox@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/markdown-it-checkbox/-/markdown-it-checkbox-1.1.0.tgz#20cff97f33d77d172f9dcf1bcfc92cecc5330fac"
dependencies:
underscore "^1.8.2"
markdown-it-emoji@^1.1.1:
version "1.4.0"
resolved "https://registry.yarnpkg.com/markdown-it-emoji/-/markdown-it-emoji-1.4.0.tgz#9bee0e9a990a963ba96df6980c4fddb05dfb4dcc"
@@ -5426,9 +5682,9 @@ markdown-it-named-headers@^0.0.4:
dependencies:
string "^3.0.1"
markdown-it-plantuml@^0.3.0:
version "0.3.2"
resolved "https://registry.yarnpkg.com/markdown-it-plantuml/-/markdown-it-plantuml-0.3.2.tgz#f93a49bdfc8417b0df3c88700445f53487e57356"
markdown-it-plantuml@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/markdown-it-plantuml/-/markdown-it-plantuml-1.1.0.tgz#9ab8bfa09a02d80845e16e60f87a488edb50fdde"
markdown-it-smartarrows@^1.0.1:
version "1.0.1"
@@ -5492,18 +5748,14 @@ md5-o-matic@^0.1.1:
version "0.1.1"
resolved "https://registry.yarnpkg.com/md5-o-matic/-/md5-o-matic-0.1.1.tgz#822bccd65e117c514fab176b25945d54100a03c3"
md5@^2.0.0:
version "2.2.1"
resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
dependencies:
charenc "~0.0.1"
crypt "~0.0.1"
is-buffer "~1.1.1"
mdurl@^1.0.1, mdurl@~1.0.1:
version "1.0.1"
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:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@@ -5561,7 +5813,20 @@ merge@^1.1.3:
version "1.2.0"
resolved "https://registry.yarnpkg.com/merge/-/merge-1.2.0.tgz#7531e39d4949c281a66b8c5a6e0265e8b05894da"
methods@~1.1.1, methods@~1.1.2:
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:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
@@ -5609,7 +5874,7 @@ mime-db@~1.12.0:
version "1.12.0"
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.12.0.tgz#3d0c63180f458eb10d325aaa37d7c58ae312e9d7"
mime-types@^2.1.12, mime-types@^2.1.3, mime-types@~2.1.17, mime-types@~2.1.18:
mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18:
version "2.1.18"
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.18.tgz#6f323f60a83d11146f831ff11fd66e2fe5503bb8"
dependencies:
@@ -5621,10 +5886,6 @@ mime-types@~2.0.1, mime-types@~2.0.3:
dependencies:
mime-db "~1.12.0"
mime@1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.3.4.tgz#115f9e3b6b3daf2959983cb38f149a2d40eb5d53"
mime@1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
@@ -5734,6 +5995,10 @@ mock-require@^3.0.1:
get-caller-file "^1.0.2"
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:
version "2.22.1"
resolved "https://registry.yarnpkg.com/moment/-/moment-2.22.1.tgz#529a2e9bf973f259c9643d237fda84de3a26e8ad"
@@ -6779,10 +7044,6 @@ q@^1.1.2:
version "1.5.1"
resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7"
qs@2.3.3:
version "2.3.3"
resolved "https://registry.yarnpkg.com/qs/-/qs-2.3.3.tgz#e9e85adbe75da0bbe4c8e0476a086290f863b404"
qs@6.5.1:
version "6.5.1"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
@@ -7030,15 +7291,6 @@ read-pkg@^2.0.0:
normalize-package-data "^2.3.2"
path-type "^2.0.0"
readable-stream@1.0.27-1:
version "1.0.27-1"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.0.27-1.tgz#6b67983c20357cefd07f0165001a16d710d91078"
dependencies:
core-util-is "~1.0.0"
inherits "~2.0.1"
isarray "0.0.1"
string_decoder "~0.10.x"
readable-stream@^1.1.8, readable-stream@~1.1.9:
version "1.1.14"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-1.1.14.tgz#7cf4c54ef648e3813084c636dd2079e166c081d9"
@@ -7114,10 +7366,6 @@ redent@^1.0.0:
indent-string "^2.1.0"
strip-indent "^1.0.1"
reduce-component@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/reduce-component/-/reduce-component-1.0.1.tgz#e0c93542c574521bea13df0f9488ed82ab77c5da"
reduce-css-calc@^1.2.6:
version "1.3.0"
resolved "https://registry.yarnpkg.com/reduce-css-calc/-/reduce-css-calc-1.3.0.tgz#747c914e049614a4c9cfbba629871ad1d2927716"
@@ -7400,6 +7648,10 @@ run-series@^1.1.1:
version "1.1.8"
resolved "https://registry.yarnpkg.com/run-series/-/run-series-1.1.8.tgz#2c4558f49221e01cd6371ff4e0a1e203e460fc36"
rw@1:
version "1.3.3"
resolved "http://registry.npm.taobao.org/rw/download/rw-1.3.3.tgz#3f862dfa91ab766b14885ef4d01124bfda074fb4"
rx-lite@^3.1.2:
version "3.1.2"
resolved "https://registry.yarnpkg.com/rx-lite/-/rx-lite-3.1.2.tgz#19ce502ca572665f3b647b10939f97fd1615f102"
@@ -7477,6 +7729,10 @@ sax@>=0.6.0, sax@^1.2.1, sax@^1.2.4, sax@~1.2.1:
version "1.2.4"
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:
version "2.1.0"
resolved "https://registry.yarnpkg.com/semver-diff/-/semver-diff-2.1.0.tgz#4bbb8437c8d37e4b0cf1a68fd726ec6d645d6d36"
@@ -8043,26 +8299,6 @@ sumchecker@^1.2.0:
debug "^2.2.0"
es6-promise "^4.0.5"
superagent-promise@^1.0.3:
version "1.1.0"
resolved "https://registry.yarnpkg.com/superagent-promise/-/superagent-promise-1.1.0.tgz#baf22d8bbdd439a9b07dd10f8c08f54fe2503533"
superagent@^1.2.0:
version "1.8.5"
resolved "https://registry.yarnpkg.com/superagent/-/superagent-1.8.5.tgz#1c0ddc3af30e80eb84ebc05cb2122da8fe940b55"
dependencies:
component-emitter "~1.2.0"
cookiejar "2.0.6"
debug "2"
extend "3.0.0"
form-data "1.0.0-rc3"
formidable "~1.0.14"
methods "~1.1.1"
mime "1.3.4"
qs "2.3.3"
readable-stream "1.0.27-1"
reduce-component "1.0.1"
supertap@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/supertap/-/supertap-1.0.0.tgz#bd9751c7fafd68c68cf8222a29892206a119fa9e"
@@ -8402,10 +8638,6 @@ underscore.string@~2.4.0:
version "2.4.0"
resolved "https://registry.yarnpkg.com/underscore.string/-/underscore.string-2.4.0.tgz#8cdd8fbac4e2d2ea1e7e2e8097c42f442280f85b"
underscore@^1.8.2:
version "1.9.0"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.9.0.tgz#31dbb314cfcc88f169cd3692d9149d81a00a73e4"
underscore@~1.4.x:
version "1.4.4"
resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.4.4.tgz#61a6a32010622afa07963bf325203cf12239d604"
@@ -8901,6 +9133,10 @@ xmldom@0.1.x:
version "0.1.27"
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:
version "4.0.1"
resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.1.tgz#a5c6d532be656e23db820efb943a1f04998d63af"