mirror of
https://github.com/BoostIo/Boostnote
synced 2025-12-21 13:41:40 +00:00
Compare commits
43 Commits
v0.16.0
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7f1bc3d84c | ||
|
|
789926bc76 | ||
|
|
006795b4d0 | ||
|
|
3e5d78d322 | ||
|
|
58c4a78be1 | ||
|
|
2603dfc1ed | ||
|
|
2df590600b | ||
|
|
ef20a8f3e5 | ||
|
|
3e405e1abf | ||
|
|
553832bdfa | ||
|
|
18d65d999a | ||
|
|
3b5eff582a | ||
|
|
85d09b3b3d | ||
|
|
8958e67fcf | ||
|
|
47b796909a | ||
|
|
67d76abdfa | ||
|
|
d75d68ba72 | ||
|
|
323be6b72d | ||
|
|
031a113338 | ||
|
|
b50c5386a6 | ||
|
|
65777b1d56 | ||
|
|
fe728874ac | ||
|
|
bd9b1306b1 | ||
|
|
0ca18d8ca5 | ||
|
|
87a530612f | ||
|
|
f4259bb4d0 | ||
|
|
aa8b589569 | ||
|
|
febc98c101 | ||
|
|
b678c3bd89 | ||
|
|
80b8948433 | ||
|
|
5414fe3384 | ||
|
|
db4016385d | ||
|
|
9d43e34cfa | ||
|
|
fa157f6f76 | ||
|
|
d6a54b8a26 | ||
|
|
9813412c8e | ||
|
|
d76b7235db | ||
|
|
418a789568 | ||
|
|
2d941c3ea3 | ||
|
|
e723d4cd59 | ||
|
|
9e770ef357 | ||
|
|
c796b3b30e | ||
|
|
168fe212f5 |
@@ -63,7 +63,7 @@ export default class CodeEditor extends React.Component {
|
||||
this.focusHandler = () => {
|
||||
ipcRenderer.send('editor:focused', true)
|
||||
}
|
||||
const debouncedDeletionOfAttachments = _.debounce(
|
||||
this.debouncedDeletionOfAttachments = _.debounce(
|
||||
attachmentManagement.deleteAttachmentsNotPresentInNote,
|
||||
30000
|
||||
)
|
||||
@@ -80,7 +80,7 @@ export default class CodeEditor extends React.Component {
|
||||
this.props.onBlur != null && this.props.onBlur(e)
|
||||
const { storageKey, noteKey } = this.props
|
||||
if (this.props.deleteUnusedAttachments === true) {
|
||||
debouncedDeletionOfAttachments(
|
||||
this.debouncedDeletionOfAttachments(
|
||||
this.editor.getValue(),
|
||||
storageKey,
|
||||
noteKey
|
||||
@@ -810,6 +810,8 @@ export default class CodeEditor extends React.Component {
|
||||
}
|
||||
|
||||
handleChange(editor, changeObject) {
|
||||
this.debouncedDeletionOfAttachments.cancel()
|
||||
|
||||
spellcheck.handleChange(editor, changeObject)
|
||||
|
||||
// The current note contains an toc. We'll check for changes on headlines.
|
||||
|
||||
@@ -323,6 +323,7 @@ class MarkdownEditor extends React.Component {
|
||||
storageKey,
|
||||
noteKey,
|
||||
linesHighlighted,
|
||||
getNote,
|
||||
RTL
|
||||
} = this.props
|
||||
|
||||
@@ -426,6 +427,8 @@ class MarkdownEditor extends React.Component {
|
||||
customCSS={config.preview.customCSS}
|
||||
allowCustomCSS={config.preview.allowCustomCSS}
|
||||
lineThroughCheckbox={config.preview.lineThroughCheckbox}
|
||||
getNote={getNote}
|
||||
export={config.export}
|
||||
onDrop={e => this.handleDropImage(e)}
|
||||
RTL={RTL}
|
||||
/>
|
||||
|
||||
@@ -18,258 +18,30 @@ import convertModeName from 'browser/lib/convertModeName'
|
||||
import copy from 'copy-to-clipboard'
|
||||
import mdurl from 'mdurl'
|
||||
import exportNote from 'browser/main/lib/dataApi/exportNote'
|
||||
import { escapeHtmlCharacters } from 'browser/lib/utils'
|
||||
import formatMarkdown from 'browser/main/lib/dataApi/formatMarkdown'
|
||||
import formatHTML, {
|
||||
CSS_FILES,
|
||||
buildStyle,
|
||||
getCodeThemeLink,
|
||||
getStyleParams,
|
||||
escapeHtmlCharactersInCodeTag
|
||||
} from 'browser/main/lib/dataApi/formatHTML'
|
||||
import formatPDF from 'browser/main/lib/dataApi/formatPDF'
|
||||
import yaml from 'js-yaml'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
import path from 'path'
|
||||
import { remote, shell } from 'electron'
|
||||
import attachmentManagement from '../main/lib/dataApi/attachmentManagement'
|
||||
import filenamify from 'filenamify'
|
||||
import { render } from 'react-dom'
|
||||
import Carousel from 'react-image-carousel'
|
||||
import { push } from 'connected-react-router'
|
||||
import ConfigManager from '../main/lib/ConfigManager'
|
||||
import uiThemes from 'browser/lib/ui-themes'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
const { remote, shell } = require('electron')
|
||||
const attachmentManagement = require('../main/lib/dataApi/attachmentManagement')
|
||||
const buildMarkdownPreviewContextMenu = require('browser/lib/contextMenuBuilder')
|
||||
.buildMarkdownPreviewContextMenu
|
||||
|
||||
const { app } = remote
|
||||
const path = require('path')
|
||||
const fileUrl = require('file-url')
|
||||
import { buildMarkdownPreviewContextMenu } from 'browser/lib/contextMenuBuilder'
|
||||
|
||||
const dialog = remote.dialog
|
||||
|
||||
const markdownStyle = require('!!css!stylus?sourceMap!./markdown.styl')[0][1]
|
||||
const appPath = fileUrl(
|
||||
process.env.NODE_ENV === 'production' ? app.getAppPath() : path.resolve()
|
||||
)
|
||||
const CSS_FILES = [
|
||||
`${appPath}/node_modules/katex/dist/katex.min.css`,
|
||||
`${appPath}/node_modules/codemirror/lib/codemirror.css`,
|
||||
`${appPath}/node_modules/react-image-carousel/lib/css/main.min.css`
|
||||
]
|
||||
|
||||
/**
|
||||
* @param {Object} opts
|
||||
* @param {String} opts.fontFamily
|
||||
* @param {Numberl} opts.fontSize
|
||||
* @param {String} opts.codeBlockFontFamily
|
||||
* @param {String} opts.theme
|
||||
* @param {Boolean} [opts.lineNumber] Should show line number
|
||||
* @param {Boolean} [opts.scrollPastEnd]
|
||||
* @param {Boolean} [opts.allowCustomCSS] Should add custom css
|
||||
* @param {String} [opts.customCSS] Will be added to bottom, only if `opts.allowCustomCSS` is truthy
|
||||
* @returns {String}
|
||||
*/
|
||||
function buildStyle(opts) {
|
||||
const {
|
||||
fontFamily,
|
||||
fontSize,
|
||||
codeBlockFontFamily,
|
||||
lineNumber,
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS,
|
||||
RTL
|
||||
} = opts
|
||||
return `
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
src: url('${appPath}/resources/fonts/Lato-Regular.woff2') format('woff2'), /* Modern Browsers */
|
||||
url('${appPath}/resources/fonts/Lato-Regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('${appPath}/resources/fonts/Lato-Regular.ttf') format('truetype');
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
src: url('${appPath}/resources/fonts/Lato-Black.woff2') format('woff2'), /* Modern Browsers */
|
||||
url('${appPath}/resources/fonts/Lato-Black.woff') format('woff'), /* Modern Browsers */
|
||||
url('${appPath}/resources/fonts/Lato-Black.ttf') format('truetype');
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Material Icons';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Material Icons'),
|
||||
local('MaterialIcons-Regular'),
|
||||
url('${appPath}/resources/fonts/MaterialIcons-Regular.woff2') format('woff2'),
|
||||
url('${appPath}/resources/fonts/MaterialIcons-Regular.woff') format('woff'),
|
||||
url('${appPath}/resources/fonts/MaterialIcons-Regular.ttf') format('truetype');
|
||||
}
|
||||
|
||||
${markdownStyle}
|
||||
|
||||
body {
|
||||
font-family: '${fontFamily.join("','")}';
|
||||
font-size: ${fontSize}px;
|
||||
|
||||
${
|
||||
scrollPastEnd
|
||||
? `
|
||||
padding-bottom: 90vh;
|
||||
box-sizing: border-box;
|
||||
`
|
||||
: ''
|
||||
}
|
||||
${RTL ? 'direction: rtl;' : ''}
|
||||
${RTL ? 'text-align: right;' : ''}
|
||||
}
|
||||
@media print {
|
||||
body {
|
||||
padding-bottom: initial;
|
||||
}
|
||||
}
|
||||
code {
|
||||
font-family: '${codeBlockFontFamily.join("','")}';
|
||||
background-color: rgba(0,0,0,0.04);
|
||||
text-align: left;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
p code,
|
||||
li code,
|
||||
td code
|
||||
{
|
||||
padding: 2px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-radius: 5px;
|
||||
}
|
||||
[data-theme="default"] p code,
|
||||
[data-theme="default"] li code,
|
||||
[data-theme="default"] td code
|
||||
{
|
||||
background-color: #F4F4F4;
|
||||
border-color: #d9d9d9;
|
||||
color: inherit;
|
||||
}
|
||||
[data-theme="white"] p code,
|
||||
[data-theme="white"] li code,
|
||||
[data-theme="white"] td code
|
||||
{
|
||||
background-color: #F4F4F4;
|
||||
border-color: #d9d9d9;
|
||||
color: inherit;
|
||||
}
|
||||
[data-theme="dark"] p code,
|
||||
[data-theme="dark"] li code,
|
||||
[data-theme="dark"] td code
|
||||
{
|
||||
background-color: #444444;
|
||||
border-color: #555;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
[data-theme="dracula"] p code,
|
||||
[data-theme="dracula"] li code,
|
||||
[data-theme="dracula"] td code
|
||||
{
|
||||
background-color: #444444;
|
||||
border-color: #555;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
[data-theme="monokai"] p code,
|
||||
[data-theme="monokai"] li code,
|
||||
[data-theme="monokai"] td code
|
||||
{
|
||||
background-color: #444444;
|
||||
border-color: #555;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
[data-theme="nord"] p code,
|
||||
[data-theme="nord"] li code,
|
||||
[data-theme="nord"] td code
|
||||
{
|
||||
background-color: #444444;
|
||||
border-color: #555;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
[data-theme="solarized-dark"] p code,
|
||||
[data-theme="solarized-dark"] li code,
|
||||
[data-theme="solarized-dark"] td code
|
||||
{
|
||||
background-color: #444444;
|
||||
border-color: #555;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
[data-theme="vulcan"] p code,
|
||||
[data-theme="vulcan"] li code,
|
||||
[data-theme="vulcan"] td code
|
||||
{
|
||||
background-color: #444444;
|
||||
border-color: #555;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.lineNumber {
|
||||
${lineNumber && 'display: block !important;'}
|
||||
font-family: '${codeBlockFontFamily.join("','")}';
|
||||
}
|
||||
|
||||
.clipboardButton {
|
||||
color: rgba(147,147,149,0.8);;
|
||||
fill: rgba(147,147,149,1);;
|
||||
border-radius: 50%;
|
||||
margin: 0px 10px;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
outline: none;
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.clipboardButton:hover {
|
||||
transition: 0.2s;
|
||||
color: #939395;
|
||||
fill: #939395;
|
||||
background-color: rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
border: none;
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin: 1em 0 0.8em;
|
||||
}
|
||||
|
||||
h4, h5, h6 {
|
||||
margin: 1.1em 0 0.5em;
|
||||
}
|
||||
|
||||
h1 {
|
||||
padding: 0.2em 0 0.2em;
|
||||
margin: 1em 0 8px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding: 0.2em 0 0.2em;
|
||||
margin: 1em 0 0.7em;
|
||||
}
|
||||
|
||||
body p {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
@media print {
|
||||
body[data-theme="${theme}"] {
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
}
|
||||
.clipboardButton {
|
||||
display: none
|
||||
}
|
||||
}
|
||||
|
||||
${allowCustomCSS ? customCSS : ''}
|
||||
`
|
||||
}
|
||||
|
||||
const scrollBarStyle = `
|
||||
::-webkit-scrollbar {
|
||||
${config.get().ui.showScrollBar ? '' : 'display: none;'}
|
||||
@@ -301,22 +73,6 @@ const scrollBarDarkStyle = `
|
||||
}
|
||||
`
|
||||
|
||||
const OSX = global.process.platform === 'darwin'
|
||||
|
||||
const defaultFontFamily = ['helvetica', 'arial', 'sans-serif']
|
||||
if (!OSX) {
|
||||
defaultFontFamily.unshift('Microsoft YaHei')
|
||||
defaultFontFamily.unshift('meiryo')
|
||||
}
|
||||
const defaultCodeBlockFontFamily = [
|
||||
'Monaco',
|
||||
'Menlo',
|
||||
'Ubuntu Mono',
|
||||
'Consolas',
|
||||
'source-code-pro',
|
||||
'monospace'
|
||||
]
|
||||
|
||||
// return the line number of the line that used to generate the specified element
|
||||
// return -1 if the line is not found
|
||||
function getSourceLineNumberByElement(element) {
|
||||
@@ -430,94 +186,15 @@ class MarkdownPreview extends React.Component {
|
||||
}
|
||||
|
||||
handleSaveAsMd() {
|
||||
this.exportAsDocument('md')
|
||||
}
|
||||
|
||||
htmlContentFormatter(noteContent, exportTasks, targetDir) {
|
||||
const {
|
||||
fontFamily,
|
||||
fontSize,
|
||||
codeBlockFontFamily,
|
||||
lineNumber,
|
||||
codeBlockTheme,
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS,
|
||||
RTL
|
||||
} = this.getStyleParams()
|
||||
|
||||
const inlineStyles = buildStyle({
|
||||
fontFamily,
|
||||
fontSize,
|
||||
codeBlockFontFamily,
|
||||
lineNumber,
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS,
|
||||
RTL
|
||||
})
|
||||
let body = this.refs.root.contentWindow.document.body.innerHTML
|
||||
body = attachmentManagement.fixLocalURLS(body, this.props.storagePath)
|
||||
const files = [this.getCodeThemeLink(codeBlockTheme), ...CSS_FILES]
|
||||
files.forEach(file => {
|
||||
if (global.process.platform === 'win32') {
|
||||
file = file.replace('file:///', '')
|
||||
} else {
|
||||
file = file.replace('file://', '')
|
||||
}
|
||||
exportTasks.push({
|
||||
src: file,
|
||||
dst: 'css'
|
||||
})
|
||||
})
|
||||
|
||||
let styles = ''
|
||||
files.forEach(file => {
|
||||
styles += `<link rel="stylesheet" href="../css/${path.basename(file)}">`
|
||||
})
|
||||
|
||||
return `<html>
|
||||
<head>
|
||||
<base href="file://${targetDir}/">
|
||||
<meta charset="UTF-8">
|
||||
<meta name = "viewport" content = "width = device-width, initial-scale = 1, maximum-scale = 1">
|
||||
<style id="style">${inlineStyles}</style>
|
||||
${styles}
|
||||
</head>
|
||||
<body>${body}</body>
|
||||
</html>`
|
||||
this.exportAsDocument('md', formatMarkdown(this.props))
|
||||
}
|
||||
|
||||
handleSaveAsHtml() {
|
||||
this.exportAsDocument('html', (noteContent, exportTasks, targetDir) =>
|
||||
Promise.resolve(
|
||||
this.htmlContentFormatter(noteContent, exportTasks, targetDir)
|
||||
)
|
||||
)
|
||||
this.exportAsDocument('html', formatHTML(this.props))
|
||||
}
|
||||
|
||||
handleSaveAsPdf() {
|
||||
this.exportAsDocument('pdf', (noteContent, exportTasks, targetDir) => {
|
||||
const printout = new remote.BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: { webSecurity: false, javascript: false }
|
||||
})
|
||||
printout.loadURL(
|
||||
'data:text/html;charset=UTF-8,' +
|
||||
this.htmlContentFormatter(noteContent, exportTasks, targetDir)
|
||||
)
|
||||
return new Promise((resolve, reject) => {
|
||||
printout.webContents.on('did-finish-load', () => {
|
||||
printout.webContents.printToPDF({}, (err, data) => {
|
||||
if (err) reject(err)
|
||||
else resolve(data)
|
||||
printout.destroy()
|
||||
})
|
||||
})
|
||||
})
|
||||
})
|
||||
this.exportAsDocument('pdf', formatPDF(this.props))
|
||||
}
|
||||
|
||||
handlePrint() {
|
||||
@@ -525,18 +202,21 @@ class MarkdownPreview extends React.Component {
|
||||
}
|
||||
|
||||
exportAsDocument(fileType, contentFormatter) {
|
||||
const note = this.props.getNote()
|
||||
|
||||
const options = {
|
||||
defaultPath: filenamify(note.title, {
|
||||
replacement: '_'
|
||||
}),
|
||||
filters: [{ name: 'Documents', extensions: [fileType] }],
|
||||
properties: ['openFile', 'createDirectory']
|
||||
}
|
||||
|
||||
dialog.showSaveDialog(remote.getCurrentWindow(), options, filename => {
|
||||
if (filename) {
|
||||
const content = this.props.value
|
||||
const storage = this.props.storagePath
|
||||
const nodeKey = this.props.noteKey
|
||||
const storagePath = this.props.storagePath
|
||||
|
||||
exportNote(nodeKey, storage, content, filename, contentFormatter)
|
||||
exportNote(storagePath, note, filename, contentFormatter)
|
||||
.then(res => {
|
||||
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'info',
|
||||
@@ -567,32 +247,6 @@ class MarkdownPreview extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Convert special characters between three ```
|
||||
* @param {string[]} splitWithCodeTag Array of HTML strings separated by three ```
|
||||
* @returns {string} HTML in which special characters between three ``` have been converted
|
||||
*/
|
||||
escapeHtmlCharactersInCodeTag(splitWithCodeTag) {
|
||||
for (let index = 0; index < splitWithCodeTag.length; index++) {
|
||||
const codeTagRequired =
|
||||
splitWithCodeTag[index] !== '```' && index < splitWithCodeTag.length - 1
|
||||
if (codeTagRequired) {
|
||||
splitWithCodeTag.splice(index + 1, 0, '```')
|
||||
}
|
||||
}
|
||||
let inCodeTag = false
|
||||
let result = ''
|
||||
for (let content of splitWithCodeTag) {
|
||||
if (content === '```') {
|
||||
inCodeTag = !inCodeTag
|
||||
} else if (inCodeTag) {
|
||||
content = escapeHtmlCharacters(content)
|
||||
}
|
||||
result += content
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
getScrollBarStyle() {
|
||||
const { theme } = this.props
|
||||
|
||||
@@ -743,47 +397,6 @@ class MarkdownPreview extends React.Component {
|
||||
}
|
||||
}
|
||||
|
||||
getStyleParams() {
|
||||
const {
|
||||
fontSize,
|
||||
lineNumber,
|
||||
codeBlockTheme,
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS,
|
||||
RTL
|
||||
} = this.props
|
||||
let { fontFamily, codeBlockFontFamily } = this.props
|
||||
fontFamily =
|
||||
_.isString(fontFamily) && fontFamily.trim().length > 0
|
||||
? fontFamily
|
||||
.split(',')
|
||||
.map(fontName => fontName.trim())
|
||||
.concat(defaultFontFamily)
|
||||
: defaultFontFamily
|
||||
codeBlockFontFamily =
|
||||
_.isString(codeBlockFontFamily) && codeBlockFontFamily.trim().length > 0
|
||||
? codeBlockFontFamily
|
||||
.split(',')
|
||||
.map(fontName => fontName.trim())
|
||||
.concat(defaultCodeBlockFontFamily)
|
||||
: defaultCodeBlockFontFamily
|
||||
|
||||
return {
|
||||
fontFamily,
|
||||
fontSize,
|
||||
codeBlockFontFamily,
|
||||
lineNumber,
|
||||
codeBlockTheme,
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS,
|
||||
RTL
|
||||
}
|
||||
}
|
||||
|
||||
applyStyle() {
|
||||
const {
|
||||
fontFamily,
|
||||
@@ -796,12 +409,13 @@ class MarkdownPreview extends React.Component {
|
||||
allowCustomCSS,
|
||||
customCSS,
|
||||
RTL
|
||||
} = this.getStyleParams()
|
||||
} = getStyleParams(this.props)
|
||||
|
||||
this.getWindow().document.getElementById(
|
||||
'codeTheme'
|
||||
).href = this.getCodeThemeLink(codeBlockTheme)
|
||||
this.getWindow().document.getElementById('style').innerHTML = buildStyle({
|
||||
).href = getCodeThemeLink(codeBlockTheme)
|
||||
|
||||
this.getWindow().document.getElementById('style').innerHTML = buildStyle(
|
||||
fontFamily,
|
||||
fontSize,
|
||||
codeBlockFontFamily,
|
||||
@@ -811,15 +425,7 @@ class MarkdownPreview extends React.Component {
|
||||
allowCustomCSS,
|
||||
customCSS,
|
||||
RTL
|
||||
})
|
||||
}
|
||||
|
||||
getCodeThemeLink(name) {
|
||||
const theme = consts.THEMES.find(theme => theme.name === name)
|
||||
|
||||
return theme != null
|
||||
? theme.path
|
||||
: `${appPath}/node_modules/codemirror/theme/elegant.css`
|
||||
)
|
||||
}
|
||||
|
||||
rewriteIframe() {
|
||||
@@ -853,7 +459,7 @@ class MarkdownPreview extends React.Component {
|
||||
this.refs.root.contentWindow.document.body.setAttribute('data-theme', theme)
|
||||
if (sanitize === 'NONE') {
|
||||
const splitWithCodeTag = value.split('```')
|
||||
value = this.escapeHtmlCharactersInCodeTag(splitWithCodeTag)
|
||||
value = escapeHtmlCharactersInCodeTag(splitWithCodeTag)
|
||||
}
|
||||
const renderedHTML = this.markdown.render(value)
|
||||
attachmentManagement.migrateAttachments(value, storagePath, noteKey)
|
||||
@@ -916,13 +522,9 @@ class MarkdownPreview extends React.Component {
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
const opts = {}
|
||||
// if (this.props.theme === 'dark') {
|
||||
// opts['font-color'] = '#DDD'
|
||||
// opts['line-color'] = '#DDD'
|
||||
// opts['element-color'] = '#DDD'
|
||||
// opts['fill'] = '#3A404C'
|
||||
// }
|
||||
|
||||
_.forEach(
|
||||
this.refs.root.contentWindow.document.querySelectorAll('.flowchart'),
|
||||
el => {
|
||||
|
||||
@@ -336,6 +336,7 @@ class MarkdownSplitEditor extends React.Component {
|
||||
storageKey,
|
||||
noteKey,
|
||||
linesHighlighted,
|
||||
getNote,
|
||||
isStacking,
|
||||
RTL
|
||||
} = this.props
|
||||
@@ -470,6 +471,7 @@ class MarkdownSplitEditor extends React.Component {
|
||||
codeBlockTheme={config.preview.codeBlockTheme}
|
||||
codeBlockFontFamily={config.editor.fontFamily}
|
||||
lineNumber={config.preview.lineNumber}
|
||||
indentSize={editorIndentSize}
|
||||
scrollPastEnd={config.preview.scrollPastEnd}
|
||||
smartQuotes={config.preview.smartQuotes}
|
||||
smartArrows={config.preview.smartArrows}
|
||||
@@ -486,6 +488,8 @@ class MarkdownSplitEditor extends React.Component {
|
||||
customCSS={config.preview.customCSS}
|
||||
allowCustomCSS={config.preview.allowCustomCSS}
|
||||
lineThroughCheckbox={config.preview.lineThroughCheckbox}
|
||||
getNote={getNote}
|
||||
export={config.export}
|
||||
RTL={RTL}
|
||||
/>
|
||||
</div>
|
||||
|
||||
@@ -8,7 +8,7 @@ import markdownItTocAndAnchor from '@hikerpig/markdown-it-toc-and-anchor'
|
||||
import _ from 'lodash'
|
||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||
import katex from 'katex'
|
||||
import { lastFindInArray } from './utils'
|
||||
import { escapeHtmlCharacters, lastFindInArray } from './utils'
|
||||
|
||||
function createGutter(str, firstLineNumber) {
|
||||
if (Number.isNaN(firstLineNumber)) firstLineNumber = 1
|
||||
@@ -31,7 +31,8 @@ class Markdown {
|
||||
html: true,
|
||||
xhtmlOut: true,
|
||||
breaks: config.preview.breaks,
|
||||
sanitize: 'STRICT'
|
||||
sanitize: 'STRICT',
|
||||
onFence: () => {}
|
||||
}
|
||||
|
||||
const updatedOptions = Object.assign(defaultOptions, options)
|
||||
@@ -266,6 +267,8 @@ class Markdown {
|
||||
token.parameters.format = 'yaml'
|
||||
}
|
||||
|
||||
updatedOptions.onFence('chart', token.parameters.format)
|
||||
|
||||
return `<pre class="fence" data-line="${token.map[0]}">
|
||||
<span class="filename">${token.fileName}</span>
|
||||
<div class="chart" data-height="${
|
||||
@@ -276,6 +279,8 @@ class Markdown {
|
||||
</pre>`
|
||||
},
|
||||
flowchart: token => {
|
||||
updatedOptions.onFence('flowchart')
|
||||
|
||||
return `<pre class="fence" data-line="${token.map[0]}">
|
||||
<span class="filename">${token.fileName}</span>
|
||||
<div class="flowchart" data-height="${token.parameters.height}">${
|
||||
@@ -305,6 +310,8 @@ class Markdown {
|
||||
</pre>`
|
||||
},
|
||||
mermaid: token => {
|
||||
updatedOptions.onFence('mermaid')
|
||||
|
||||
return `<pre class="fence" data-line="${token.map[0]}">
|
||||
<span class="filename">${token.fileName}</span>
|
||||
<div class="mermaid" data-height="${token.parameters.height}">${
|
||||
@@ -313,6 +320,8 @@ class Markdown {
|
||||
</pre>`
|
||||
},
|
||||
sequence: token => {
|
||||
updatedOptions.onFence('sequence')
|
||||
|
||||
return `<pre class="fence" data-line="${token.map[0]}">
|
||||
<span class="filename">${token.fileName}</span>
|
||||
<div class="sequence" data-height="${token.parameters.height}">${
|
||||
@@ -322,6 +331,8 @@ class Markdown {
|
||||
}
|
||||
},
|
||||
token => {
|
||||
updatedOptions.onFence('code', token.langType)
|
||||
|
||||
return `<pre class="code CodeMirror" data-line="${token.map[0]}">
|
||||
<span class="filename">${token.fileName}</span>
|
||||
${createGutter(token.content, token.firstLineNumber)}
|
||||
@@ -468,6 +479,16 @@ class Markdown {
|
||||
return true
|
||||
})
|
||||
|
||||
this.md.renderer.rules.code_inline = function(tokens, idx) {
|
||||
const token = tokens[idx]
|
||||
|
||||
return (
|
||||
'<code class="inline">' +
|
||||
escapeHtmlCharacters(token.content) +
|
||||
'</code>'
|
||||
)
|
||||
}
|
||||
|
||||
if (config.preview.smartArrows) {
|
||||
this.md.use(smartArrows)
|
||||
}
|
||||
|
||||
@@ -57,10 +57,11 @@ class MarkdownNoteDetail extends React.Component {
|
||||
|
||||
this.dispatchTimer = null
|
||||
|
||||
this.toggleLockButton = this.handleToggleLockButton.bind(this)
|
||||
this.generateToc = this.handleGenerateToc.bind(this)
|
||||
this.toggleLockButton = this.handleToggleLockButton.bind(this)
|
||||
this.handleUpdateContent = this.handleUpdateContent.bind(this)
|
||||
this.handleSwitchStackDirection = this.handleSwitchStackDirection.bind(this)
|
||||
this.getNote = this.getNote.bind(this)
|
||||
}
|
||||
|
||||
focus() {
|
||||
@@ -441,6 +442,10 @@ class MarkdownNoteDetail extends React.Component {
|
||||
this.updateNote(note)
|
||||
}
|
||||
|
||||
getNote() {
|
||||
return this.state.note
|
||||
}
|
||||
|
||||
renderEditor() {
|
||||
const { config, ignorePreviewPointerEvents } = this.props
|
||||
const { note, isStacking } = this.state
|
||||
@@ -456,8 +461,8 @@ class MarkdownNoteDetail extends React.Component {
|
||||
noteKey={note.key}
|
||||
linesHighlighted={note.linesHighlighted}
|
||||
onChange={this.handleUpdateContent}
|
||||
isLocked={this.state.isLocked}
|
||||
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
||||
getNote={this.getNote}
|
||||
RTL={config.editor.rtlEnabled && this.state.RTL}
|
||||
/>
|
||||
)
|
||||
@@ -473,6 +478,7 @@ class MarkdownNoteDetail extends React.Component {
|
||||
linesHighlighted={note.linesHighlighted}
|
||||
onChange={this.handleUpdateContent}
|
||||
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
||||
getNote={this.getNote}
|
||||
RTL={config.editor.rtlEnabled && this.state.RTL}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -18,6 +18,7 @@ import { getLocales } from 'browser/lib/Languages'
|
||||
import applyShortcuts from 'browser/main/lib/shortcutManager'
|
||||
import { chooseTheme, applyTheme } from 'browser/main/lib/ThemeManager'
|
||||
import { push } from 'connected-react-router'
|
||||
import { ipcRenderer } from 'electron'
|
||||
|
||||
const path = require('path')
|
||||
const electron = require('electron')
|
||||
@@ -184,6 +185,7 @@ class Main extends React.Component {
|
||||
this.toggleMenuBarVisible.bind(this)
|
||||
)
|
||||
eventEmitter.on('dispatch:push', this.changeRoutePush.bind(this))
|
||||
eventEmitter.on('update', () => ipcRenderer.send('update-check', 'manual'))
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
|
||||
@@ -21,6 +21,7 @@ import Markdown from '../../lib/markdown'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
import { confirmDeleteNote } from 'browser/lib/confirmDeleteNote'
|
||||
import context from 'browser/lib/context'
|
||||
import filenamify from 'filenamify'
|
||||
import queryString from 'query-string'
|
||||
|
||||
const { remote } = require('electron')
|
||||
@@ -634,6 +635,38 @@ class NoteList extends React.Component {
|
||||
this.selectNextNote()
|
||||
}
|
||||
|
||||
handleExportClick(e, note, fileType) {
|
||||
const options = {
|
||||
defaultPath: filenamify(note.title, {
|
||||
replacement: '_'
|
||||
}),
|
||||
filters: [{ name: 'Documents', extensions: [fileType] }],
|
||||
properties: ['openFile', 'createDirectory']
|
||||
}
|
||||
|
||||
dialog.showSaveDialog(remote.getCurrentWindow(), options, filename => {
|
||||
if (filename) {
|
||||
const { config } = this.props
|
||||
|
||||
dataApi
|
||||
.exportNoteAs(note, filename, fileType, config)
|
||||
.then(res => {
|
||||
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'info',
|
||||
message: `Exported to ${filename}`
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
dialog.showErrorBox(
|
||||
'Export error',
|
||||
err ? err.message || err : 'Unexpected error during export'
|
||||
)
|
||||
throw err
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
handleNoteContextMenu(e, uniqueKey) {
|
||||
const { location } = this.props
|
||||
const { selectedNoteKeys } = this.state
|
||||
@@ -689,9 +722,40 @@ class NoteList extends React.Component {
|
||||
click: this.copyNoteLink.bind(this, note)
|
||||
}
|
||||
)
|
||||
|
||||
if (note.type === 'MARKDOWN_NOTE') {
|
||||
templates.push(
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export Note'),
|
||||
submenu: [
|
||||
{
|
||||
label: i18n.__('Export as Plain Text (.txt)'),
|
||||
click: e => this.handleExportClick(e, note, 'txt')
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export as Markdown (.md)'),
|
||||
click: e => this.handleExportClick(e, note, 'md')
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export as HTML (.html)'),
|
||||
click: e => this.handleExportClick(e, note, 'html')
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export as PDF (.pdf)'),
|
||||
click: e => this.handleExportClick(e, note, 'pdf')
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
if (note.blog && note.blog.blogLink && note.blog.blogId) {
|
||||
templates.push(
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: updateLabel,
|
||||
click: this.publishMarkdown.bind(this)
|
||||
@@ -702,10 +766,15 @@ class NoteList extends React.Component {
|
||||
}
|
||||
)
|
||||
} else {
|
||||
templates.push({
|
||||
templates.push(
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: publishLabel,
|
||||
click: this.publishMarkdown.bind(this)
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,12 +43,20 @@ class StorageItem extends React.Component {
|
||||
label: i18n.__('Export Storage'),
|
||||
submenu: [
|
||||
{
|
||||
label: i18n.__('Export as txt'),
|
||||
label: i18n.__('Export as Plain Text (.txt)'),
|
||||
click: e => this.handleExportStorageClick(e, 'txt')
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export as md'),
|
||||
label: i18n.__('Export as Markdown (.md)'),
|
||||
click: e => this.handleExportStorageClick(e, 'md')
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export as HTML (.html)'),
|
||||
click: e => this.handleExportStorageClick(e, 'html')
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export as PDF (.pdf)'),
|
||||
click: e => this.handleExportStorageClick(e, 'pdf')
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -97,14 +105,28 @@ class StorageItem extends React.Component {
|
||||
}
|
||||
dialog.showOpenDialog(remote.getCurrentWindow(), options, paths => {
|
||||
if (paths && paths.length === 1) {
|
||||
const { storage, dispatch } = this.props
|
||||
dataApi.exportStorage(storage.key, fileType, paths[0]).then(data => {
|
||||
const { storage, dispatch, config } = this.props
|
||||
dataApi
|
||||
.exportStorage(storage.key, fileType, paths[0], config)
|
||||
.then(data => {
|
||||
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'info',
|
||||
message: `Exported to ${paths[0]}`
|
||||
})
|
||||
|
||||
dispatch({
|
||||
type: 'EXPORT_STORAGE',
|
||||
storage: data.storage,
|
||||
fileType: data.fileType
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
dialog.showErrorBox(
|
||||
'Export error',
|
||||
error ? error.message || error : 'Unexpected error during export'
|
||||
)
|
||||
throw error
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -166,12 +188,20 @@ class StorageItem extends React.Component {
|
||||
label: i18n.__('Export Folder'),
|
||||
submenu: [
|
||||
{
|
||||
label: i18n.__('Export as txt'),
|
||||
label: i18n.__('Export as Plain Text (.txt)'),
|
||||
click: e => this.handleExportFolderClick(e, folder, 'txt')
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export as md'),
|
||||
label: i18n.__('Export as Markdown (.md)'),
|
||||
click: e => this.handleExportFolderClick(e, folder, 'md')
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export as HTML (.html)'),
|
||||
click: e => this.handleExportFolderClick(e, folder, 'html')
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export as PDF (.pdf)'),
|
||||
click: e => this.handleExportFolderClick(e, folder, 'pdf')
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -202,30 +232,28 @@ class StorageItem extends React.Component {
|
||||
}
|
||||
dialog.showOpenDialog(remote.getCurrentWindow(), options, paths => {
|
||||
if (paths && paths.length === 1) {
|
||||
const { storage, dispatch } = this.props
|
||||
const { storage, dispatch, config } = this.props
|
||||
dataApi
|
||||
.exportFolder(storage.key, folder.key, fileType, paths[0])
|
||||
.exportFolder(storage.key, folder.key, fileType, paths[0], config)
|
||||
.then(data => {
|
||||
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'info',
|
||||
message: `Exported to ${paths[0]}`
|
||||
})
|
||||
|
||||
dispatch({
|
||||
type: 'EXPORT_FOLDER',
|
||||
storage: data.storage,
|
||||
folderKey: data.folderKey,
|
||||
fileType: data.fileType
|
||||
})
|
||||
return data
|
||||
})
|
||||
.then(data => {
|
||||
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'info',
|
||||
message: 'Exported to "' + data.exportDir + '"'
|
||||
})
|
||||
})
|
||||
.catch(err => {
|
||||
.catch(error => {
|
||||
dialog.showErrorBox(
|
||||
'Export error',
|
||||
err ? err.message || err : 'Unexpected error during export'
|
||||
error ? error.message || error : 'Unexpected error during export'
|
||||
)
|
||||
throw err
|
||||
throw error
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
@@ -26,6 +26,8 @@ import { confirmDeleteNote } from 'browser/lib/confirmDeleteNote'
|
||||
import ColorPicker from 'browser/components/ColorPicker'
|
||||
import { every, sortBy } from 'lodash'
|
||||
|
||||
const { dialog } = remote
|
||||
|
||||
function matchActiveTags(tags, activeTags) {
|
||||
return every(activeTags, v => tags.indexOf(v) >= 0)
|
||||
}
|
||||
@@ -63,15 +65,12 @@ class SideNav extends React.Component {
|
||||
}
|
||||
|
||||
deleteTag(tag) {
|
||||
const selectedButton = remote.dialog.showMessageBox(
|
||||
remote.getCurrentWindow(),
|
||||
{
|
||||
const selectedButton = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: i18n.__('Confirm tag deletion'),
|
||||
detail: i18n.__('This will permanently remove this tag.'),
|
||||
buttons: [i18n.__('Confirm'), i18n.__('Cancel')]
|
||||
}
|
||||
)
|
||||
})
|
||||
|
||||
if (selectedButton === 0) {
|
||||
const {
|
||||
@@ -155,28 +154,80 @@ class SideNav extends React.Component {
|
||||
}
|
||||
|
||||
handleTagContextMenu(e, tag) {
|
||||
const menu = []
|
||||
|
||||
menu.push({
|
||||
label: i18n.__('Delete Tag'),
|
||||
click: this.deleteTag.bind(this, tag)
|
||||
})
|
||||
|
||||
menu.push({
|
||||
context.popup([
|
||||
{
|
||||
label: i18n.__('Rename Tag'),
|
||||
click: this.handleRenameTagClick.bind(this, tag)
|
||||
},
|
||||
{
|
||||
label: i18n.__('Customize Color'),
|
||||
click: this.displayColorPicker.bind(
|
||||
this,
|
||||
tag,
|
||||
e.target.getBoundingClientRect()
|
||||
)
|
||||
})
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export Tag'),
|
||||
submenu: [
|
||||
{
|
||||
label: i18n.__('Export as Plain Text (.txt)'),
|
||||
click: e => this.handleExportTagClick(e, tag, 'txt')
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export as Markdown (.md)'),
|
||||
click: e => this.handleExportTagClick(e, tag, 'md')
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export as HTML (.html)'),
|
||||
click: e => this.handleExportTagClick(e, tag, 'html')
|
||||
},
|
||||
{
|
||||
label: i18n.__('Export as PDF (.pdf)'),
|
||||
click: e => this.handleExportTagClick(e, tag, 'pdf')
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: i18n.__('Delete Tag'),
|
||||
click: this.deleteTag.bind(this, tag)
|
||||
}
|
||||
])
|
||||
}
|
||||
|
||||
menu.push({
|
||||
label: i18n.__('Rename Tag'),
|
||||
click: this.handleRenameTagClick.bind(this, tag)
|
||||
handleExportTagClick(e, tag, fileType) {
|
||||
const options = {
|
||||
properties: ['openDirectory', 'createDirectory'],
|
||||
buttonLabel: i18n.__('Select directory'),
|
||||
title: i18n.__('Select a folder to export the files to'),
|
||||
multiSelections: false
|
||||
}
|
||||
dialog.showOpenDialog(remote.getCurrentWindow(), options, paths => {
|
||||
if (paths && paths.length === 1) {
|
||||
const { data, config } = this.props
|
||||
dataApi
|
||||
.exportTag(data, tag, fileType, paths[0], config)
|
||||
.then(data => {
|
||||
dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'info',
|
||||
message: `Exported to ${paths[0]}`
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
dialog.showErrorBox(
|
||||
'Export error',
|
||||
error ? error.message || error : 'Unexpected error during export'
|
||||
)
|
||||
throw error
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
context.popup(menu)
|
||||
}
|
||||
|
||||
dismissColorPicker() {
|
||||
@@ -330,6 +381,7 @@ class SideNav extends React.Component {
|
||||
dispatch={dispatch}
|
||||
onSortEnd={this.onSortEnd.bind(this)(storage)}
|
||||
useDragHandle
|
||||
config={config}
|
||||
/>
|
||||
)
|
||||
})
|
||||
|
||||
@@ -12,6 +12,7 @@ import DevTools from './DevTools'
|
||||
require('./lib/ipcClient')
|
||||
require('../lib/customMeta')
|
||||
import i18n from 'browser/lib/i18n'
|
||||
import ConfigManager from './lib/ConfigManager'
|
||||
|
||||
const electron = require('electron')
|
||||
|
||||
@@ -107,6 +108,22 @@ function updateApp() {
|
||||
}
|
||||
}
|
||||
|
||||
function downloadUpdate() {
|
||||
const index = dialog.showMessageBox(remote.getCurrentWindow(), {
|
||||
type: 'warning',
|
||||
message: i18n.__('Update Boostnote'),
|
||||
detail: i18n.__('New Boostnote is ready to be downloaded.'),
|
||||
buttons: [i18n.__('Download now'), i18n.__('Ignore updates')]
|
||||
})
|
||||
|
||||
if (index === 0) {
|
||||
ipcRenderer.send('update-download-confirm')
|
||||
} else if (index === 1) {
|
||||
ipcRenderer.send('update-cancel')
|
||||
ConfigManager.set({ autoUpdateEnabled: false })
|
||||
}
|
||||
}
|
||||
|
||||
ReactDOM.render(
|
||||
<Provider store={store}>
|
||||
<ConnectedRouter history={history}>
|
||||
@@ -147,8 +164,12 @@ ReactDOM.render(
|
||||
})
|
||||
|
||||
ipcRenderer.on('update-found', function() {
|
||||
notify('Update found!', {
|
||||
body: 'Preparing to update...'
|
||||
downloadUpdate()
|
||||
})
|
||||
|
||||
ipcRenderer.on('update-not-found', function(_, msg) {
|
||||
notify('Update not found!', {
|
||||
body: msg
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -18,9 +18,9 @@ const DEFAULT_MARKDOWN_LINT_CONFIG = `{
|
||||
|
||||
const DEFAULT_CSS_CONFIG = `
|
||||
/* Drop Your Custom CSS Code Here */
|
||||
[data-theme="default"] p code,
|
||||
[data-theme="default"] li code,
|
||||
[data-theme="default"] td code
|
||||
[data-theme="default"] p code.inline,
|
||||
[data-theme="default"] li code.inline,
|
||||
[data-theme="default"] td code.inline
|
||||
{
|
||||
padding: 2px;
|
||||
border-width: 1px;
|
||||
@@ -144,6 +144,11 @@ export const DEFAULT_CONFIG = {
|
||||
username: '',
|
||||
password: ''
|
||||
},
|
||||
export: {
|
||||
metadata: 'DONT_EXPORT', // 'DONT_EXPORT', 'MERGE_HEADER', 'MERGE_VARIABLE'
|
||||
variable: 'boostnote',
|
||||
prefixAttachmentFolder: false
|
||||
},
|
||||
coloredTags: {},
|
||||
wakatime: {
|
||||
key: null
|
||||
|
||||
@@ -706,14 +706,15 @@ function replaceNoteKeyWithNewNoteKey(noteContent, oldNoteKey, newNoteKey) {
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Deletes all :storage and noteKey references from the given input.
|
||||
* @param input Input in which the references should be deleted
|
||||
* @description replace all :storage references with given destination folder.
|
||||
* @param input Input in which the references should be replaced
|
||||
* @param noteKey Key of the current note
|
||||
* @param destinationFolder Destination folder of the attachements
|
||||
* @returns {String} Input without the references
|
||||
*/
|
||||
function removeStorageAndNoteReferences(input, noteKey) {
|
||||
function replaceStorageReferences(input, noteKey, destinationFolder) {
|
||||
return input.replace(
|
||||
new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '.*?("|\\))', 'g'),
|
||||
new RegExp('/?' + STORAGE_FOLDER_PLACEHOLDER + '[^"\\)<\\s]+', 'g'),
|
||||
function(match) {
|
||||
return match
|
||||
.replace(new RegExp(mdurl.encode(path.win32.sep), 'g'), path.posix.sep)
|
||||
@@ -735,7 +736,7 @@ function removeStorageAndNoteReferences(input, noteKey) {
|
||||
')?',
|
||||
'g'
|
||||
),
|
||||
DESTINATION_FOLDER
|
||||
destinationFolder
|
||||
)
|
||||
}
|
||||
)
|
||||
@@ -1101,8 +1102,8 @@ module.exports = {
|
||||
getAttachmentsInMarkdownContent,
|
||||
getAbsolutePathsOfAttachmentsInContent,
|
||||
importAttachments,
|
||||
removeStorageAndNoteReferences,
|
||||
removeAttachmentsByPaths,
|
||||
replaceStorageReferences,
|
||||
deleteAttachmentFolder,
|
||||
deleteAttachmentsNotPresentInNote,
|
||||
getAttachmentsPathAndStatus,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
import fs from 'fs'
|
||||
import fx from 'fs-extra'
|
||||
import path from 'path'
|
||||
|
||||
/**
|
||||
* @description Copy a file from source to destination
|
||||
@@ -14,7 +15,8 @@ function copyFile(srcPath, dstPath) {
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const dstFolder = path.dirname(dstPath)
|
||||
if (!fs.existsSync(dstFolder)) fs.mkdirSync(dstFolder)
|
||||
|
||||
fx.ensureDirSync(dstFolder)
|
||||
|
||||
const input = fs.createReadStream(decodeURI(srcPath))
|
||||
const output = fs.createWriteStream(dstPath)
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { findStorage } from 'browser/lib/findStorage'
|
||||
import resolveStorageData from './resolveStorageData'
|
||||
import resolveStorageNotes from './resolveStorageNotes'
|
||||
import getFilename from './getFilename'
|
||||
import exportNote from './exportNote'
|
||||
import filenamify from 'filenamify'
|
||||
import * as path from 'path'
|
||||
import getContentFormatter from './getContentFormatter'
|
||||
|
||||
/**
|
||||
* @param {String} storageKey
|
||||
* @param {String} folderKey
|
||||
* @param {String} fileType
|
||||
* @param {String} exportDir
|
||||
* @param {Object} config
|
||||
*
|
||||
* @return {Object}
|
||||
* ```
|
||||
@@ -22,7 +23,7 @@ import * as path from 'path'
|
||||
* ```
|
||||
*/
|
||||
|
||||
function exportFolder(storageKey, folderKey, fileType, exportDir) {
|
||||
function exportFolder(storageKey, folderKey, fileType, exportDir, config) {
|
||||
let targetStorage
|
||||
try {
|
||||
targetStorage = findStorage(storageKey)
|
||||
@@ -30,38 +31,33 @@ function exportFolder(storageKey, folderKey, fileType, exportDir) {
|
||||
return Promise.reject(e)
|
||||
}
|
||||
|
||||
return resolveStorageData(targetStorage)
|
||||
.then(function assignNotes(storage) {
|
||||
return resolveStorageNotes(storage).then(notes => {
|
||||
return {
|
||||
storage,
|
||||
notes
|
||||
}
|
||||
})
|
||||
})
|
||||
.then(function exportNotes(data) {
|
||||
const { storage, notes } = data
|
||||
const deduplicator = {}
|
||||
|
||||
return Promise.all(
|
||||
notes
|
||||
.filter(
|
||||
return resolveStorageData(targetStorage)
|
||||
.then(storage => {
|
||||
return resolveStorageNotes(storage).then(notes => ({
|
||||
storage,
|
||||
notes: notes.filter(
|
||||
note =>
|
||||
note.folder === folderKey &&
|
||||
note.isTrashed === false &&
|
||||
!note.isTrashed &&
|
||||
note.type === 'MARKDOWN_NOTE'
|
||||
)
|
||||
.map(note => {
|
||||
const notePath = path.join(
|
||||
}))
|
||||
})
|
||||
.then(({ storage, notes }) => {
|
||||
const contentFormatter = getContentFormatter(storage, fileType, config)
|
||||
|
||||
return Promise.all(
|
||||
notes.map(note => {
|
||||
const targetPath = getFilename(
|
||||
note,
|
||||
fileType,
|
||||
exportDir,
|
||||
`${filenamify(note.title, { replacement: '_' })}.${fileType}`
|
||||
)
|
||||
return exportNote(
|
||||
note.key,
|
||||
storage.path,
|
||||
note.content,
|
||||
notePath,
|
||||
null
|
||||
deduplicator
|
||||
)
|
||||
|
||||
return exportNote(storage.key, note, targetPath, contentFormatter)
|
||||
})
|
||||
).then(() => ({
|
||||
storage,
|
||||
|
||||
@@ -4,58 +4,35 @@ import { findStorage } from 'browser/lib/findStorage'
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const attachmentManagement = require('./attachmentManagement')
|
||||
|
||||
/**
|
||||
* Export note together with attachments
|
||||
*
|
||||
* If attachments are stored in the storage, creates 'attachments' subfolder in target directory
|
||||
* and copies attachments to it. Changes links to images in the content of the note
|
||||
*
|
||||
* @param {String} nodeKey key of the node that should be exported
|
||||
* @param {String} storageKey or storage path
|
||||
* @param {String} noteContent Content to export
|
||||
* @param {Object} note Note to export
|
||||
* @param {String} targetPath Path to exported file
|
||||
* @param {function} outputFormatter
|
||||
* @return {Promise.<*[]>}
|
||||
*/
|
||||
function exportNote(
|
||||
nodeKey,
|
||||
storageKey,
|
||||
noteContent,
|
||||
targetPath,
|
||||
outputFormatter
|
||||
) {
|
||||
function exportNote(storageKey, note, targetPath, outputFormatter) {
|
||||
const storagePath = path.isAbsolute(storageKey)
|
||||
? storageKey
|
||||
: findStorage(storageKey).path
|
||||
|
||||
const exportTasks = []
|
||||
|
||||
if (!storagePath) {
|
||||
throw new Error('Storage path is not found')
|
||||
}
|
||||
const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent(
|
||||
noteContent,
|
||||
storagePath
|
||||
)
|
||||
attachmentsAbsolutePaths.forEach(attachment => {
|
||||
exportTasks.push({
|
||||
src: attachment,
|
||||
dst: attachmentManagement.DESTINATION_FOLDER
|
||||
})
|
||||
})
|
||||
|
||||
let exportedData = attachmentManagement.removeStorageAndNoteReferences(
|
||||
noteContent,
|
||||
nodeKey
|
||||
const exportedData = Promise.resolve(
|
||||
outputFormatter
|
||||
? outputFormatter(note, targetPath, exportTasks)
|
||||
: note.content
|
||||
)
|
||||
|
||||
if (outputFormatter) {
|
||||
exportedData = outputFormatter(exportedData, exportTasks, targetPath)
|
||||
} else {
|
||||
exportedData = Promise.resolve(exportedData)
|
||||
}
|
||||
|
||||
const tasks = prepareTasks(exportTasks, storagePath, path.dirname(targetPath))
|
||||
|
||||
return Promise.all(tasks.map(task => copyFile(task.src, task.dst)))
|
||||
@@ -63,9 +40,9 @@ function exportNote(
|
||||
.then(data => {
|
||||
return saveToFile(data, targetPath)
|
||||
})
|
||||
.catch(err => {
|
||||
.catch(error => {
|
||||
rollbackExport(tasks)
|
||||
throw err
|
||||
throw error
|
||||
})
|
||||
}
|
||||
|
||||
@@ -107,14 +84,14 @@ function rollbackExport(tasks) {
|
||||
}
|
||||
|
||||
if (fs.existsSync(fullpath)) {
|
||||
fs.unlink(fullpath)
|
||||
fs.unlinkSync(fullpath)
|
||||
folders.add(path.dirname(fullpath))
|
||||
}
|
||||
})
|
||||
|
||||
folders.forEach(folder => {
|
||||
if (fs.readdirSync(folder).length === 0) {
|
||||
fs.rmdir(folder)
|
||||
fs.rmdirSync(folder)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
19
browser/main/lib/dataApi/exportNoteAs.js
Normal file
19
browser/main/lib/dataApi/exportNoteAs.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { findStorage } from 'browser/lib/findStorage'
|
||||
import exportNote from './exportNote'
|
||||
import getContentFormatter from './getContentFormatter'
|
||||
|
||||
/**
|
||||
* @param {Object} note
|
||||
* @param {String} filename
|
||||
* @param {String} fileType
|
||||
* @param {Object} config
|
||||
*/
|
||||
|
||||
function exportNoteAs(note, filename, fileType, config) {
|
||||
const storage = findStorage(note.storage)
|
||||
const contentFormatter = getContentFormatter(storage, fileType, config)
|
||||
|
||||
return exportNote(storage.key, note, filename, contentFormatter)
|
||||
}
|
||||
|
||||
module.exports = exportNoteAs
|
||||
@@ -2,13 +2,17 @@ import { findStorage } from 'browser/lib/findStorage'
|
||||
import resolveStorageData from './resolveStorageData'
|
||||
import resolveStorageNotes from './resolveStorageNotes'
|
||||
import filenamify from 'filenamify'
|
||||
import * as path from 'path'
|
||||
import * as fs from 'fs'
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import exportNote from './exportNote'
|
||||
import getContentFormatter from './getContentFormatter'
|
||||
import getFilename from './getFilename'
|
||||
|
||||
/**
|
||||
* @param {String} storageKey
|
||||
* @param {String} fileType
|
||||
* @param {String} exportDir
|
||||
* @param {Object} config
|
||||
*
|
||||
* @return {Object}
|
||||
* ```
|
||||
@@ -20,7 +24,7 @@ import * as fs from 'fs'
|
||||
* ```
|
||||
*/
|
||||
|
||||
function exportStorage(storageKey, fileType, exportDir) {
|
||||
function exportStorage(storageKey, fileType, exportDir, config) {
|
||||
let targetStorage
|
||||
try {
|
||||
targetStorage = findStorage(storageKey)
|
||||
@@ -29,39 +33,52 @@ function exportStorage(storageKey, fileType, exportDir) {
|
||||
}
|
||||
|
||||
return resolveStorageData(targetStorage)
|
||||
.then(storage =>
|
||||
resolveStorageNotes(storage).then(notes => ({ storage, notes }))
|
||||
.then(storage => {
|
||||
return resolveStorageNotes(storage).then(notes => ({
|
||||
storage,
|
||||
notes: notes.filter(
|
||||
note => !note.isTrashed && note.type === 'MARKDOWN_NOTE'
|
||||
)
|
||||
.then(function exportNotes(data) {
|
||||
const { storage, notes } = data
|
||||
}))
|
||||
})
|
||||
.then(({ storage, notes }) => {
|
||||
const contentFormatter = getContentFormatter(storage, fileType, config)
|
||||
|
||||
const folderNamesMapping = {}
|
||||
const deduplicators = {}
|
||||
|
||||
storage.folders.forEach(folder => {
|
||||
const folderExportedDir = path.join(
|
||||
exportDir,
|
||||
filenamify(folder.name, { replacement: '_' })
|
||||
)
|
||||
|
||||
folderNamesMapping[folder.key] = folderExportedDir
|
||||
|
||||
// make sure directory exists
|
||||
try {
|
||||
fs.mkdirSync(folderExportedDir)
|
||||
} catch (e) {}
|
||||
})
|
||||
notes
|
||||
.filter(note => !note.isTrashed && note.type === 'MARKDOWN_NOTE')
|
||||
.forEach(markdownNote => {
|
||||
const folderExportedDir = folderNamesMapping[markdownNote.folder]
|
||||
const snippetName = `${filenamify(markdownNote.title, {
|
||||
replacement: '_'
|
||||
})}.${fileType}`
|
||||
const notePath = path.join(folderExportedDir, snippetName)
|
||||
fs.writeFileSync(notePath, markdownNote.content)
|
||||
|
||||
deduplicators[folder.key] = {}
|
||||
})
|
||||
|
||||
return {
|
||||
return Promise.all(
|
||||
notes.map(note => {
|
||||
const targetPath = getFilename(
|
||||
note,
|
||||
fileType,
|
||||
folderNamesMapping[note.folder],
|
||||
deduplicators[note.folder]
|
||||
)
|
||||
|
||||
return exportNote(storage.key, note, targetPath, contentFormatter)
|
||||
})
|
||||
).then(() => ({
|
||||
storage,
|
||||
fileType,
|
||||
exportDir
|
||||
}
|
||||
}))
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
28
browser/main/lib/dataApi/exportTag.js
Normal file
28
browser/main/lib/dataApi/exportTag.js
Normal file
@@ -0,0 +1,28 @@
|
||||
import exportNoteAs from './exportNoteAs'
|
||||
import getFilename from './getFilename'
|
||||
|
||||
/**
|
||||
* @param {Object} data
|
||||
* @param {String} tag
|
||||
* @param {String} fileType
|
||||
* @param {String} exportDir
|
||||
* @param {Object} config
|
||||
*/
|
||||
|
||||
function exportTag(data, tag, fileType, exportDir, config) {
|
||||
const notes = data.noteMap
|
||||
.map(note => note)
|
||||
.filter(note => note.tags.indexOf(tag) !== -1)
|
||||
|
||||
const deduplicator = {}
|
||||
|
||||
return Promise.all(
|
||||
notes.map(note => {
|
||||
const filename = getFilename(note, fileType, exportDir, deduplicator)
|
||||
|
||||
return exportNoteAs(note, filename, fileType, config)
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
module.exports = exportTag
|
||||
796
browser/main/lib/dataApi/formatHTML.js
Normal file
796
browser/main/lib/dataApi/formatHTML.js
Normal file
@@ -0,0 +1,796 @@
|
||||
import path from 'path'
|
||||
import fileUrl from 'file-url'
|
||||
import fs from 'fs'
|
||||
import { remote } from 'electron'
|
||||
import consts from 'browser/lib/consts'
|
||||
import Markdown from 'browser/lib/markdown'
|
||||
import attachmentManagement from './attachmentManagement'
|
||||
import { version as codemirrorVersion } from 'codemirror/package.json'
|
||||
import { escapeHtmlCharacters } from 'browser/lib/utils'
|
||||
|
||||
const { app } = remote
|
||||
const appPath = fileUrl(
|
||||
process.env.NODE_ENV === 'production' ? app.getAppPath() : path.resolve()
|
||||
)
|
||||
|
||||
let markdownStyle = ''
|
||||
try {
|
||||
markdownStyle = require('!!css!stylus?sourceMap!../../../components/markdown.styl')[0][1]
|
||||
} catch (e) {}
|
||||
|
||||
export const CSS_FILES = [
|
||||
`${appPath}/node_modules/katex/dist/katex.min.css`,
|
||||
`${appPath}/node_modules/codemirror/lib/codemirror.css`,
|
||||
`${appPath}/node_modules/react-image-carousel/lib/css/main.min.css`
|
||||
]
|
||||
|
||||
const macos = global.process.platform === 'darwin'
|
||||
|
||||
const defaultFontFamily = ['helvetica', 'arial', 'sans-serif']
|
||||
if (!macos) {
|
||||
defaultFontFamily.unshift('Microsoft YaHei')
|
||||
defaultFontFamily.unshift('meiryo')
|
||||
}
|
||||
|
||||
const defaultCodeBlockFontFamily = [
|
||||
'Monaco',
|
||||
'Menlo',
|
||||
'Ubuntu Mono',
|
||||
'Consolas',
|
||||
'source-code-pro',
|
||||
'monospace'
|
||||
]
|
||||
|
||||
function unprefix(file) {
|
||||
if (global.process.platform === 'win32') {
|
||||
return file.replace('file:///', '')
|
||||
} else {
|
||||
return file.replace('file://', '')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* ```
|
||||
* {
|
||||
* fontFamily,
|
||||
* fontSize,
|
||||
* lineNumber,
|
||||
* codeBlockFontFamily,
|
||||
* codeBlockTheme,
|
||||
* scrollPastEnd,
|
||||
* theme,
|
||||
* allowCustomCSS,
|
||||
* customCSS
|
||||
* smartQuotes,
|
||||
* sanitize,
|
||||
* breaks,
|
||||
* storagePath,
|
||||
* export,
|
||||
* indentSize
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export default function formatHTML(props) {
|
||||
const {
|
||||
fontFamily,
|
||||
fontSize,
|
||||
codeBlockFontFamily,
|
||||
lineNumber,
|
||||
codeBlockTheme,
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS
|
||||
} = getStyleParams(props)
|
||||
|
||||
const inlineStyles = buildStyle(
|
||||
fontFamily,
|
||||
fontSize,
|
||||
codeBlockFontFamily,
|
||||
lineNumber,
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS
|
||||
)
|
||||
|
||||
const { smartQuotes, sanitize, breaks } = props
|
||||
|
||||
let indentSize = parseInt(props.indentSize, 10)
|
||||
if (!(indentSize > 0 && indentSize < 132)) {
|
||||
indentSize = 4
|
||||
}
|
||||
|
||||
const files = [getCodeThemeLink(codeBlockTheme), ...CSS_FILES]
|
||||
|
||||
return function(note, targetPath, exportTasks) {
|
||||
const styles = files
|
||||
.map(file => `<link rel="stylesheet" href="css/${path.basename(file)}">`)
|
||||
.join('\n')
|
||||
|
||||
let inlineScripts = ''
|
||||
let scripts = ''
|
||||
|
||||
let decodeEntities = false
|
||||
function addDecodeEntities() {
|
||||
if (decodeEntities) {
|
||||
return
|
||||
}
|
||||
|
||||
decodeEntities = true
|
||||
|
||||
inlineScripts += `
|
||||
function decodeEntities (text) {
|
||||
var entities = [
|
||||
['apos', '\\''],
|
||||
['amp', '&'],
|
||||
['lt', '<'],
|
||||
['gt', '>'],
|
||||
['#63', '\\?'],
|
||||
['#36', '\\$']
|
||||
]
|
||||
|
||||
for (var i = 0, max = entities.length; i < max; ++i) {
|
||||
text = text.replace(new RegExp(\`&\${entities[i][0]};\`, 'g'), entities[i][1])
|
||||
}
|
||||
|
||||
return text
|
||||
}`
|
||||
}
|
||||
|
||||
let lodash = false
|
||||
function addLodash() {
|
||||
if (lodash) {
|
||||
return
|
||||
}
|
||||
|
||||
lodash = true
|
||||
|
||||
exportTasks.push({
|
||||
src: unprefix(`${appPath}/node_modules/lodash/lodash.min.js`),
|
||||
dst: 'js'
|
||||
})
|
||||
|
||||
scripts += `<script src="js/lodash.min.js"></script>`
|
||||
}
|
||||
|
||||
let raphael = false
|
||||
function addRaphael() {
|
||||
if (raphael) {
|
||||
return
|
||||
}
|
||||
|
||||
raphael = true
|
||||
|
||||
exportTasks.push({
|
||||
src: unprefix(`${appPath}/node_modules/raphael/raphael.min.js`),
|
||||
dst: 'js'
|
||||
})
|
||||
|
||||
scripts += `<script src="js/raphael.min.js"></script>`
|
||||
}
|
||||
|
||||
let yaml = false
|
||||
function addYAML() {
|
||||
if (yaml) {
|
||||
return
|
||||
}
|
||||
|
||||
yaml = true
|
||||
|
||||
exportTasks.push({
|
||||
src: unprefix(`${appPath}/node_modules/js-yaml/dist/js-yaml.min.js`),
|
||||
dst: 'js'
|
||||
})
|
||||
|
||||
scripts += `<script src="js/js-yaml.min.js"></script>`
|
||||
}
|
||||
|
||||
let chart = false
|
||||
function addChart() {
|
||||
if (chart) {
|
||||
return
|
||||
}
|
||||
|
||||
chart = true
|
||||
|
||||
addLodash()
|
||||
|
||||
exportTasks.push({
|
||||
src: unprefix(`${appPath}/node_modules/chart.js/dist/Chart.min.js`),
|
||||
dst: 'js'
|
||||
})
|
||||
|
||||
scripts += `<script src="js/Chart.min.js"></script>`
|
||||
|
||||
inlineScripts += `
|
||||
function displayCharts() {
|
||||
_.forEach(
|
||||
document.querySelectorAll('.chart'),
|
||||
el => {
|
||||
try {
|
||||
const format = el.attributes.getNamedItem('data-format').value
|
||||
const chartConfig = format === 'yaml' ? jsyaml.load(el.innerHTML) : JSON.parse(el.innerHTML)
|
||||
el.innerHTML = ''
|
||||
|
||||
const canvas = document.createElement('canvas')
|
||||
el.appendChild(canvas)
|
||||
|
||||
const height = el.attributes.getNamedItem('data-height')
|
||||
if (height && height.value !== 'undefined') {
|
||||
el.style.height = height.value + 'vh'
|
||||
canvas.height = height.value + 'vh'
|
||||
}
|
||||
|
||||
const chart = new Chart(canvas, chartConfig)
|
||||
} catch (e) {
|
||||
el.className = 'chart-error'
|
||||
el.innerHTML = 'chartjs diagram parse error: ' + e.message
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', displayCharts);
|
||||
`
|
||||
}
|
||||
|
||||
let codemirror = false
|
||||
function addCodeMirror() {
|
||||
if (codemirror) {
|
||||
return
|
||||
}
|
||||
|
||||
codemirror = true
|
||||
|
||||
addDecodeEntities()
|
||||
addLodash()
|
||||
|
||||
exportTasks.push(
|
||||
{
|
||||
src: unprefix(`${appPath}/node_modules/codemirror/lib/codemirror.js`),
|
||||
dst: 'js/codemirror'
|
||||
},
|
||||
{
|
||||
src: unprefix(`${appPath}/node_modules/codemirror/mode/meta.js`),
|
||||
dst: 'js/codemirror/mode'
|
||||
},
|
||||
{
|
||||
src: unprefix(
|
||||
`${appPath}/node_modules/codemirror/addon/mode/loadmode.js`
|
||||
),
|
||||
dst: 'js/codemirror/addon/mode'
|
||||
},
|
||||
{
|
||||
src: unprefix(
|
||||
`${appPath}/node_modules/codemirror/addon/runmode/runmode.js`
|
||||
),
|
||||
dst: 'js/codemirror/addon/runmode'
|
||||
}
|
||||
)
|
||||
|
||||
scripts += `
|
||||
<script src="js/codemirror/codemirror.js"></script>
|
||||
<script src="js/codemirror/mode/meta.js"></script>
|
||||
<script src="js/codemirror/addon/mode/loadmode.js"></script>
|
||||
<script src="js/codemirror/addon/runmode/runmode.js"></script>
|
||||
`
|
||||
|
||||
let className = `cm-s-${codeBlockTheme}`
|
||||
if (codeBlockTheme.indexOf('solarized') === 0) {
|
||||
const [refThema, color] = codeBlockTheme.split(' ')
|
||||
className = `cm-s-${refThema} cm-s-${color}`
|
||||
}
|
||||
|
||||
inlineScripts += `
|
||||
CodeMirror.modeURL = 'https://cdn.jsdelivr.net/npm/codemirror@${codemirrorVersion}/mode/%N/%N.js';
|
||||
|
||||
function displayCodeBlocks() {
|
||||
_.forEach(
|
||||
document.querySelectorAll('.code code'),
|
||||
el => {
|
||||
el.parentNode.className += ' ${className}'
|
||||
let syntax = CodeMirror.findModeByName(el.className)
|
||||
if (syntax == null) syntax = CodeMirror.findModeByName('Plain Text')
|
||||
CodeMirror.requireMode(syntax.mode, () => {
|
||||
const content = decodeEntities(el.innerHTML)
|
||||
el.innerHTML = ''
|
||||
CodeMirror.runMode(content, syntax.mime, el, {
|
||||
tabSize: ${indentSize}
|
||||
})
|
||||
})
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', displayCodeBlocks);
|
||||
`
|
||||
}
|
||||
|
||||
let flowchart = false
|
||||
function addFlowchart() {
|
||||
if (flowchart) {
|
||||
return
|
||||
}
|
||||
|
||||
flowchart = true
|
||||
|
||||
addDecodeEntities()
|
||||
addLodash()
|
||||
addRaphael()
|
||||
|
||||
exportTasks.push({
|
||||
src: unprefix(
|
||||
`${appPath}/node_modules/flowchart.js/release/flowchart.min.js`
|
||||
),
|
||||
dst: 'js'
|
||||
})
|
||||
|
||||
scripts += `<script src="js/flowchart.min.js"></script>`
|
||||
|
||||
inlineScripts += `
|
||||
function displayFlowcharts() {
|
||||
_.forEach(
|
||||
document.querySelectorAll('.flowchart'),
|
||||
el => {
|
||||
try {
|
||||
const diagram = flowchart.parse(
|
||||
decodeEntities(el.innerHTML)
|
||||
)
|
||||
el.innerHTML = ''
|
||||
diagram.drawSVG(el)
|
||||
} catch (e) {
|
||||
el.className = 'flowchart-error'
|
||||
el.innerHTML = 'Flowchart parse error: ' + e.message
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', displayFlowcharts);
|
||||
`
|
||||
}
|
||||
|
||||
let mermaid = false
|
||||
function addMermaid() {
|
||||
if (mermaid) {
|
||||
return
|
||||
}
|
||||
|
||||
mermaid = true
|
||||
|
||||
addLodash()
|
||||
|
||||
exportTasks.push({
|
||||
src: unprefix(`${appPath}/node_modules/mermaid/dist/mermaid.min.js`),
|
||||
dst: 'js'
|
||||
})
|
||||
|
||||
scripts += `<script src="js/mermaid.min.js"></script>`
|
||||
|
||||
inlineScripts += `
|
||||
function displayMermaids() {
|
||||
_.forEach(
|
||||
document.querySelectorAll('.mermaid'),
|
||||
el => {
|
||||
const height = el.attributes.getNamedItem('data-height')
|
||||
if (height && height.value !== 'undefined') {
|
||||
el.style.height = height.value + 'vh'
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', displayMermaids);
|
||||
`
|
||||
}
|
||||
|
||||
let sequence = false
|
||||
function addSequence() {
|
||||
if (sequence) {
|
||||
return
|
||||
}
|
||||
|
||||
sequence = true
|
||||
|
||||
addDecodeEntities()
|
||||
addLodash()
|
||||
addRaphael()
|
||||
|
||||
exportTasks.push({
|
||||
src: unprefix(
|
||||
`${appPath}/node_modules/@rokt33r/js-sequence-diagrams/dist/sequence-diagram-min.js`
|
||||
),
|
||||
dst: 'js'
|
||||
})
|
||||
|
||||
scripts += `<script src="js/sequence-diagram-min.js"></script>`
|
||||
|
||||
inlineScripts += `
|
||||
function displaySequences() {
|
||||
_.forEach(
|
||||
document.querySelectorAll('.sequence'),
|
||||
el => {
|
||||
try {
|
||||
const diagram = Diagram.parse(
|
||||
decodeEntities(el.innerHTML)
|
||||
)
|
||||
el.innerHTML = ''
|
||||
diagram.drawSVG(el, { theme: 'simple' })
|
||||
} catch (e) {
|
||||
el.className = 'sequence-error'
|
||||
el.innerHTML = 'Sequence diagram parse error: ' + e.message
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
document.addEventListener('DOMContentLoaded', displaySequences);
|
||||
`
|
||||
}
|
||||
|
||||
const modes = {}
|
||||
const markdown = new Markdown({
|
||||
typographer: smartQuotes,
|
||||
sanitize,
|
||||
breaks,
|
||||
onFence(type, mode) {
|
||||
if (type === 'chart') {
|
||||
addChart()
|
||||
|
||||
if (mode === 'yaml') {
|
||||
addYAML()
|
||||
}
|
||||
} else if (type === 'code') {
|
||||
addCodeMirror()
|
||||
|
||||
if (mode && modes[mode] !== true) {
|
||||
const file = unprefix(
|
||||
`${appPath}/node_modules/codemirror/mode/${mode}/${mode}.js`
|
||||
)
|
||||
|
||||
if (fs.existsSync(file)) {
|
||||
exportTasks.push({
|
||||
src: file,
|
||||
dst: `js/codemirror/mode/${mode}`
|
||||
})
|
||||
|
||||
modes[mode] = true
|
||||
}
|
||||
}
|
||||
} else if (type === 'flowchart') {
|
||||
addFlowchart()
|
||||
} else if (type === 'mermaid') {
|
||||
addMermaid()
|
||||
} else if (type === 'sequence') {
|
||||
addSequence()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
let body = note.content
|
||||
|
||||
if (sanitize === 'NONE') {
|
||||
body = escapeHtmlCharactersInCodeTag(body.split('```'))
|
||||
}
|
||||
|
||||
body = markdown.render(note.content)
|
||||
|
||||
const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent(
|
||||
note.content,
|
||||
props.storagePath
|
||||
)
|
||||
|
||||
files.forEach(file => {
|
||||
exportTasks.push({
|
||||
src: unprefix(file),
|
||||
dst: 'css'
|
||||
})
|
||||
})
|
||||
|
||||
const destinationFolder = props.export.prefixAttachmentFolder
|
||||
? `${path.parse(targetPath).name} - ${
|
||||
attachmentManagement.DESTINATION_FOLDER
|
||||
}`
|
||||
: attachmentManagement.DESTINATION_FOLDER
|
||||
|
||||
attachmentsAbsolutePaths.forEach(attachment => {
|
||||
exportTasks.push({
|
||||
src: attachment,
|
||||
dst: destinationFolder
|
||||
})
|
||||
})
|
||||
|
||||
body = attachmentManagement.replaceStorageReferences(
|
||||
body,
|
||||
note.key,
|
||||
destinationFolder
|
||||
)
|
||||
|
||||
return `
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name = "viewport" content = "width = device-width, initial-scale = 1, maximum-scale = 1">
|
||||
<style id="style">${inlineStyles}</style>
|
||||
${styles}
|
||||
${scripts}
|
||||
<script>${inlineScripts}</script>
|
||||
</head>
|
||||
<body data-theme="${theme}">
|
||||
${body}
|
||||
</body>
|
||||
</html>
|
||||
`
|
||||
}
|
||||
}
|
||||
|
||||
export function getStyleParams(props) {
|
||||
const {
|
||||
fontSize,
|
||||
lineNumber,
|
||||
codeBlockTheme,
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS,
|
||||
RTL
|
||||
} = props
|
||||
|
||||
let { fontFamily, codeBlockFontFamily } = props
|
||||
|
||||
fontFamily =
|
||||
_.isString(fontFamily) && fontFamily.trim().length > 0
|
||||
? fontFamily
|
||||
.split(',')
|
||||
.map(fontName => fontName.trim())
|
||||
.concat(defaultFontFamily)
|
||||
: defaultFontFamily
|
||||
|
||||
codeBlockFontFamily =
|
||||
_.isString(codeBlockFontFamily) && codeBlockFontFamily.trim().length > 0
|
||||
? codeBlockFontFamily
|
||||
.split(',')
|
||||
.map(fontName => fontName.trim())
|
||||
.concat(defaultCodeBlockFontFamily)
|
||||
: defaultCodeBlockFontFamily
|
||||
|
||||
return {
|
||||
fontFamily,
|
||||
fontSize,
|
||||
codeBlockFontFamily,
|
||||
lineNumber,
|
||||
codeBlockTheme,
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS,
|
||||
RTL
|
||||
}
|
||||
}
|
||||
|
||||
export function getCodeThemeLink(name) {
|
||||
const theme = consts.THEMES.find(theme => theme.name === name)
|
||||
|
||||
return theme != null
|
||||
? theme.path
|
||||
: `${appPath}/node_modules/codemirror/theme/elegant.css`
|
||||
}
|
||||
|
||||
export function buildStyle(
|
||||
fontFamily,
|
||||
fontSize,
|
||||
codeBlockFontFamily,
|
||||
lineNumber,
|
||||
scrollPastEnd,
|
||||
theme,
|
||||
allowCustomCSS,
|
||||
customCSS,
|
||||
RTL
|
||||
) {
|
||||
return `
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
src: url('${appPath}/resources/fonts/Lato-Regular.woff2') format('woff2'), /* Modern Browsers */
|
||||
url('${appPath}/resources/fonts/Lato-Regular.woff') format('woff'), /* Modern Browsers */
|
||||
url('${appPath}/resources/fonts/Lato-Regular.ttf') format('truetype');
|
||||
font-style: normal;
|
||||
font-weight: normal;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Lato';
|
||||
src: url('${appPath}/resources/fonts/Lato-Black.woff2') format('woff2'), /* Modern Browsers */
|
||||
url('${appPath}/resources/fonts/Lato-Black.woff') format('woff'), /* Modern Browsers */
|
||||
url('${appPath}/resources/fonts/Lato-Black.ttf') format('truetype');
|
||||
font-style: normal;
|
||||
font-weight: 700;
|
||||
text-rendering: optimizeLegibility;
|
||||
}
|
||||
@font-face {
|
||||
font-family: 'Material Icons';
|
||||
font-style: normal;
|
||||
font-weight: 400;
|
||||
src: local('Material Icons'),
|
||||
local('MaterialIcons-Regular'),
|
||||
url('${appPath}/resources/fonts/MaterialIcons-Regular.woff2') format('woff2'),
|
||||
url('${appPath}/resources/fonts/MaterialIcons-Regular.woff') format('woff'),
|
||||
url('${appPath}/resources/fonts/MaterialIcons-Regular.ttf') format('truetype');
|
||||
}
|
||||
${markdownStyle}
|
||||
|
||||
body {
|
||||
font-family: '${fontFamily.join("','")}';
|
||||
font-size: ${fontSize}px;
|
||||
${scrollPastEnd && 'padding-bottom: 90vh;box-sizing: border-box;'}
|
||||
${RTL && 'direction: rtl;text-align: right;'}
|
||||
}
|
||||
@media print {
|
||||
body {
|
||||
padding-bottom: initial;
|
||||
}
|
||||
}
|
||||
|
||||
code {
|
||||
font-family: '${codeBlockFontFamily.join("','")}';
|
||||
background-color: rgba(0,0,0,0.04);
|
||||
text-align: left;
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
p code.inline,
|
||||
li code.inline,
|
||||
td code.inline
|
||||
{
|
||||
padding: 2px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-radius: 5px;
|
||||
}
|
||||
[data-theme="default"] p code.inline,
|
||||
[data-theme="default"] li code.inline,
|
||||
[data-theme="default"] td code.inline
|
||||
{
|
||||
background-color: #F4F4F4;
|
||||
border-color: #d9d9d9;
|
||||
color: inherit;
|
||||
}
|
||||
[data-theme="white"] p code.inline,
|
||||
[data-theme="white"] li code.inline,
|
||||
[data-theme="white"] td code.inline
|
||||
{
|
||||
background-color: #F4F4F4;
|
||||
border-color: #d9d9d9;
|
||||
color: inherit;
|
||||
}
|
||||
[data-theme="dark"] p code.inline,
|
||||
[data-theme="dark"] li code.inline,
|
||||
[data-theme="dark"] td code.inline
|
||||
{
|
||||
background-color: #444444;
|
||||
border-color: #555;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
[data-theme="dracula"] p code.inline,
|
||||
[data-theme="dracula"] li code.inline,
|
||||
[data-theme="dracula"] td code.inline
|
||||
{
|
||||
background-color: #444444;
|
||||
border-color: #555;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
[data-theme="monokai"] p code.inline,
|
||||
[data-theme="monokai"] li code.inline,
|
||||
[data-theme="monokai"] td code.inline
|
||||
{
|
||||
background-color: #444444;
|
||||
border-color: #555;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
[data-theme="nord"] p code.inline,
|
||||
[data-theme="nord"] li code.inline,
|
||||
[data-theme="nord"] td code.inline
|
||||
{
|
||||
background-color: #444444;
|
||||
border-color: #555;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
[data-theme="solarized-dark"] p code.inline,
|
||||
[data-theme="solarized-dark"] li code.inline,
|
||||
[data-theme="solarized-dark"] td code.inline
|
||||
{
|
||||
background-color: #444444;
|
||||
border-color: #555;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
[data-theme="vulcan"] p code.inline,
|
||||
[data-theme="vulcan"] li code.inline,
|
||||
[data-theme="vulcan"] td code.inline
|
||||
{
|
||||
background-color: #444444;
|
||||
border-color: #555;
|
||||
color: #FFFFFF;
|
||||
}
|
||||
|
||||
.lineNumber {
|
||||
${lineNumber && 'display: block !important;'}
|
||||
font-family: '${codeBlockFontFamily.join("','")}';
|
||||
}
|
||||
|
||||
.clipboardButton {
|
||||
color: rgba(147,147,149,0.8);;
|
||||
fill: rgba(147,147,149,1);;
|
||||
border-radius: 50%;
|
||||
margin: 0px 10px;
|
||||
border: none;
|
||||
background-color: transparent;
|
||||
outline: none;
|
||||
height: 15px;
|
||||
width: 15px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.clipboardButton:hover {
|
||||
transition: 0.2s;
|
||||
color: #939395;
|
||||
fill: #939395;
|
||||
background-color: rgba(0,0,0,0.1);
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
border: none;
|
||||
}
|
||||
|
||||
h1 {
|
||||
padding-bottom: 4px;
|
||||
margin: 1em 0 8px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
padding-bottom: 0.2em;
|
||||
margin: 1em 0 0.37em;
|
||||
}
|
||||
|
||||
body p {
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
@media print {
|
||||
body[data-theme="${theme}"] {
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
}
|
||||
.clipboardButton {
|
||||
display: none
|
||||
}
|
||||
}
|
||||
|
||||
${allowCustomCSS ? customCSS : ''}
|
||||
`
|
||||
}
|
||||
|
||||
/**
|
||||
* @description Convert special characters between three ```
|
||||
* @param {string[]} splitWithCodeTag Array of HTML strings separated by three ```
|
||||
* @returns {string} HTML in which special characters between three ``` have been converted
|
||||
*/
|
||||
export function escapeHtmlCharactersInCodeTag(splitWithCodeTag) {
|
||||
for (let index = 0; index < splitWithCodeTag.length; index++) {
|
||||
const codeTagRequired =
|
||||
splitWithCodeTag[index] !== '```' && index < splitWithCodeTag.length - 1
|
||||
if (codeTagRequired) {
|
||||
splitWithCodeTag.splice(index + 1, 0, '```')
|
||||
}
|
||||
}
|
||||
let inCodeTag = false
|
||||
let result = ''
|
||||
for (let content of splitWithCodeTag) {
|
||||
if (content === '```') {
|
||||
inCodeTag = !inCodeTag
|
||||
} else if (inCodeTag) {
|
||||
content = escapeHtmlCharacters(content)
|
||||
}
|
||||
result += content
|
||||
}
|
||||
return result
|
||||
}
|
||||
103
browser/main/lib/dataApi/formatMarkdown.js
Normal file
103
browser/main/lib/dataApi/formatMarkdown.js
Normal file
@@ -0,0 +1,103 @@
|
||||
import attachmentManagement from './attachmentManagement'
|
||||
import yaml from 'js-yaml'
|
||||
import path from 'path'
|
||||
|
||||
const delimiterRegExp = /^\-{3}/
|
||||
|
||||
/**
|
||||
* ```
|
||||
* {
|
||||
* storagePath,
|
||||
* export
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export default function formatMarkdown(props) {
|
||||
return function(note, targetPath, exportTasks) {
|
||||
let result = note.content
|
||||
|
||||
if (props.storagePath && note.key) {
|
||||
const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent(
|
||||
result,
|
||||
props.storagePath
|
||||
)
|
||||
|
||||
const destinationFolder = props.export.prefixAttachmentFolder
|
||||
? `${path.parse(targetPath).name} - ${
|
||||
attachmentManagement.DESTINATION_FOLDER
|
||||
}`
|
||||
: attachmentManagement.DESTINATION_FOLDER
|
||||
|
||||
attachmentsAbsolutePaths.forEach(attachment => {
|
||||
exportTasks.push({
|
||||
src: attachment,
|
||||
dst: destinationFolder
|
||||
})
|
||||
})
|
||||
|
||||
result = attachmentManagement.replaceStorageReferences(
|
||||
result,
|
||||
note.key,
|
||||
destinationFolder
|
||||
)
|
||||
}
|
||||
|
||||
if (props.export.metadata === 'MERGE_HEADER') {
|
||||
const metadata = getFrontMatter(result)
|
||||
|
||||
const values = Object.assign({}, note)
|
||||
delete values.content
|
||||
delete values.isTrashed
|
||||
|
||||
for (const key in values) {
|
||||
metadata[key] = values[key]
|
||||
}
|
||||
|
||||
result = replaceFrontMatter(result, metadata)
|
||||
} else if (props.export.metadata === 'MERGE_VARIABLE') {
|
||||
const metadata = getFrontMatter(result)
|
||||
|
||||
const values = Object.assign({}, note)
|
||||
delete values.content
|
||||
delete values.isTrashed
|
||||
|
||||
if (props.export.variable) {
|
||||
metadata[props.export.variable] = values
|
||||
} else {
|
||||
for (const key in values) {
|
||||
metadata[key] = values[key]
|
||||
}
|
||||
}
|
||||
|
||||
result = replaceFrontMatter(result, metadata)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
function getFrontMatter(markdown) {
|
||||
const lines = markdown.split('\n')
|
||||
|
||||
if (delimiterRegExp.test(lines[0])) {
|
||||
let line = 0
|
||||
while (++line < lines.length && !delimiterRegExp.test(lines[line])) {}
|
||||
|
||||
return yaml.load(lines.slice(1, line).join('\n')) || {}
|
||||
} else {
|
||||
return {}
|
||||
}
|
||||
}
|
||||
|
||||
function replaceFrontMatter(markdown, metadata) {
|
||||
const lines = markdown.split('\n')
|
||||
|
||||
if (delimiterRegExp.test(lines[0])) {
|
||||
let line = 0
|
||||
while (++line < lines.length && !delimiterRegExp.test(lines[line])) {}
|
||||
|
||||
return `---\n${yaml.dump(metadata)}---\n${lines.slice(line + 1).join('\n')}`
|
||||
} else {
|
||||
return `---\n${yaml.dump(metadata)}---\n\n${markdown}`
|
||||
}
|
||||
}
|
||||
26
browser/main/lib/dataApi/formatPDF.js
Normal file
26
browser/main/lib/dataApi/formatPDF.js
Normal file
@@ -0,0 +1,26 @@
|
||||
import formatHTML from './formatHTML'
|
||||
import { remote } from 'electron'
|
||||
|
||||
export default function formatPDF(props) {
|
||||
return function(note, targetPath, exportTasks) {
|
||||
const printout = new remote.BrowserWindow({
|
||||
show: false,
|
||||
webPreferences: { webSecurity: false, javascript: false }
|
||||
})
|
||||
|
||||
printout.loadURL(
|
||||
'data:text/html;charset=UTF-8,' +
|
||||
formatHTML(props)(note, targetPath, exportTasks)
|
||||
)
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
printout.webContents.on('did-finish-load', () => {
|
||||
printout.webContents.printToPDF({}, (err, data) => {
|
||||
if (err) reject(err)
|
||||
else resolve(data)
|
||||
printout.destroy()
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
58
browser/main/lib/dataApi/getContentFormatter.js
Normal file
58
browser/main/lib/dataApi/getContentFormatter.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import formatMarkdown from './formatMarkdown'
|
||||
import formatHTML from './formatHTML'
|
||||
import formatPDF from './formatPDF'
|
||||
|
||||
/**
|
||||
* @param {Object} storage
|
||||
* @param {String} fileType
|
||||
* @param {Object} config
|
||||
*/
|
||||
|
||||
export default function getContentFormatter(storage, fileType, config) {
|
||||
if (fileType === 'md') {
|
||||
return formatMarkdown({
|
||||
storagePath: storage.path,
|
||||
export: config.export
|
||||
})
|
||||
} else if (fileType === 'html') {
|
||||
return formatHTML({
|
||||
theme: config.ui.theme,
|
||||
fontSize: config.preview.fontSize,
|
||||
fontFamily: config.preview.fontFamily,
|
||||
codeBlockTheme: config.preview.codeBlockTheme,
|
||||
codeBlockFontFamily: config.editor.fontFamily,
|
||||
lineNumber: config.preview.lineNumber,
|
||||
indentSize: config.editor.indentSize,
|
||||
scrollPastEnd: config.preview.scrollPastEnd,
|
||||
smartQuotes: config.preview.smartQuotes,
|
||||
breaks: config.preview.breaks,
|
||||
sanitize: config.preview.sanitize,
|
||||
customCSS: config.preview.customCSS,
|
||||
allowCustomCSS: config.preview.allowCustomCSS,
|
||||
storagePath: storage.path,
|
||||
export: config.export,
|
||||
RTL: config.editor.rtlEnabled /* && this.state.RTL */
|
||||
})
|
||||
} else if (fileType === 'pdf') {
|
||||
return formatPDF({
|
||||
theme: config.ui.theme,
|
||||
fontSize: config.preview.fontSize,
|
||||
fontFamily: config.preview.fontFamily,
|
||||
codeBlockTheme: config.preview.codeBlockTheme,
|
||||
codeBlockFontFamily: config.editor.fontFamily,
|
||||
lineNumber: config.preview.lineNumber,
|
||||
indentSize: config.editor.indentSize,
|
||||
scrollPastEnd: config.preview.scrollPastEnd,
|
||||
smartQuotes: config.preview.smartQuotes,
|
||||
breaks: config.preview.breaks,
|
||||
sanitize: config.preview.sanitize,
|
||||
customCSS: config.preview.customCSS,
|
||||
allowCustomCSS: config.preview.allowCustomCSS,
|
||||
storagePath: storage.path,
|
||||
export: config.export,
|
||||
RTL: config.editor.rtlEnabled /* && this.state.RTL */
|
||||
})
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
37
browser/main/lib/dataApi/getFilename.js
Normal file
37
browser/main/lib/dataApi/getFilename.js
Normal file
@@ -0,0 +1,37 @@
|
||||
import filenamify from 'filenamify'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
import path from 'path'
|
||||
|
||||
/**
|
||||
* @param {Object} note
|
||||
* @param {String} fileType
|
||||
* @param {String} directory
|
||||
* @param {Object} deduplicator
|
||||
*
|
||||
* @return {String}
|
||||
*/
|
||||
|
||||
function getFilename(note, fileType, directory, deduplicator) {
|
||||
const basename = note.title
|
||||
? filenamify(note.title, { replacement: '_' })
|
||||
: i18n.__('Untitled')
|
||||
|
||||
if (deduplicator) {
|
||||
if (deduplicator[basename]) {
|
||||
const filename = path.join(
|
||||
directory,
|
||||
`${basename} (${deduplicator[basename]}).${fileType}`
|
||||
)
|
||||
|
||||
++deduplicator[basename]
|
||||
|
||||
return filename
|
||||
} else {
|
||||
deduplicator[basename] = 1
|
||||
}
|
||||
}
|
||||
|
||||
return path.join(directory, `${basename}.${fileType}`)
|
||||
}
|
||||
|
||||
module.exports = getFilename
|
||||
@@ -15,11 +15,14 @@ const dataApi = {
|
||||
updateNote: require('./updateNote'),
|
||||
deleteNote: require('./deleteNote'),
|
||||
moveNote: require('./moveNote'),
|
||||
exportNoteAs: require('./exportNoteAs'),
|
||||
migrateFromV5Storage: require('./migrateFromV5Storage'),
|
||||
createSnippet: require('./createSnippet'),
|
||||
deleteSnippet: require('./deleteSnippet'),
|
||||
updateSnippet: require('./updateSnippet'),
|
||||
fetchSnippet: require('./fetchSnippet'),
|
||||
exportTag: require('./exportTag'),
|
||||
getFilename: require('./getFilename'),
|
||||
|
||||
_migrateFromV6Storage: require('./migrateFromV6Storage'),
|
||||
_resolveStorageData: require('./resolveStorageData'),
|
||||
|
||||
184
browser/main/modals/PreferencesModal/ExportTab.js
Normal file
184
browser/main/modals/PreferencesModal/ExportTab.js
Normal file
@@ -0,0 +1,184 @@
|
||||
import PropTypes from 'prop-types'
|
||||
import React from 'react'
|
||||
import CSSModules from 'browser/lib/CSSModules'
|
||||
import styles from './ConfigTab.styl'
|
||||
import ConfigManager from 'browser/main/lib/ConfigManager'
|
||||
import store from 'browser/main/store'
|
||||
import _ from 'lodash'
|
||||
import i18n from 'browser/lib/i18n'
|
||||
|
||||
const electron = require('electron')
|
||||
const ipc = electron.ipcRenderer
|
||||
|
||||
class ExportTab extends React.Component {
|
||||
constructor(props) {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
config: props.config
|
||||
}
|
||||
}
|
||||
|
||||
clearMessage() {
|
||||
_.debounce(() => {
|
||||
this.setState({
|
||||
ExportAlert: null
|
||||
})
|
||||
}, 2000)()
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
this.handleSettingDone = () => {
|
||||
this.setState({
|
||||
ExportAlert: {
|
||||
type: 'success',
|
||||
message: i18n.__('Successfully applied!')
|
||||
}
|
||||
})
|
||||
}
|
||||
this.handleSettingError = err => {
|
||||
this.setState({
|
||||
ExportAlert: {
|
||||
type: 'error',
|
||||
message:
|
||||
err.message != null ? err.message : i18n.__('An error occurred!')
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
this.oldExport = this.state.config.export
|
||||
|
||||
ipc.addListener('APP_SETTING_DONE', this.handleSettingDone)
|
||||
ipc.addListener('APP_SETTING_ERROR', this.handleSettingError)
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
ipc.removeListener('APP_SETTING_DONE', this.handleSettingDone)
|
||||
ipc.removeListener('APP_SETTING_ERROR', this.handleSettingError)
|
||||
}
|
||||
|
||||
handleSaveButtonClick(e) {
|
||||
const newConfig = {
|
||||
export: this.state.config.export
|
||||
}
|
||||
|
||||
ConfigManager.set(newConfig)
|
||||
|
||||
store.dispatch({
|
||||
type: 'SET_UI',
|
||||
config: newConfig
|
||||
})
|
||||
|
||||
this.clearMessage()
|
||||
this.props.haveToSave()
|
||||
}
|
||||
|
||||
handleExportChange(e) {
|
||||
const { config } = this.state
|
||||
|
||||
config.export = {
|
||||
metadata: this.refs.metadata.value,
|
||||
variable: !_.isNil(this.refs.variable)
|
||||
? this.refs.variable.value
|
||||
: config.export.variable,
|
||||
prefixAttachmentFolder: this.refs.prefixAttachmentFolder.checked
|
||||
}
|
||||
|
||||
this.setState({
|
||||
config
|
||||
})
|
||||
|
||||
if (_.isEqual(this.oldExport, config.export)) {
|
||||
this.props.haveToSave()
|
||||
} else {
|
||||
this.props.haveToSave({
|
||||
tab: 'Export',
|
||||
type: 'warning',
|
||||
message: i18n.__('Unsaved Changes!')
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
render() {
|
||||
const { config, ExportAlert } = this.state
|
||||
|
||||
const ExportAlertElement =
|
||||
ExportAlert != null ? (
|
||||
<p className={`alert ${ExportAlert.type}`}>{ExportAlert.message}</p>
|
||||
) : null
|
||||
|
||||
return (
|
||||
<div styleName='root'>
|
||||
<div styleName='group'>
|
||||
<div styleName='group-header'>{i18n.__('Export')}</div>
|
||||
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>{i18n.__('Metadata')}</div>
|
||||
<div styleName='group-section-control'>
|
||||
<select
|
||||
value={config.export.metadata}
|
||||
onChange={e => this.handleExportChange(e)}
|
||||
ref='metadata'
|
||||
>
|
||||
<option value='DONT_EXPORT'>{i18n.__(`Don't export`)}</option>
|
||||
<option value='MERGE_HEADER'>
|
||||
{i18n.__('Merge with the header')}
|
||||
</option>
|
||||
<option value='MERGE_VARIABLE'>
|
||||
{i18n.__('Merge with a variable')}
|
||||
</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{config.export.metadata === 'MERGE_VARIABLE' && (
|
||||
<div styleName='group-section'>
|
||||
<div styleName='group-section-label'>
|
||||
{i18n.__('Variable Name')}
|
||||
</div>
|
||||
<div styleName='group-section-control'>
|
||||
<input
|
||||
styleName='group-section-control-input'
|
||||
onChange={e => this.handleExportChange(e)}
|
||||
ref='variable'
|
||||
value={config.export.variable}
|
||||
type='text'
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<div styleName='group-checkBoxSection'>
|
||||
<label>
|
||||
<input
|
||||
onChange={e => this.handleExportChange(e)}
|
||||
checked={config.export.prefixAttachmentFolder}
|
||||
ref='prefixAttachmentFolder'
|
||||
type='checkbox'
|
||||
/>
|
||||
|
||||
{i18n.__('Prefix attachment folder')}
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div styleName='group-control'>
|
||||
<button
|
||||
styleName='group-control-rightButton'
|
||||
onClick={e => this.handleSaveButtonClick(e)}
|
||||
>
|
||||
{i18n.__('Save')}
|
||||
</button>
|
||||
{ExportAlertElement}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
ExportTab.propTypes = {
|
||||
dispatch: PropTypes.func,
|
||||
haveToSave: PropTypes.func
|
||||
}
|
||||
|
||||
export default CSSModules(ExportTab, styles)
|
||||
@@ -16,25 +16,78 @@ class InfoTab extends React.Component {
|
||||
super(props)
|
||||
|
||||
this.state = {
|
||||
config: this.props.config
|
||||
config: this.props.config,
|
||||
subscriptionFormStatus: 'idle',
|
||||
subscriptionFormErrorMessage: null,
|
||||
subscriptionFormEmail: ''
|
||||
}
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { autoUpdateEnabled, amaEnabled } = ConfigManager.get()
|
||||
|
||||
this.setState({ config: { autoUpdateEnabled, amaEnabled } })
|
||||
}
|
||||
|
||||
handleLinkClick(e) {
|
||||
shell.openExternal(e.currentTarget.href)
|
||||
e.preventDefault()
|
||||
}
|
||||
|
||||
handleConfigChange(e) {
|
||||
const newConfig = { amaEnabled: this.refs.amaEnabled.checked }
|
||||
const newConfig = {
|
||||
amaEnabled: this.refs.amaEnabled.checked,
|
||||
autoUpdateEnabled: this.refs.autoUpdateEnabled.checked
|
||||
}
|
||||
|
||||
this.setState({ config: newConfig })
|
||||
return newConfig
|
||||
}
|
||||
|
||||
handleSubscriptionFormSubmit(e) {
|
||||
e.preventDefault()
|
||||
this.setState({
|
||||
subscriptionFormStatus: 'sending',
|
||||
subscriptionFormErrorMessage: null
|
||||
})
|
||||
|
||||
fetch(
|
||||
'https://boostmails.boostio.co/api/public/lists/5f434dccd05f3160b41c0d49/subscriptions',
|
||||
{
|
||||
headers: {
|
||||
Accept: 'application/json',
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
method: 'POST',
|
||||
body: JSON.stringify({ email: this.state.subscriptionFormEmail })
|
||||
}
|
||||
)
|
||||
.then(response => {
|
||||
if (response.status >= 400) {
|
||||
return response.text().then(text => {
|
||||
throw new Error(text)
|
||||
})
|
||||
}
|
||||
this.setState({
|
||||
subscriptionFormStatus: 'done'
|
||||
})
|
||||
})
|
||||
.catch(error => {
|
||||
this.setState({
|
||||
subscriptionFormStatus: 'idle',
|
||||
subscriptionFormErrorMessage: error.message
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
handleSubscriptionFormEmailChange(e) {
|
||||
this.setState({
|
||||
subscriptionFormEmail: e.target.value
|
||||
})
|
||||
}
|
||||
|
||||
handleSaveButtonClick(e) {
|
||||
const newConfig = {
|
||||
amaEnabled: this.state.config.amaEnabled
|
||||
}
|
||||
const newConfig = this.state.config
|
||||
|
||||
if (!newConfig.amaEnabled) {
|
||||
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('DISABLE_AMA')
|
||||
@@ -61,20 +114,17 @@ class InfoTab extends React.Component {
|
||||
})
|
||||
}
|
||||
|
||||
toggleAutoUpdate() {
|
||||
const newConfig = {
|
||||
autoUpdateEnabled: !this.state.config.autoUpdateEnabled
|
||||
}
|
||||
|
||||
this.setState({ config: newConfig })
|
||||
ConfigManager.set(newConfig)
|
||||
}
|
||||
|
||||
infoMessage() {
|
||||
const { amaMessage } = this.state
|
||||
return amaMessage ? <p styleName='policy-confirm'>{amaMessage}</p> : null
|
||||
}
|
||||
|
||||
handleAutoUpdateChange() {
|
||||
const { autoUpdateEnabled } = this.handleConfigChange()
|
||||
|
||||
ConfigManager.set({ autoUpdateEnabled })
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div styleName='root'>
|
||||
@@ -134,6 +184,40 @@ class InfoTab extends React.Component {
|
||||
|
||||
<hr />
|
||||
|
||||
<div styleName='group-header--sub'>Subscribe Update Notes</div>
|
||||
{this.state.subscriptionFormStatus === 'done' ? (
|
||||
<div>
|
||||
<blockquote color={{ color: 'green' }}>
|
||||
Thanks for the subscription!
|
||||
</blockquote>
|
||||
</div>
|
||||
) : (
|
||||
<div>
|
||||
{this.state.subscriptionFormErrorMessage != null && (
|
||||
<blockquote style={{ color: 'red' }}>
|
||||
{this.state.subscriptionFormErrorMessage}
|
||||
</blockquote>
|
||||
)}
|
||||
<form onSubmit={e => this.handleSubscriptionFormSubmit(e)}>
|
||||
<input
|
||||
styleName='subscription-email-input'
|
||||
placeholder='E-mail'
|
||||
type='email'
|
||||
onChange={e => this.handleSubscriptionFormEmailChange(e)}
|
||||
disabled={this.state.subscriptionFormStatus === 'sending'}
|
||||
/>
|
||||
<button
|
||||
styleName='subscription-submit-button'
|
||||
type='submit'
|
||||
disabled={this.state.subscriptionFormStatus === 'sending'}
|
||||
>
|
||||
Subscribe
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
)}
|
||||
<hr />
|
||||
|
||||
<div styleName='group-header--sub'>{i18n.__('About')}</div>
|
||||
|
||||
<div styleName='top'>
|
||||
@@ -181,7 +265,8 @@ class InfoTab extends React.Component {
|
||||
<label>
|
||||
<input
|
||||
type='checkbox'
|
||||
onChange={this.toggleAutoUpdate.bind(this)}
|
||||
ref='autoUpdateEnabled'
|
||||
onChange={() => this.handleAutoUpdateChange()}
|
||||
checked={this.state.config.autoUpdateEnabled}
|
||||
/>
|
||||
{i18n.__('Enable Auto Update')}
|
||||
|
||||
@@ -33,6 +33,35 @@
|
||||
.separate-line
|
||||
margin 40px 0
|
||||
|
||||
.subscription-email-input
|
||||
height 35px
|
||||
vertical-align middle
|
||||
width 200px
|
||||
font-size $tab--button-font-size
|
||||
border solid 1px $border-color
|
||||
border-radius 2px
|
||||
padding 0 5px
|
||||
margin-right 5px
|
||||
outline none
|
||||
&:disabled
|
||||
background-color $ui-input--disabled-backgroundColor
|
||||
|
||||
.subscription-submit-button
|
||||
margin-top 10px
|
||||
height 35px
|
||||
border-radius 2px
|
||||
border none
|
||||
background-color alpha(#1EC38B, 90%)
|
||||
padding-left 20px
|
||||
padding-right 20px
|
||||
text-decoration none
|
||||
color white
|
||||
font-weight 600
|
||||
font-size 16px
|
||||
&:hover
|
||||
background-color #1EC38B
|
||||
transition 0.2s
|
||||
|
||||
.policy-submit
|
||||
margin-top 10px
|
||||
height 35px
|
||||
|
||||
@@ -6,6 +6,7 @@ import UiTab from './UiTab'
|
||||
import InfoTab from './InfoTab'
|
||||
import Crowdfunding from './Crowdfunding'
|
||||
import StoragesTab from './StoragesTab'
|
||||
import ExportTab from './ExportTab'
|
||||
import SnippetTab from './SnippetTab'
|
||||
import PluginsTab from './PluginsTab'
|
||||
import Blog from './Blog'
|
||||
@@ -24,7 +25,8 @@ class Preferences extends React.Component {
|
||||
currentTab: 'STORAGES',
|
||||
UIAlert: '',
|
||||
HotkeyAlert: '',
|
||||
BlogAlert: ''
|
||||
BlogAlert: '',
|
||||
ExportAlert: ''
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,6 +83,15 @@ class Preferences extends React.Component {
|
||||
haveToSave={alert => this.setState({ BlogAlert: alert })}
|
||||
/>
|
||||
)
|
||||
case 'EXPORT':
|
||||
return (
|
||||
<ExportTab
|
||||
dispatch={dispatch}
|
||||
config={config}
|
||||
data={data}
|
||||
haveToSave={alert => this.setState({ ExportAlert: alert })}
|
||||
/>
|
||||
)
|
||||
case 'SNIPPET':
|
||||
return <SnippetTab dispatch={dispatch} config={config} data={data} />
|
||||
case 'PLUGINS':
|
||||
@@ -131,6 +142,11 @@ class Preferences extends React.Component {
|
||||
{ target: 'INFO', label: i18n.__('About') },
|
||||
{ target: 'CROWDFUNDING', label: i18n.__('Crowdfunding') },
|
||||
{ target: 'BLOG', label: i18n.__('Blog'), Blog: this.state.BlogAlert },
|
||||
{
|
||||
target: 'EXPORT',
|
||||
label: i18n.__('Export'),
|
||||
Export: this.state.ExportAlert
|
||||
},
|
||||
{ target: 'SNIPPET', label: i18n.__('Snippets') },
|
||||
{ target: 'PLUGINS', label: i18n.__('Plugins') }
|
||||
]
|
||||
|
||||
@@ -187,7 +187,7 @@ module.exports = function(grunt) {
|
||||
}
|
||||
|
||||
ChildProcess.exec(
|
||||
`codesign --verbose --deep --force --sign \"${OSX_COMMON_NAME}\" dist/Boostnote-darwin-x64/Boostnote.app`,
|
||||
`codesign --verbose --deep --force --timestamp=none --sign \"${OSX_COMMON_NAME}\" dist/Boostnote-darwin-x64/Boostnote.app`,
|
||||
function(err, stdout, stderr) {
|
||||
grunt.log.writeln(stdout)
|
||||
if (err) {
|
||||
|
||||
@@ -26,6 +26,7 @@ if (!singleInstance) {
|
||||
}
|
||||
|
||||
var isUpdateReady = false
|
||||
let updateFound = false
|
||||
|
||||
var ghReleasesOpts = {
|
||||
repo: 'BoostIO/boost-releases',
|
||||
@@ -36,25 +37,33 @@ const updater = new GhReleases(ghReleasesOpts)
|
||||
|
||||
// Check for updates
|
||||
// `status` returns true if there is a new update available
|
||||
function checkUpdate() {
|
||||
function checkUpdate(manualTriggered = false) {
|
||||
if (!isPackaged) {
|
||||
// Prevents app from attempting to update when in dev mode.
|
||||
console.log('Updates are disabled in Development mode, see main-app.js')
|
||||
return true
|
||||
}
|
||||
if (!electronConfig.get('autoUpdateEnabled', true)) return
|
||||
if (process.platform === 'linux' || isUpdateReady) {
|
||||
|
||||
// End if auto updates disabled and it is an automatic check
|
||||
if (!electronConfig.get('autoUpdateEnabled', true) && !manualTriggered) return
|
||||
|
||||
if (process.platform === 'linux' || isUpdateReady || updateFound) {
|
||||
return true
|
||||
}
|
||||
|
||||
updater.check((err, status) => {
|
||||
if (err) {
|
||||
var isLatest = err.message === 'There is no newer version.'
|
||||
if (!isLatest) console.error('Updater error! %s', err.message)
|
||||
mainWindow.webContents.send(
|
||||
'update-not-found',
|
||||
isLatest ? 'There is no newer version.' : 'Updater error'
|
||||
)
|
||||
return
|
||||
}
|
||||
if (status) {
|
||||
mainWindow.webContents.send('update-found', 'Update available!')
|
||||
updater.download()
|
||||
updateFound = true
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -63,6 +72,7 @@ updater.on('update-downloaded', info => {
|
||||
if (mainWindow != null) {
|
||||
mainWindow.webContents.send('update-ready', 'Update available!')
|
||||
isUpdateReady = true
|
||||
updateFound = false
|
||||
}
|
||||
})
|
||||
|
||||
@@ -77,6 +87,14 @@ ipc.on('update-app-confirm', function(event, msg) {
|
||||
}
|
||||
})
|
||||
|
||||
ipc.on('update-cancel', () => {
|
||||
updateFound = false
|
||||
})
|
||||
|
||||
ipc.on('update-download-confirm', () => {
|
||||
updater.download()
|
||||
})
|
||||
|
||||
app.on('window-all-closed', function() {
|
||||
app.quit()
|
||||
})
|
||||
@@ -113,7 +131,7 @@ app.on('ready', function() {
|
||||
if (isUpdateReady) {
|
||||
mainWindow.webContents.send('update-ready', 'Update available!')
|
||||
} else {
|
||||
checkUpdate()
|
||||
checkUpdate(msg === 'manual')
|
||||
}
|
||||
})
|
||||
}, 10 * 1000)
|
||||
|
||||
@@ -178,6 +178,18 @@ const file = {
|
||||
mainWindow.webContents.send('list:isMarkdownNote', 'print')
|
||||
mainWindow.webContents.send('print')
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
},
|
||||
{
|
||||
label: 'Update',
|
||||
click() {
|
||||
mainWindow.webContents.send('update')
|
||||
}
|
||||
},
|
||||
{
|
||||
type: 'separator'
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -472,9 +484,21 @@ const help = {
|
||||
]
|
||||
}
|
||||
|
||||
const team = {
|
||||
label: 'For Team',
|
||||
submenu: [
|
||||
{
|
||||
label: 'BoostHub',
|
||||
click: async () => {
|
||||
shell.openExternal('https://boosthub.io/')
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
module.exports =
|
||||
process.platform === 'darwin'
|
||||
? [boost, file, edit, view, window, help]
|
||||
? [boost, file, edit, view, window, team, help]
|
||||
: process.platform === 'win32'
|
||||
? [boost, file, view, help]
|
||||
: [file, view, help]
|
||||
? [boost, file, view, team, help]
|
||||
: [file, view, team, help]
|
||||
|
||||
@@ -202,7 +202,6 @@
|
||||
"Create new folder": "Ordner erstellen",
|
||||
"Folder name": "Ordnername",
|
||||
"Create": "Erstellen",
|
||||
"Untitled": "Neuer Ordner",
|
||||
"Unlink Storage": "Speicherverknüpfung aufheben",
|
||||
"Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.": "Die Verknüpfung des Speichers mit Boostnote wird entfernt. Es werden keine Daten gelöscht. Um die Daten dauerhaft zu löschen musst du den Ordner auf der Festplatte manuell entfernen.",
|
||||
"Empty note": "Leere Notiz",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "boost",
|
||||
"productName": "Boostnote",
|
||||
"version": "0.16.0",
|
||||
"version": "0.16.1",
|
||||
"main": "index.js",
|
||||
"description": "Boostnote",
|
||||
"license": "GPL-3.0",
|
||||
@@ -168,7 +168,7 @@
|
||||
"identity-obj-proxy": "^3.0.0",
|
||||
"jest": "^22.4.3",
|
||||
"jest-localstorage-mock": "^2.2.0",
|
||||
"jsdom": "^9.4.2",
|
||||
"jsdom": "^16.5.0",
|
||||
"json-loader": "^0.5.4",
|
||||
"markdownlint": "^0.11.0",
|
||||
"merge-stream": "^1.0.0",
|
||||
|
||||
62
readme.md
62
readme.md
@@ -1,12 +1,26 @@
|
||||
> [We've launched desktop and mobile app of the new Boost Note now.](https://github.com/BoostIO/BoostNote.next)
|
||||
|
||||
> ### [Boost Note for Teams](https://boosthub.io/)
|
||||
> # New Boost Note app is available!
|
||||
>
|
||||
> We've developed a collaborative workspace app called "Boost Hub" for developer teams.
|
||||
> We've launched a new Boost Note app which supports real-time collaborative writing.
|
||||
>
|
||||
> It's customizable and easy to optimize for your team like rego blocks and even lets you edit documents together in real-time!
|
||||
> And it is open sourced too! Please check it out! https://github.com/BoostIO/BoostNote-App
|
||||
>
|
||||
> ## 📦 Download App
|
||||
>
|
||||
> ### 🖥 Desktop
|
||||
>
|
||||
> - [🌎 Web App (boostnote.io)](https://boostnote.io)
|
||||
> - [🍎 macOS (.dmg)](https://github.com/BoostIO/BoostNote-App/releases/latest/download/boost-note-mac.dmg)
|
||||
> - [:framed_picture: Windows (.exe NSIS)](https://github.com/BoostIO/BoostNote-App/releases/latest/download/boost-note-win.exe)
|
||||
> - [🐧 Linux (.deb)](https://github.com/BoostIO/BoostNote-App/releases/latest/download/boost-note-linux.deb)
|
||||
> - [🐧 Linux (.rpm)](https://github.com/BoostIO/BoostNote-App/releases/latest/download/boost-note-linux.rpm)
|
||||
>
|
||||
> ### 📱 Mobile
|
||||
>
|
||||
> - [🌎 Mobile Web App (m.boostnote.io)](https://m.boostnote.io)
|
||||
> - [🍏 iOS (Apple App Store)](https://apps.apple.com/gb/app/boost-note-mobile/id1576176505)
|
||||
> - [🤖 Android (Google Play Store)](https://play.google.com/store/apps/details?id=com.boostio.boostnote2021)
|
||||
|
||||

|
||||
<h1 align="center">BoostNote-Legacy</h1>
|
||||
|
||||
<h4 align="center">Note-taking app for programmers. </h4>
|
||||
<h5 align="center">Apps available for Mac, Windows and Linux.</h5>
|
||||
@@ -21,42 +35,6 @@
|
||||
|
||||
[Find the latest release of Boostnote here!](https://github.com/BoostIO/boost-releases/releases/)
|
||||
|
||||
## Roadmap
|
||||
|
||||
[Boost Note Roadmap 2020](https://medium.com/boostnote/boost-note-roadmap-2020-9f06a642f5f1)
|
||||
|
||||
## Authors & Maintainers
|
||||
|
||||
- [Rokt33r](https://github.com/rokt33r)
|
||||
- [KZ](https://github.com/kazup01)
|
||||
- [ZeroX-DG](https://github.com/ZeroX-DG)
|
||||
|
||||
## Contributors
|
||||
|
||||
Thank you to all the people who have 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 thanks to the support by our amazing backers.
|
||||
|
||||
Issues on Boostnote can be funded by anyone and the money will be distributed to contributors and maintainers. If you use Boostnote please consider becoming a backer:
|
||||
|
||||
[](https://issuehunt.io/repos/53266139)
|
||||
|
||||
## 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/zt-cun7pas3-WwkaezxHBB1lCbUHrwQLXw)
|
||||
- [Blog](https://medium.com/boostnote)
|
||||
- [Reddit](https://www.reddit.com/r/Boostnote/)
|
||||
|
||||
### Boostnote mobile
|
||||
A community project developing a mobile cross-platform version of boostnote for iOS and Android can be found here: [NoteApp](https://github.com/T0M0F/NoteApp)
|
||||
|
||||
|
||||
#### More Information
|
||||
|
||||
- Website: https://boostnote.io
|
||||
|
||||
@@ -702,14 +702,15 @@ it('should remove the all ":storage" and noteKey references', function() {
|
||||
' </p>\n' +
|
||||
' </body>\n' +
|
||||
'</html>'
|
||||
const actual = systemUnderTest.removeStorageAndNoteReferences(
|
||||
const actual = systemUnderTest.replaceStorageReferences(
|
||||
testInput,
|
||||
noteKey
|
||||
noteKey,
|
||||
systemUnderTest.DESTINATION_FOLDER
|
||||
)
|
||||
expect(actual).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
it('should make sure that "removeStorageAndNoteReferences" works with markdown content as well', function() {
|
||||
it('should make sure that "replaceStorageReferences" works with markdown content as well', function() {
|
||||
const noteKey = 'noteKey'
|
||||
const testInput =
|
||||
'Test input' +
|
||||
@@ -736,9 +737,113 @@ it('should make sure that "removeStorageAndNoteReferences" works with markdown c
|
||||
systemUnderTest.DESTINATION_FOLDER +
|
||||
path.posix.sep +
|
||||
'pdf.pdf)'
|
||||
const actual = systemUnderTest.removeStorageAndNoteReferences(
|
||||
const actual = systemUnderTest.replaceStorageReferences(
|
||||
testInput,
|
||||
noteKey
|
||||
noteKey,
|
||||
systemUnderTest.DESTINATION_FOLDER
|
||||
)
|
||||
expect(actual).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
it('should replace the all ":storage" references', function() {
|
||||
const storageFolder = systemUnderTest.DESTINATION_FOLDER
|
||||
const noteKey = 'noteKey'
|
||||
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) +
|
||||
noteKey +
|
||||
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) +
|
||||
noteKey +
|
||||
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) +
|
||||
noteKey +
|
||||
mdurl.encode(path.sep) +
|
||||
'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
|
||||
' </p>\n' +
|
||||
' </body>\n' +
|
||||
'</html>'
|
||||
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="' +
|
||||
storageFolder +
|
||||
path.sep +
|
||||
'0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
|
||||
' </p>\n' +
|
||||
' <p data-line="4">\n' +
|
||||
' <a href="' +
|
||||
storageFolder +
|
||||
path.sep +
|
||||
'0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
|
||||
' </p>\n' +
|
||||
' <p data-line="6">\n' +
|
||||
' <img src="' +
|
||||
storageFolder +
|
||||
path.sep +
|
||||
'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
|
||||
' </p>\n' +
|
||||
' </body>\n' +
|
||||
'</html>'
|
||||
const actual = systemUnderTest.replaceStorageReferences(
|
||||
testInput,
|
||||
noteKey,
|
||||
systemUnderTest.DESTINATION_FOLDER
|
||||
)
|
||||
expect(actual).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
it('should make sure that "replaceStorageReferences" works with markdown content as well', function() {
|
||||
const noteKey = 'noteKey'
|
||||
const testInput =
|
||||
'Test input' +
|
||||
' \n' +
|
||||
'[pdf](' +
|
||||
systemUnderTest.STORAGE_FOLDER_PLACEHOLDER +
|
||||
path.posix.sep +
|
||||
noteKey +
|
||||
path.posix.sep +
|
||||
'pdf.pdf)'
|
||||
|
||||
const expectedOutput =
|
||||
'Test input' +
|
||||
' \n' +
|
||||
'[pdf](' +
|
||||
systemUnderTest.DESTINATION_FOLDER +
|
||||
path.posix.sep +
|
||||
'pdf.pdf)'
|
||||
const actual = systemUnderTest.replaceStorageReferences(
|
||||
testInput,
|
||||
noteKey,
|
||||
systemUnderTest.DESTINATION_FOLDER
|
||||
)
|
||||
expect(actual).toEqual(expectedOutput)
|
||||
})
|
||||
|
||||
@@ -52,12 +52,20 @@ test.serial('Export a folder', t => {
|
||||
}
|
||||
input2.title = 'input2'
|
||||
|
||||
const config = {
|
||||
export: {
|
||||
metadata: 'DONT_EXPORT',
|
||||
variable: 'boostnote',
|
||||
prefixAttachmentFolder: false
|
||||
}
|
||||
}
|
||||
|
||||
return createNote(storageKey, input1)
|
||||
.then(function() {
|
||||
return createNote(storageKey, input2)
|
||||
})
|
||||
.then(function() {
|
||||
return exportFolder(storageKey, folderKey, 'md', storagePath)
|
||||
return exportFolder(storageKey, folderKey, 'md', storagePath, config)
|
||||
})
|
||||
.then(function assert() {
|
||||
let filePath = path.join(storagePath, 'input1.md')
|
||||
|
||||
@@ -35,7 +35,16 @@ test.serial('Export a storage', t => {
|
||||
acc[folder.key] = folder.name
|
||||
return acc
|
||||
}, {})
|
||||
return exportStorage(storageKey, 'md', exportDir).then(() => {
|
||||
|
||||
const config = {
|
||||
export: {
|
||||
metadata: 'DONT_EXPORT',
|
||||
variable: 'boostnote',
|
||||
prefixAttachmentFolder: false
|
||||
}
|
||||
}
|
||||
|
||||
return exportStorage(storageKey, 'md', exportDir, config).then(() => {
|
||||
notes.forEach(note => {
|
||||
const noteDir = path.join(
|
||||
exportDir,
|
||||
|
||||
546
yarn.lock
546
yarn.lock
@@ -132,13 +132,14 @@
|
||||
resolved "https://registry.yarnpkg.com/JSV/-/JSV-4.0.2.tgz#d077f6825571f82132f9dffaed587b4029feff57"
|
||||
integrity sha1-0Hf2glVx+CEy+d/67Vh7QCn+/1c=
|
||||
|
||||
abab@^1.0.3, abab@^1.0.4:
|
||||
abab@^1.0.4:
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/abab/-/abab-1.0.4.tgz#5faad9c2c07f60dd76770f71cf025b62a63cfd4e"
|
||||
|
||||
abab@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.0.tgz#aba0ab4c5eee2d4c79d3487d85450fb2376ebb0f"
|
||||
abab@^2.0.0, abab@^2.0.3, abab@^2.0.5:
|
||||
version "2.0.6"
|
||||
resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.6.tgz#41b80f2c871d19686216b82309231cfd3cb3d291"
|
||||
integrity sha512-j2afSsaIENvHZN2B8GOpF566vZ5WVk5opAiMTvWgaQT8DkbOqsTfvNAvHoRGU2zzP8cPoqys+xHTRDWW8L+/BA==
|
||||
|
||||
abbrev@1:
|
||||
version "1.1.1"
|
||||
@@ -155,40 +156,49 @@ accessibility-developer-tools@^2.11.0:
|
||||
version "2.12.0"
|
||||
resolved "https://registry.yarnpkg.com/accessibility-developer-tools/-/accessibility-developer-tools-2.12.0.tgz#3da0cce9d6ec6373964b84f35db7cfc3df7ab514"
|
||||
|
||||
acorn-globals@^3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-3.1.0.tgz#fd8270f71fbb4996b004fa880ee5d46573a731bf"
|
||||
dependencies:
|
||||
acorn "^4.0.4"
|
||||
|
||||
acorn-globals@^4.1.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-4.1.0.tgz#ab716025dbe17c54d3ef81d32ece2b2d99fe2538"
|
||||
dependencies:
|
||||
acorn "^5.0.0"
|
||||
|
||||
acorn-globals@^6.0.0:
|
||||
version "6.0.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45"
|
||||
integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg==
|
||||
dependencies:
|
||||
acorn "^7.1.1"
|
||||
acorn-walk "^7.1.1"
|
||||
|
||||
acorn-jsx@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-3.0.1.tgz#afdf9488fb1ecefc8348f6fb22f464e32a58b36b"
|
||||
dependencies:
|
||||
acorn "^3.0.4"
|
||||
|
||||
acorn-walk@^7.1.1:
|
||||
version "7.2.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc"
|
||||
integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==
|
||||
|
||||
acorn@^3.0.0, acorn@^3.0.4:
|
||||
version "3.3.0"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-3.3.0.tgz#45e37fb39e8da3f25baee3ff5369e2bb5f22017a"
|
||||
|
||||
acorn@^4.0.4:
|
||||
version "4.0.13"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-4.0.13.tgz#105495ae5361d697bd195c825192e1ad7f253787"
|
||||
|
||||
acorn@^5.0.0, acorn@^5.3.0, acorn@^5.5.0:
|
||||
version "5.5.3"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.5.3.tgz#f473dd47e0277a08e28e9bec5aeeb04751f0b8c9"
|
||||
|
||||
acorn@^5.5.3:
|
||||
acorn@^5.0.0, acorn@^5.3.0, acorn@^5.5.0, acorn@^5.5.3:
|
||||
version "5.7.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.1.tgz#f095829297706a7c9776958c0afc8930a9b9d9d8"
|
||||
|
||||
acorn@^7.1.1:
|
||||
version "7.4.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.4.1.tgz#feaed255973d2e77555b83dbc08851a6c63520fa"
|
||||
integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==
|
||||
|
||||
acorn@^8.0.5:
|
||||
version "8.7.1"
|
||||
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.1.tgz#0197122c843d1bf6d0a5e83220a788f278f63c30"
|
||||
integrity sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==
|
||||
|
||||
ajv-keywords@^1.0.0:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-1.5.1.tgz#314dd0a4b3368fad3dfcdc54ede6171b886daf3c"
|
||||
@@ -205,7 +215,7 @@ ajv@^4.7.0:
|
||||
co "^4.6.0"
|
||||
json-stable-stringify "^1.0.1"
|
||||
|
||||
ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0:
|
||||
ajv@^5.2.3, ajv@^5.3.0:
|
||||
version "5.5.2"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-5.5.2.tgz#73b5eeca3fab653e3d3f9422b341ad42205dc965"
|
||||
dependencies:
|
||||
@@ -214,6 +224,16 @@ ajv@^5.1.0, ajv@^5.2.3, ajv@^5.3.0:
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.3.0"
|
||||
|
||||
ajv@^6.12.3:
|
||||
version "6.12.6"
|
||||
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
|
||||
integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==
|
||||
dependencies:
|
||||
fast-deep-equal "^3.1.1"
|
||||
fast-json-stable-stringify "^2.0.0"
|
||||
json-schema-traverse "^0.4.1"
|
||||
uri-js "^4.2.2"
|
||||
|
||||
align-text@^0.1.1, align-text@^0.1.3:
|
||||
version "0.1.4"
|
||||
resolved "https://registry.yarnpkg.com/align-text/-/align-text-0.1.4.tgz#0cd90a561093f35d0a99256c22b7069433fad117"
|
||||
@@ -656,9 +676,10 @@ aws-sign2@~0.7.0:
|
||||
version "0.7.0"
|
||||
resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8"
|
||||
|
||||
aws4@^1.6.0:
|
||||
version "1.7.0"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.7.0.tgz#d4d0e9b9dbfca77bf08eeb0a8a471550fe39e289"
|
||||
aws4@^1.8.0:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.11.0.tgz#d61f46d83b2519250e2784daf5b09479a8b41c59"
|
||||
integrity sha512-xh1Rl34h6Fi1DC2WWKfxUTVqRsNnr6LsKz2+hfwDxQJWmrx8+c7ylaqBMcHfl1U1r2dsifOvKX3LQuLNZ+XSvA==
|
||||
|
||||
babel-code-frame@^6.16.0, babel-code-frame@^6.22.0, babel-code-frame@^6.26.0:
|
||||
version "6.26.0"
|
||||
@@ -1420,6 +1441,11 @@ browser-process-hrtime@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-0.1.2.tgz#425d68a58d3447f02a04aa894187fce8af8b7b8e"
|
||||
|
||||
browser-process-hrtime@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626"
|
||||
integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow==
|
||||
|
||||
browser-resolve@^1.11.2:
|
||||
version "1.11.2"
|
||||
resolved "https://registry.yarnpkg.com/browser-resolve/-/browser-resolve-1.11.2.tgz#8ff09b0a2c421718a1051c260b32e48f442938ce"
|
||||
@@ -1960,9 +1986,10 @@ 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:
|
||||
version "1.0.6"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.6.tgz#723e7df6e801ac5613113a7e445a9b69cb632818"
|
||||
combined-stream@^1.0.6, combined-stream@~1.0.6:
|
||||
version "1.0.8"
|
||||
resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f"
|
||||
integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==
|
||||
dependencies:
|
||||
delayed-stream "~1.0.0"
|
||||
|
||||
@@ -2125,7 +2152,7 @@ content-disposition@0.5.2:
|
||||
version "0.5.2"
|
||||
resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.2.tgz#0cf68bb9ddf5f2be7961c3a85178cb85dba78cb4"
|
||||
|
||||
content-type-parser@^1.0.1, content-type-parser@^1.0.2:
|
||||
content-type-parser@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/content-type-parser/-/content-type-parser-1.0.2.tgz#caabe80623e63638b2502fd4c7f12ff4ce2352e7"
|
||||
|
||||
@@ -2356,9 +2383,15 @@ csso@~2.3.1:
|
||||
clap "^1.0.9"
|
||||
source-map "^0.5.3"
|
||||
|
||||
cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
|
||||
version "0.3.2"
|
||||
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.2.tgz#b8036170c79f07a90ff2f16e22284027a243848b"
|
||||
cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0", cssom@~0.3.6:
|
||||
version "0.3.8"
|
||||
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a"
|
||||
integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg==
|
||||
|
||||
cssom@^0.4.4:
|
||||
version "0.4.4"
|
||||
resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10"
|
||||
integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw==
|
||||
|
||||
"cssstyle@>= 0.2.37 < 0.3.0":
|
||||
version "0.2.37"
|
||||
@@ -2366,18 +2399,19 @@ cssom@0.3.x, "cssom@>= 0.3.2 < 0.4.0":
|
||||
dependencies:
|
||||
cssom "0.3.x"
|
||||
|
||||
"cssstyle@>= 0.3.1 < 0.4.0":
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-0.3.1.tgz#6da9b4cff1bc5d716e6e5fe8e04fcb1b50a49adf"
|
||||
dependencies:
|
||||
cssom "0.3.x"
|
||||
|
||||
cssstyle@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-1.0.0.tgz#79b16d51ec5591faec60e688891f15d2a5705129"
|
||||
dependencies:
|
||||
cssom "0.3.x"
|
||||
|
||||
cssstyle@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852"
|
||||
integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A==
|
||||
dependencies:
|
||||
cssom "~0.3.6"
|
||||
|
||||
cuint@^0.2.1:
|
||||
version "0.2.2"
|
||||
resolved "https://registry.yarnpkg.com/cuint/-/cuint-0.2.2.tgz#408086d409550c2631155619e9fa7bcadc3b991b"
|
||||
@@ -2708,6 +2742,15 @@ data-urls@^1.0.0:
|
||||
whatwg-mimetype "^2.0.0"
|
||||
whatwg-url "^6.4.0"
|
||||
|
||||
data-urls@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b"
|
||||
integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ==
|
||||
dependencies:
|
||||
abab "^2.0.3"
|
||||
whatwg-mimetype "^2.3.0"
|
||||
whatwg-url "^8.0.0"
|
||||
|
||||
date-fns@^1.23.0:
|
||||
version "1.29.0"
|
||||
resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-1.29.0.tgz#12e609cdcb935127311d04d33334e2960a2a54e6"
|
||||
@@ -2757,6 +2800,11 @@ decamelize@^1.0.0, decamelize@^1.1.1, decamelize@^1.1.2:
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290"
|
||||
|
||||
decimal.js@^10.2.1:
|
||||
version "10.3.1"
|
||||
resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.3.1.tgz#d8c3a444a9c6774ba60ca6ad7261c3a94fd5e783"
|
||||
integrity sha512-V0pfhfr8suzyPGOx3nmq4aHqabehUZn6Ch9kyFpV79TGDTWFmHqUqXdabR7QHqxzrYolF4+tVmJhUG4OURg5dQ==
|
||||
|
||||
decode-uri-component@^0.2.0:
|
||||
version "0.2.0"
|
||||
resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545"
|
||||
@@ -2948,6 +2996,13 @@ domexception@^1.0.0, domexception@^1.0.1:
|
||||
dependencies:
|
||||
webidl-conversions "^4.0.2"
|
||||
|
||||
domexception@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304"
|
||||
integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg==
|
||||
dependencies:
|
||||
webidl-conversions "^5.0.0"
|
||||
|
||||
domhandler@^2.3.0:
|
||||
version "2.4.2"
|
||||
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
|
||||
@@ -3306,9 +3361,9 @@ escaper@^2.5.3:
|
||||
resolved "https://registry.yarnpkg.com/escaper/-/escaper-2.5.3.tgz#8b8fe90ba364054151ab7eff18b4ce43b1e13ab5"
|
||||
integrity sha512-QGb9sFxBVpbzMggrKTX0ry1oiI4CSDAl9vIL702hzl1jGW8VZs7qfqTRX7WDOjoNDoEVGcEtu1ZOQgReSfT2kQ==
|
||||
|
||||
escodegen@^1.6.1, escodegen@^1.9.0:
|
||||
version "1.9.1"
|
||||
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.9.1.tgz#dbae17ef96c8e4bedb1356f4504fa4cc2f7cb7e2"
|
||||
escodegen@^1.9.0, escodegen@^1.9.1:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.0.tgz#b27a9389481d5bfd5bec76f7bb1eb3f8f4556589"
|
||||
dependencies:
|
||||
esprima "^3.1.3"
|
||||
estraverse "^4.2.0"
|
||||
@@ -3317,12 +3372,13 @@ escodegen@^1.6.1, escodegen@^1.9.0:
|
||||
optionalDependencies:
|
||||
source-map "~0.6.1"
|
||||
|
||||
escodegen@^1.9.1:
|
||||
version "1.11.0"
|
||||
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.11.0.tgz#b27a9389481d5bfd5bec76f7bb1eb3f8f4556589"
|
||||
escodegen@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-2.0.0.tgz#5e32b12833e8aa8fa35e1bf0befa89380484c7dd"
|
||||
integrity sha512-mmHKys/C8BFUGI+MAWNcSYoORYLMdPzjrknd2Vc+bUsjN5bXcr8EhrNB+UTqfL1y3I9c4fw2ihgtMPQLBRiQxw==
|
||||
dependencies:
|
||||
esprima "^3.1.3"
|
||||
estraverse "^4.2.0"
|
||||
esprima "^4.0.1"
|
||||
estraverse "^5.2.0"
|
||||
esutils "^2.0.2"
|
||||
optionator "^0.8.1"
|
||||
optionalDependencies:
|
||||
@@ -3515,6 +3571,11 @@ esprima@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.0.tgz#4499eddcd1110e0b218bacf2fa7f7f59f55ca804"
|
||||
|
||||
esprima@^4.0.1:
|
||||
version "4.0.1"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71"
|
||||
integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==
|
||||
|
||||
"esprima@~ 1.0.2":
|
||||
version "1.0.4"
|
||||
resolved "https://registry.yarnpkg.com/esprima/-/esprima-1.0.4.tgz#9f557e08fc3b4d26ece9dd34f8fbf476b62585ad"
|
||||
@@ -3541,6 +3602,11 @@ estraverse@^4.0.0, estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0:
|
||||
version "4.2.0"
|
||||
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.2.0.tgz#0dee3fed31fcd469618ce7342099fc1afa0bdb13"
|
||||
|
||||
estraverse@^5.2.0:
|
||||
version "5.3.0"
|
||||
resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.3.0.tgz#2eea5290702f26ab8fe5370370ff86c965d21123"
|
||||
integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==
|
||||
|
||||
esutils@^2.0.2:
|
||||
version "2.0.2"
|
||||
resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.2.tgz#0abf4f1caa5bcb1f7a9d8acc6dea4faaa04bac9b"
|
||||
@@ -3707,7 +3773,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
|
||||
assign-symbols "^1.0.0"
|
||||
is-extendable "^1.0.1"
|
||||
|
||||
extend@~3.0.1:
|
||||
extend@~3.0.2:
|
||||
version "3.0.2"
|
||||
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
|
||||
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
|
||||
@@ -3765,6 +3831,11 @@ fast-deep-equal@^1.0.0:
|
||||
version "1.1.0"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-1.1.0.tgz#c053477817c86b51daa853c81e059b733d023614"
|
||||
|
||||
fast-deep-equal@^3.1.1:
|
||||
version "3.1.3"
|
||||
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525"
|
||||
integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==
|
||||
|
||||
fast-diff@^1.1.1:
|
||||
version "1.1.2"
|
||||
resolved "https://registry.yarnpkg.com/fast-diff/-/fast-diff-1.1.2.tgz#4b62c42b8e03de3f848460b639079920695d0154"
|
||||
@@ -4022,12 +4093,13 @@ 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@~2.3.1:
|
||||
version "2.3.2"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.2.tgz#4970498be604c20c005d4f5c23aecd21d6b49099"
|
||||
form-data@~2.3.2:
|
||||
version "2.3.3"
|
||||
resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6"
|
||||
integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==
|
||||
dependencies:
|
||||
asynckit "^0.4.0"
|
||||
combined-stream "1.0.6"
|
||||
combined-stream "^1.0.6"
|
||||
mime-types "^2.1.12"
|
||||
|
||||
forwarded@~0.1.2:
|
||||
@@ -4475,11 +4547,12 @@ har-schema@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92"
|
||||
|
||||
har-validator@~5.0.3:
|
||||
version "5.0.3"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.0.3.tgz#ba402c266194f15956ef15e0fcf242993f6a7dfd"
|
||||
har-validator@~5.1.3:
|
||||
version "5.1.5"
|
||||
resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.5.tgz#1f0803b9f8cb20c0fa13822df1ecddb36bde1efd"
|
||||
integrity sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==
|
||||
dependencies:
|
||||
ajv "^5.1.0"
|
||||
ajv "^6.12.3"
|
||||
har-schema "^2.0.0"
|
||||
|
||||
harmony-reflect@^1.4.6:
|
||||
@@ -4612,12 +4685,19 @@ html-comment-regex@^1.1.0:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/html-comment-regex/-/html-comment-regex-1.1.1.tgz#668b93776eaae55ebde8f3ad464b307a4963625e"
|
||||
|
||||
html-encoding-sniffer@^1.0.1, html-encoding-sniffer@^1.0.2:
|
||||
html-encoding-sniffer@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-1.0.2.tgz#e70d84b94da53aa375e11fe3a351be6642ca46f8"
|
||||
dependencies:
|
||||
whatwg-encoding "^1.0.1"
|
||||
|
||||
html-encoding-sniffer@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3"
|
||||
integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ==
|
||||
dependencies:
|
||||
whatwg-encoding "^1.0.5"
|
||||
|
||||
html-minifier@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/html-minifier/-/html-minifier-4.0.0.tgz#cca9aad8bce1175e02e17a8c33e46d8988889f56"
|
||||
@@ -4748,7 +4828,7 @@ 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.17:
|
||||
iconv-lite@0.4.24, iconv-lite@^0.4.17:
|
||||
version "0.4.24"
|
||||
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
|
||||
integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==
|
||||
@@ -5179,6 +5259,11 @@ is-posix-bracket@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz#3334dc79774368e92f016e6fbc0a88f5cd6e6bc4"
|
||||
|
||||
is-potential-custom-element-name@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz#171ed6f19e3ac554394edf78caa05784a45bebb5"
|
||||
integrity sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==
|
||||
|
||||
is-primitive@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575"
|
||||
@@ -5712,38 +5797,7 @@ jsdom@11.6.2:
|
||||
ws "^4.0.0"
|
||||
xml-name-validator "^3.0.0"
|
||||
|
||||
jsdom@^11.5.1:
|
||||
version "11.11.0"
|
||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.11.0.tgz#df486efad41aee96c59ad7a190e2449c7eb1110e"
|
||||
dependencies:
|
||||
abab "^1.0.4"
|
||||
acorn "^5.3.0"
|
||||
acorn-globals "^4.1.0"
|
||||
array-equal "^1.0.0"
|
||||
cssom ">= 0.3.2 < 0.4.0"
|
||||
cssstyle ">= 0.3.1 < 0.4.0"
|
||||
data-urls "^1.0.0"
|
||||
domexception "^1.0.0"
|
||||
escodegen "^1.9.0"
|
||||
html-encoding-sniffer "^1.0.2"
|
||||
left-pad "^1.2.0"
|
||||
nwsapi "^2.0.0"
|
||||
parse5 "4.0.0"
|
||||
pn "^1.1.0"
|
||||
request "^2.83.0"
|
||||
request-promise-native "^1.0.5"
|
||||
sax "^1.2.4"
|
||||
symbol-tree "^3.2.2"
|
||||
tough-cookie "^2.3.3"
|
||||
w3c-hr-time "^1.0.1"
|
||||
webidl-conversions "^4.0.2"
|
||||
whatwg-encoding "^1.0.3"
|
||||
whatwg-mimetype "^2.1.0"
|
||||
whatwg-url "^6.4.1"
|
||||
ws "^4.0.0"
|
||||
xml-name-validator "^3.0.0"
|
||||
|
||||
jsdom@^11.9.0:
|
||||
jsdom@^11.5.1, jsdom@^11.9.0:
|
||||
version "11.12.0"
|
||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-11.12.0.tgz#1a80d40ddd378a1de59656e9e6dc5a3ba8657bc8"
|
||||
dependencies:
|
||||
@@ -5774,29 +5828,37 @@ jsdom@^11.9.0:
|
||||
ws "^5.2.0"
|
||||
xml-name-validator "^3.0.0"
|
||||
|
||||
jsdom@^9.4.2:
|
||||
version "9.12.0"
|
||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-9.12.0.tgz#e8c546fffcb06c00d4833ca84410fed7f8a097d4"
|
||||
jsdom@^16.5.0:
|
||||
version "16.5.0"
|
||||
resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.5.0.tgz#9e453505600cc5a70b385750d35256f380730cc4"
|
||||
integrity sha512-QxZH0nmDTnTTVI0YDm4RUlaUPl5dcyn62G5TMDNfMmTW+J1u1v9gCR8WR+WZ6UghAa7nKJjDOFaI00eMMWvJFQ==
|
||||
dependencies:
|
||||
abab "^1.0.3"
|
||||
acorn "^4.0.4"
|
||||
acorn-globals "^3.1.0"
|
||||
array-equal "^1.0.0"
|
||||
content-type-parser "^1.0.1"
|
||||
cssom ">= 0.3.2 < 0.4.0"
|
||||
cssstyle ">= 0.2.37 < 0.3.0"
|
||||
escodegen "^1.6.1"
|
||||
html-encoding-sniffer "^1.0.1"
|
||||
nwmatcher ">= 1.3.9 < 2.0.0"
|
||||
parse5 "^1.5.1"
|
||||
request "^2.79.0"
|
||||
sax "^1.2.1"
|
||||
symbol-tree "^3.2.1"
|
||||
tough-cookie "^2.3.2"
|
||||
webidl-conversions "^4.0.0"
|
||||
whatwg-encoding "^1.0.1"
|
||||
whatwg-url "^4.3.0"
|
||||
xml-name-validator "^2.0.1"
|
||||
abab "^2.0.5"
|
||||
acorn "^8.0.5"
|
||||
acorn-globals "^6.0.0"
|
||||
cssom "^0.4.4"
|
||||
cssstyle "^2.3.0"
|
||||
data-urls "^2.0.0"
|
||||
decimal.js "^10.2.1"
|
||||
domexception "^2.0.1"
|
||||
escodegen "^2.0.0"
|
||||
html-encoding-sniffer "^2.0.1"
|
||||
is-potential-custom-element-name "^1.0.0"
|
||||
nwsapi "^2.2.0"
|
||||
parse5 "6.0.1"
|
||||
request "^2.88.2"
|
||||
request-promise-native "^1.0.9"
|
||||
saxes "^5.0.1"
|
||||
symbol-tree "^3.2.4"
|
||||
tough-cookie "^4.0.0"
|
||||
w3c-hr-time "^1.0.2"
|
||||
w3c-xmlserializer "^2.0.0"
|
||||
webidl-conversions "^6.1.0"
|
||||
whatwg-encoding "^1.0.5"
|
||||
whatwg-mimetype "^2.3.0"
|
||||
whatwg-url "^8.0.0"
|
||||
ws "^7.4.4"
|
||||
xml-name-validator "^3.0.0"
|
||||
|
||||
jsesc@^1.3.0:
|
||||
version "1.3.0"
|
||||
@@ -5818,6 +5880,11 @@ json-schema-traverse@^0.3.0:
|
||||
version "0.3.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz#349a6d44c53a51de89b40805c5d5e59b417d3340"
|
||||
|
||||
json-schema-traverse@^0.4.1:
|
||||
version "0.4.1"
|
||||
resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660"
|
||||
integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==
|
||||
|
||||
json-schema@0.2.3:
|
||||
version "0.2.3"
|
||||
resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13"
|
||||
@@ -6173,11 +6240,16 @@ lodash.uniq@^4.5.0:
|
||||
version "4.5.0"
|
||||
resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773"
|
||||
|
||||
lodash@^4.0.0, lodash@^4.0.1, lodash@^4.12.0, lodash@^4.13.0, lodash@^4.13.1, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.2, lodash@^4.17.4, lodash@^4.17.5, lodash@^4.2.0, lodash@^4.2.1, lodash@^4.3.0, lodash@^4.5.1, lodash@^4.6.1:
|
||||
lodash@^4.0.0, lodash@^4.0.1, lodash@^4.12.0, lodash@^4.13.0, lodash@^4.16.6, lodash@^4.17.10, lodash@^4.17.15, lodash@^4.17.19, 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.19"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.19.tgz#e48ddedbe30b3321783c5b4301fbd353bc1e4a4b"
|
||||
integrity sha512-JNvd8XER9GQX0v2qJgsaN/mzFCNA5BRe/j8JN9d+tWyGLSodKQHKFicdwNYzWwI3wjRnaKPsGj1XkBjx/F96DQ==
|
||||
|
||||
lodash@^4.7.0:
|
||||
version "4.17.21"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
|
||||
integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
|
||||
|
||||
lodash@~0.9.2:
|
||||
version "0.9.2"
|
||||
resolved "https://registry.yarnpkg.com/lodash/-/lodash-0.9.2.tgz#8f3499c5245d346d682e5b0d3b40767e09f1a92c"
|
||||
@@ -6517,6 +6589,11 @@ micromatch@^3.1.4, micromatch@^3.1.8:
|
||||
snapdragon "^0.8.1"
|
||||
to-regex "^3.0.2"
|
||||
|
||||
mime-db@1.52.0:
|
||||
version "1.52.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.52.0.tgz#bbabcdc02859f4987301c856e3387ce5ec43bf70"
|
||||
integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==
|
||||
|
||||
"mime-db@>= 1.33.0 < 2", mime-db@~1.33.0:
|
||||
version "1.33.0"
|
||||
resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.33.0.tgz#a3492050a5cb9b63450541e39d9788d2272783db"
|
||||
@@ -6527,6 +6604,13 @@ mime-types@^2.1.12, mime-types@~2.1.17, mime-types@~2.1.18:
|
||||
dependencies:
|
||||
mime-db "~1.33.0"
|
||||
|
||||
mime-types@~2.1.19:
|
||||
version "2.1.35"
|
||||
resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.35.tgz#381a871b62a734450660ae3deee44813f70d959a"
|
||||
integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==
|
||||
dependencies:
|
||||
mime-db "1.52.0"
|
||||
|
||||
mime@1.4.1:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/mime/-/mime-1.4.1.tgz#121f9ebc49e3766f311a76e1fa1c8003c4b03aa6"
|
||||
@@ -6938,21 +7022,19 @@ number-is-nan@^1.0.0:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d"
|
||||
|
||||
"nwmatcher@>= 1.3.9 < 2.0.0", nwmatcher@^1.4.3:
|
||||
nwmatcher@^1.4.3:
|
||||
version "1.4.4"
|
||||
resolved "https://registry.yarnpkg.com/nwmatcher/-/nwmatcher-1.4.4.tgz#2285631f34a95f0d0395cd900c96ed39b58f346e"
|
||||
|
||||
nwsapi@^2.0.0:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.0.1.tgz#a50d59a2dcb14b6931401171713ced2d0eb3468f"
|
||||
nwsapi@^2.0.7, nwsapi@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7"
|
||||
integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ==
|
||||
|
||||
nwsapi@^2.0.7:
|
||||
version "2.0.8"
|
||||
resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.0.8.tgz#e3603579b7e162b3dbedae4fb24e46f771d8fa24"
|
||||
|
||||
oauth-sign@~0.8.2:
|
||||
version "0.8.2"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.8.2.tgz#46a6ab7f0aead8deae9ec0565780b7d4efeb9d43"
|
||||
oauth-sign@~0.9.0:
|
||||
version "0.9.0"
|
||||
resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455"
|
||||
integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==
|
||||
|
||||
object-assign@^3.0.0:
|
||||
version "3.0.0"
|
||||
@@ -7230,9 +7312,10 @@ parse5@4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-4.0.0.tgz#6d78656e3da8d78b4ec0b906f7c08ef1dfe3f608"
|
||||
|
||||
parse5@^1.5.1:
|
||||
version "1.5.1"
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-1.5.1.tgz#9b7f3b0de32be78dc2401b17573ccaf0f6f59d94"
|
||||
parse5@6.0.1:
|
||||
version "6.0.1"
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
|
||||
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
|
||||
|
||||
parseurl@~1.3.2:
|
||||
version "1.3.2"
|
||||
@@ -7784,19 +7867,20 @@ pseudomap@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3"
|
||||
|
||||
psl@^1.1.24:
|
||||
version "1.1.29"
|
||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.1.29.tgz#60f580d360170bb722a797cc704411e6da850c67"
|
||||
psl@^1.1.28, psl@^1.1.33:
|
||||
version "1.8.0"
|
||||
resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24"
|
||||
integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ==
|
||||
|
||||
punycode@1.3.2:
|
||||
version "1.3.2"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d"
|
||||
|
||||
punycode@^1.2.4, punycode@^1.4.1:
|
||||
punycode@^1.2.4:
|
||||
version "1.4.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.4.1.tgz#c0d5a63b2718800ad8e1eb0fa5269c84dd41845e"
|
||||
|
||||
punycode@^2.1.0:
|
||||
punycode@^2.1.0, punycode@^2.1.1:
|
||||
version "2.1.1"
|
||||
resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec"
|
||||
|
||||
@@ -7813,9 +7897,10 @@ qs@6.5.1:
|
||||
version "6.5.1"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.1.tgz#349cdf6eef89ec45c12d7d5eb3fc0c870343a6d8"
|
||||
|
||||
qs@~6.5.1:
|
||||
version "6.5.2"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36"
|
||||
qs@~6.5.2:
|
||||
version "6.5.3"
|
||||
resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.3.tgz#3aeeffc91967ef6e35c0e488ef46fb296ab76aad"
|
||||
integrity sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==
|
||||
|
||||
query-string@^4.1.0:
|
||||
version "4.3.4"
|
||||
@@ -8425,44 +8510,47 @@ repeating@^2.0.0:
|
||||
dependencies:
|
||||
is-finite "^1.0.0"
|
||||
|
||||
request-promise-core@1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.1.tgz#3eee00b2c5aa83239cfb04c5700da36f81cd08b6"
|
||||
request-promise-core@1.1.4:
|
||||
version "1.1.4"
|
||||
resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.4.tgz#3eedd4223208d419867b78ce815167d10593a22f"
|
||||
integrity sha512-TTbAfBBRdWD7aNNOoVOBH4pN/KigV6LyapYNNlAPA8JwbovRti1E88m3sYAwsLi5ryhPKsE9APwnjFTgdUjTpw==
|
||||
dependencies:
|
||||
lodash "^4.13.1"
|
||||
lodash "^4.17.19"
|
||||
|
||||
request-promise-native@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.5.tgz#5281770f68e0c9719e5163fd3fab482215f4fda5"
|
||||
request-promise-native@^1.0.5, request-promise-native@^1.0.9:
|
||||
version "1.0.9"
|
||||
resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.9.tgz#e407120526a5efdc9a39b28a5679bf47b9d9dc28"
|
||||
integrity sha512-wcW+sIUiWnKgNY0dqCpOZkUbF/I+YPi+f09JZIDa39Ec+q82CpSYniDp+ISgTTbKmnpJWASeJBPZmoxH84wt3g==
|
||||
dependencies:
|
||||
request-promise-core "1.1.1"
|
||||
stealthy-require "^1.1.0"
|
||||
tough-cookie ">=2.3.3"
|
||||
request-promise-core "1.1.4"
|
||||
stealthy-require "^1.1.1"
|
||||
tough-cookie "^2.3.3"
|
||||
|
||||
request@^2.45.0, request@^2.79.0, request@^2.83.0, request@^2.87.0:
|
||||
version "2.87.0"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.87.0.tgz#32f00235cd08d482b4d0d68db93a829c0ed5756e"
|
||||
request@^2.45.0, request@^2.79.0, request@^2.83.0, request@^2.87.0, request@^2.88.2:
|
||||
version "2.88.2"
|
||||
resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3"
|
||||
integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==
|
||||
dependencies:
|
||||
aws-sign2 "~0.7.0"
|
||||
aws4 "^1.6.0"
|
||||
aws4 "^1.8.0"
|
||||
caseless "~0.12.0"
|
||||
combined-stream "~1.0.5"
|
||||
extend "~3.0.1"
|
||||
combined-stream "~1.0.6"
|
||||
extend "~3.0.2"
|
||||
forever-agent "~0.6.1"
|
||||
form-data "~2.3.1"
|
||||
har-validator "~5.0.3"
|
||||
form-data "~2.3.2"
|
||||
har-validator "~5.1.3"
|
||||
http-signature "~1.2.0"
|
||||
is-typedarray "~1.0.0"
|
||||
isstream "~0.1.2"
|
||||
json-stringify-safe "~5.0.1"
|
||||
mime-types "~2.1.17"
|
||||
oauth-sign "~0.8.2"
|
||||
mime-types "~2.1.19"
|
||||
oauth-sign "~0.9.0"
|
||||
performance-now "^2.1.0"
|
||||
qs "~6.5.1"
|
||||
safe-buffer "^5.1.1"
|
||||
tough-cookie "~2.3.3"
|
||||
qs "~6.5.2"
|
||||
safe-buffer "^5.1.2"
|
||||
tough-cookie "~2.5.0"
|
||||
tunnel-agent "^0.6.0"
|
||||
uuid "^3.1.0"
|
||||
uuid "^3.3.2"
|
||||
|
||||
require-directory@^2.1.1:
|
||||
version "2.1.1"
|
||||
@@ -8679,10 +8767,17 @@ sax@1.2.1:
|
||||
version "1.2.1"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.1.tgz#7b8e656190b228e81a66aea748480d828cd2d37a"
|
||||
|
||||
sax@>=0.6.0, sax@^1.2.1, sax@^1.2.4, sax@~1.2.1:
|
||||
sax@>=0.6.0, sax@^1.2.4, sax@~1.2.1:
|
||||
version "1.2.4"
|
||||
resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9"
|
||||
|
||||
saxes@^5.0.1:
|
||||
version "5.0.1"
|
||||
resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d"
|
||||
integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw==
|
||||
dependencies:
|
||||
xmlchars "^2.2.0"
|
||||
|
||||
scheduler@^0.13.6:
|
||||
version "0.13.6"
|
||||
resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.13.6.tgz#466a4ec332467b31a91b9bf74e5347072e4cd889"
|
||||
@@ -9142,7 +9237,7 @@ statuses@~1.4.0:
|
||||
version "1.4.0"
|
||||
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.4.0.tgz#bb73d446da2796106efcc1b601a253d6c46bd087"
|
||||
|
||||
stealthy-require@^1.1.0:
|
||||
stealthy-require@^1.1.1:
|
||||
version "1.1.1"
|
||||
resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b"
|
||||
|
||||
@@ -9386,9 +9481,10 @@ symbol-observable@^1.0.2, symbol-observable@^1.0.3, symbol-observable@^1.0.4, sy
|
||||
version "1.2.0"
|
||||
resolved "https://registry.yarnpkg.com/symbol-observable/-/symbol-observable-1.2.0.tgz#c22688aed4eab3cdc2dfeacbb561660560a00804"
|
||||
|
||||
symbol-tree@^3.2.1, symbol-tree@^3.2.2:
|
||||
version "3.2.2"
|
||||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.2.tgz#ae27db38f660a7ae2e1c3b7d1bc290819b8519e6"
|
||||
symbol-tree@^3.2.2, symbol-tree@^3.2.4:
|
||||
version "3.2.4"
|
||||
resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2"
|
||||
integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==
|
||||
|
||||
table@4.0.2:
|
||||
version "4.0.2"
|
||||
@@ -9588,18 +9684,22 @@ touch@0.0.3:
|
||||
dependencies:
|
||||
nopt "~1.0.10"
|
||||
|
||||
tough-cookie@>=2.3.3, tough-cookie@^2.3.2, tough-cookie@^2.3.3, tough-cookie@~2.3.3:
|
||||
version "2.3.4"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.3.4.tgz#ec60cee38ac675063ffc97a5c18970578ee83655"
|
||||
tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@~2.5.0:
|
||||
version "2.5.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2"
|
||||
integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==
|
||||
dependencies:
|
||||
punycode "^1.4.1"
|
||||
psl "^1.1.28"
|
||||
punycode "^2.1.1"
|
||||
|
||||
tough-cookie@^2.3.4:
|
||||
version "2.4.3"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.4.3.tgz#53f36da3f47783b0925afa06ff9f3b165280f781"
|
||||
tough-cookie@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-4.0.0.tgz#d822234eeca882f991f0f908824ad2622ddbece4"
|
||||
integrity sha512-tHdtEpQCMrc1YLrMaqXXcj6AxhYi/xgit6mZu1+EDWUn+qhUf8wMQoFIy9NXuq23zAwtcB0t/MjACGR18pcRbg==
|
||||
dependencies:
|
||||
psl "^1.1.24"
|
||||
punycode "^1.4.1"
|
||||
psl "^1.1.33"
|
||||
punycode "^2.1.1"
|
||||
universalify "^0.1.2"
|
||||
|
||||
tr46@^1.0.1:
|
||||
version "1.0.1"
|
||||
@@ -9607,9 +9707,12 @@ tr46@^1.0.1:
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
tr46@~0.0.3:
|
||||
version "0.0.3"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
|
||||
tr46@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240"
|
||||
integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==
|
||||
dependencies:
|
||||
punycode "^2.1.1"
|
||||
|
||||
"traverse@>=0.3.0 <0.4":
|
||||
version "0.3.9"
|
||||
@@ -9826,6 +9929,11 @@ universalify@^0.1.0:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.1.tgz#fa71badd4437af4c148841e3b3b165f9e9e590b7"
|
||||
|
||||
universalify@^0.1.2:
|
||||
version "0.1.2"
|
||||
resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66"
|
||||
integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==
|
||||
|
||||
"unorm@>= 1.0.0":
|
||||
version "1.6.0"
|
||||
resolved "https://registry.npmjs.org/unorm/-/unorm-1.6.0.tgz#029b289661fba714f1a9af439eb51d9b16c205af"
|
||||
@@ -9870,6 +9978,13 @@ upper-case@^1.1.1:
|
||||
resolved "https://registry.yarnpkg.com/upper-case/-/upper-case-1.1.3.tgz#f6b4501c2ec4cdd26ba78be7222961de77621598"
|
||||
integrity sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg=
|
||||
|
||||
uri-js@^4.2.2:
|
||||
version "4.4.1"
|
||||
resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.4.1.tgz#9b1a52595225859e55f669d928f88c6c57f2a77e"
|
||||
integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==
|
||||
dependencies:
|
||||
punycode "^2.1.0"
|
||||
|
||||
urix@^0.1.0:
|
||||
version "0.1.0"
|
||||
resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72"
|
||||
@@ -9950,10 +10065,15 @@ uuid@3.1.0:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"
|
||||
|
||||
uuid@^3.0.1, uuid@^3.1.0, uuid@^3.2.1:
|
||||
uuid@^3.0.1, uuid@^3.2.1:
|
||||
version "3.2.1"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.2.1.tgz#12c528bb9d58d0b9265d9a2f6f0fe8be17ff1f14"
|
||||
|
||||
uuid@^3.3.2:
|
||||
version "3.4.0"
|
||||
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee"
|
||||
integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==
|
||||
|
||||
validate-npm-package-license@^3.0.1:
|
||||
version "3.0.3"
|
||||
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.3.tgz#81643bcbef1bdfecd4623793dc4648948ba98338"
|
||||
@@ -9988,11 +10108,19 @@ vm-browserify@0.0.4:
|
||||
dependencies:
|
||||
indexof "0.0.1"
|
||||
|
||||
w3c-hr-time@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.1.tgz#82ac2bff63d950ea9e3189a58a65625fedf19045"
|
||||
w3c-hr-time@^1.0.1, w3c-hr-time@^1.0.2:
|
||||
version "1.0.2"
|
||||
resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd"
|
||||
integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ==
|
||||
dependencies:
|
||||
browser-process-hrtime "^0.1.2"
|
||||
browser-process-hrtime "^1.0.0"
|
||||
|
||||
w3c-xmlserializer@^2.0.0:
|
||||
version "2.0.0"
|
||||
resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a"
|
||||
integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA==
|
||||
dependencies:
|
||||
xml-name-validator "^3.0.0"
|
||||
|
||||
walker@~1.0.5:
|
||||
version "1.0.7"
|
||||
@@ -10015,14 +10143,20 @@ watchpack@^0.2.1:
|
||||
chokidar "^1.0.0"
|
||||
graceful-fs "^4.1.2"
|
||||
|
||||
webidl-conversions@^3.0.0:
|
||||
version "3.0.1"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
|
||||
|
||||
webidl-conversions@^4.0.0, webidl-conversions@^4.0.2:
|
||||
webidl-conversions@^4.0.2:
|
||||
version "4.0.2"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
|
||||
|
||||
webidl-conversions@^5.0.0:
|
||||
version "5.0.0"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff"
|
||||
integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA==
|
||||
|
||||
webidl-conversions@^6.1.0:
|
||||
version "6.1.0"
|
||||
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514"
|
||||
integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==
|
||||
|
||||
webpack-core@~0.6.9:
|
||||
version "0.6.9"
|
||||
resolved "https://registry.yarnpkg.com/webpack-core/-/webpack-core-0.6.9.tgz#fc571588c8558da77be9efb6debdc5a3b172bdc2"
|
||||
@@ -10094,26 +10228,21 @@ well-known-symbols@^1.0.0:
|
||||
version "1.0.0"
|
||||
resolved "https://registry.yarnpkg.com/well-known-symbols/-/well-known-symbols-1.0.0.tgz#73c78ae81a7726a8fa598e2880801c8b16225518"
|
||||
|
||||
whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3:
|
||||
version "1.0.3"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.3.tgz#57c235bc8657e914d24e1a397d3c82daee0a6ba3"
|
||||
whatwg-encoding@^1.0.1, whatwg-encoding@^1.0.3, whatwg-encoding@^1.0.5:
|
||||
version "1.0.5"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0"
|
||||
integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw==
|
||||
dependencies:
|
||||
iconv-lite "0.4.19"
|
||||
iconv-lite "0.4.24"
|
||||
|
||||
whatwg-fetch@>=0.10.0:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-fetch/-/whatwg-fetch-2.0.4.tgz#dde6a5df315f9d39991aa17621853d720b85566f"
|
||||
|
||||
whatwg-mimetype@^2.0.0, whatwg-mimetype@^2.1.0:
|
||||
version "2.1.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.1.0.tgz#f0f21d76cbba72362eb609dbed2a30cd17fcc7d4"
|
||||
|
||||
whatwg-url@^4.3.0:
|
||||
version "4.8.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-4.8.0.tgz#d2981aa9148c1e00a41c5a6131166ab4683bbcc0"
|
||||
dependencies:
|
||||
tr46 "~0.0.3"
|
||||
webidl-conversions "^3.0.0"
|
||||
whatwg-mimetype@^2.0.0, whatwg-mimetype@^2.1.0, whatwg-mimetype@^2.3.0:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf"
|
||||
integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g==
|
||||
|
||||
whatwg-url@^6.4.0, whatwg-url@^6.4.1:
|
||||
version "6.4.1"
|
||||
@@ -10123,6 +10252,15 @@ whatwg-url@^6.4.0, whatwg-url@^6.4.1:
|
||||
tr46 "^1.0.1"
|
||||
webidl-conversions "^4.0.2"
|
||||
|
||||
whatwg-url@^8.0.0:
|
||||
version "8.7.0"
|
||||
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77"
|
||||
integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg==
|
||||
dependencies:
|
||||
lodash "^4.7.0"
|
||||
tr46 "^2.1.0"
|
||||
webidl-conversions "^6.1.0"
|
||||
|
||||
when@~3.6.x:
|
||||
version "3.6.4"
|
||||
resolved "https://registry.yarnpkg.com/when/-/when-3.6.4.tgz#473b517ec159e2b85005497a13983f095412e34e"
|
||||
@@ -10252,14 +10390,15 @@ ws@^5.2.0:
|
||||
dependencies:
|
||||
async-limiter "~1.0.0"
|
||||
|
||||
ws@^7.4.4:
|
||||
version "7.5.8"
|
||||
resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.8.tgz#ac2729881ab9e7cbaf8787fe3469a48c5c7f636a"
|
||||
integrity sha512-ri1Id1WinAX5Jqn9HejiGb8crfRio0Qgu8+MtL36rlTA6RLsMdWt1Az/19A2Qij6uSHUMphEFaTKa4WG+UNHNw==
|
||||
|
||||
xdg-basedir@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"
|
||||
|
||||
xml-name-validator@^2.0.1:
|
||||
version "2.0.1"
|
||||
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-2.0.1.tgz#4d8b8f1eccd3419aa362061becef515e1e559635"
|
||||
|
||||
xml-name-validator@^3.0.0:
|
||||
version "3.0.0"
|
||||
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"
|
||||
@@ -10281,6 +10420,11 @@ xmlbuilder@^4.1.0:
|
||||
dependencies:
|
||||
lodash "^4.0.0"
|
||||
|
||||
xmlchars@^2.2.0:
|
||||
version "2.2.0"
|
||||
resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb"
|
||||
integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==
|
||||
|
||||
xmldom@0.1.x:
|
||||
version "0.1.27"
|
||||
resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.27.tgz#d501f97b3bdb403af8ef9ecc20573187aadac0e9"
|
||||
|
||||
Reference in New Issue
Block a user