Merge branch 'master' into text-expansion-support
@@ -3,10 +3,7 @@ import React from 'react'
|
|||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import CodeMirror from 'codemirror'
|
import CodeMirror from 'codemirror'
|
||||||
import 'codemirror-mode-elixir'
|
import 'codemirror-mode-elixir'
|
||||||
import path from 'path'
|
import attachmentManagement from 'browser/main/lib/dataApi/attachmentManagement'
|
||||||
import copyImage from 'browser/main/lib/dataApi/copyImage'
|
|
||||||
import { findStorage } from 'browser/lib/findStorage'
|
|
||||||
import fs from 'fs'
|
|
||||||
import eventEmitter from 'browser/main/lib/eventEmitter'
|
import eventEmitter from 'browser/main/lib/eventEmitter'
|
||||||
import iconv from 'iconv-lite'
|
import iconv from 'iconv-lite'
|
||||||
import crypto from 'crypto'
|
import crypto from 'crypto'
|
||||||
@@ -354,23 +351,13 @@ export default class CodeEditor extends React.Component {
|
|||||||
this.editor.setCursor(cursor)
|
this.editor.setCursor(cursor)
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDropImage (e) {
|
handleDropImage (dropEvent) {
|
||||||
e.preventDefault()
|
dropEvent.preventDefault()
|
||||||
const ValidImageTypes = ['image/gif', 'image/jpeg', 'image/png']
|
const {storageKey, noteKey} = this.props
|
||||||
|
attachmentManagement.handleAttachmentDrop(this, storageKey, noteKey, dropEvent)
|
||||||
const file = e.dataTransfer.files[0]
|
|
||||||
const filePath = file.path
|
|
||||||
const filename = path.basename(filePath)
|
|
||||||
const fileType = file['type']
|
|
||||||
|
|
||||||
copyImage(filePath, this.props.storageKey).then((imagePath) => {
|
|
||||||
var showPreview = ValidImageTypes.indexOf(fileType) > 0
|
|
||||||
const imageMd = `${showPreview ? '!' : ''}[${filename}](${path.join('/:storage', imagePath)})`
|
|
||||||
this.insertImageMd(imageMd)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
insertImageMd (imageMd) {
|
insertAttachmentMd (imageMd) {
|
||||||
this.editor.replaceSelection(imageMd)
|
this.editor.replaceSelection(imageMd)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -396,24 +383,8 @@ export default class CodeEditor extends React.Component {
|
|||||||
return prevChar === '](' && nextChar === ')'
|
return prevChar === '](' && nextChar === ')'
|
||||||
}
|
}
|
||||||
if (dataTransferItem.type.match('image')) {
|
if (dataTransferItem.type.match('image')) {
|
||||||
const blob = dataTransferItem.getAsFile()
|
const {storageKey, noteKey} = this.props
|
||||||
const reader = new FileReader()
|
attachmentManagement.handlePastImageEvent(this, storageKey, noteKey, dataTransferItem)
|
||||||
let base64data
|
|
||||||
|
|
||||||
reader.readAsDataURL(blob)
|
|
||||||
reader.onloadend = () => {
|
|
||||||
base64data = reader.result.replace(/^data:image\/png;base64,/, '')
|
|
||||||
base64data += base64data.replace('+', ' ')
|
|
||||||
const binaryData = new Buffer(base64data, 'base64').toString('binary')
|
|
||||||
const imageName = Math.random().toString(36).slice(-16)
|
|
||||||
const storagePath = findStorage(this.props.storageKey).path
|
|
||||||
const imageDir = path.join(storagePath, 'images')
|
|
||||||
if (!fs.existsSync(imageDir)) fs.mkdirSync(imageDir)
|
|
||||||
const imagePath = path.join(imageDir, `${imageName}.png`)
|
|
||||||
fs.writeFile(imagePath, binaryData, 'binary')
|
|
||||||
const imageMd = `})`
|
|
||||||
this.insertImageMd(imageMd)
|
|
||||||
}
|
|
||||||
} else if (this.props.fetchUrlTitle && isURL(pastedTxt) && !isInLinkTag(editor)) {
|
} else if (this.props.fetchUrlTitle && isURL(pastedTxt) && !isInLinkTag(editor)) {
|
||||||
this.handlePasteUrl(e, editor, pastedTxt)
|
this.handlePasteUrl(e, editor, pastedTxt)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,7 +223,7 @@ class MarkdownEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { className, value, config, storageKey } = this.props
|
const {className, value, config, storageKey, noteKey} = this.props
|
||||||
|
|
||||||
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
||||||
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
||||||
@@ -263,6 +263,7 @@ class MarkdownEditor extends React.Component {
|
|||||||
displayLineNumbers={config.editor.displayLineNumbers}
|
displayLineNumbers={config.editor.displayLineNumbers}
|
||||||
scrollPastEnd={config.editor.scrollPastEnd}
|
scrollPastEnd={config.editor.scrollPastEnd}
|
||||||
storageKey={storageKey}
|
storageKey={storageKey}
|
||||||
|
noteKey={noteKey}
|
||||||
fetchUrlTitle={config.editor.fetchUrlTitle}
|
fetchUrlTitle={config.editor.fetchUrlTitle}
|
||||||
onChange={(e) => this.handleChange(e)}
|
onChange={(e) => this.handleChange(e)}
|
||||||
onBlur={(e) => this.handleBlur(e)}
|
onBlur={(e) => this.handleBlur(e)}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@ import exportNote from 'browser/main/lib/dataApi/exportNote'
|
|||||||
import { escapeHtmlCharacters } from 'browser/lib/utils'
|
import { escapeHtmlCharacters } from 'browser/lib/utils'
|
||||||
|
|
||||||
const { remote } = require('electron')
|
const { remote } = require('electron')
|
||||||
|
const attachmentManagement = require('../main/lib/dataApi/attachmentManagement')
|
||||||
|
|
||||||
const { app } = remote
|
const { app } = remote
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const dialog = remote.dialog
|
const dialog = remote.dialog
|
||||||
@@ -391,13 +393,11 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
value = value.replace(codeBlock, htmlTextHelper.encodeEntities(codeBlock))
|
value = value.replace(codeBlock, htmlTextHelper.encodeEntities(codeBlock))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
this.refs.root.contentWindow.document.body.innerHTML = this.markdown.render(value)
|
let renderedHTML = this.markdown.render(value)
|
||||||
|
this.refs.root.contentWindow.document.body.innerHTML = attachmentManagement.fixLocalURLS(renderedHTML, storagePath)
|
||||||
|
|
||||||
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
|
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('a'), (el) => {
|
||||||
this.fixDecodedURI(el)
|
this.fixDecodedURI(el)
|
||||||
el.href = this.markdown.normalizeLinkText(el.href)
|
|
||||||
if (!/\/:storage/.test(el.href)) return
|
|
||||||
el.href = `file:///${this.markdown.normalizeLinkText(path.join(storagePath, 'images', path.basename(el.href)))}`
|
|
||||||
el.addEventListener('click', this.anchorClickHandler)
|
el.addEventListener('click', this.anchorClickHandler)
|
||||||
})
|
})
|
||||||
|
|
||||||
@@ -409,12 +409,6 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
el.addEventListener('click', this.linkClickHandler)
|
el.addEventListener('click', this.linkClickHandler)
|
||||||
})
|
})
|
||||||
|
|
||||||
_.forEach(this.refs.root.contentWindow.document.querySelectorAll('img'), (el) => {
|
|
||||||
el.src = this.markdown.normalizeLinkText(el.src)
|
|
||||||
if (!/\/:storage/.test(el.src)) return
|
|
||||||
el.src = `file:///${this.markdown.normalizeLinkText(path.join(storagePath, 'images', path.basename(el.src)))}`
|
|
||||||
})
|
|
||||||
|
|
||||||
codeBlockTheme = consts.THEMES.some((_theme) => _theme === codeBlockTheme)
|
codeBlockTheme = consts.THEMES.some((_theme) => _theme === codeBlockTheme)
|
||||||
? codeBlockTheme
|
? codeBlockTheme
|
||||||
: 'default'
|
: 'default'
|
||||||
@@ -523,6 +517,15 @@ export default class MarkdownPreview extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
handlelinkClick (e) {
|
handlelinkClick (e) {
|
||||||
|
e.preventDefault()
|
||||||
|
e.stopPropagation()
|
||||||
|
|
||||||
|
const href = e.target.href
|
||||||
|
if (href.match(/^http/i)) {
|
||||||
|
shell.openExternal(href)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const noteHash = e.target.href.split('/').pop()
|
const noteHash = e.target.href.split('/').pop()
|
||||||
// this will match the new uuid v4 hash and the old hash
|
// this will match the new uuid v4 hash and the old hash
|
||||||
// e.g.
|
// e.g.
|
||||||
|
|||||||
@@ -88,7 +88,7 @@ class MarkdownSplitEditor extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { config, value, storageKey } = this.props
|
const {config, value, storageKey, noteKey} = this.props
|
||||||
const storage = findStorage(storageKey)
|
const storage = findStorage(storageKey)
|
||||||
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
let editorFontSize = parseInt(config.editor.fontSize, 10)
|
||||||
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
if (!(editorFontSize > 0 && editorFontSize < 101)) editorFontSize = 14
|
||||||
@@ -115,6 +115,7 @@ class MarkdownSplitEditor extends React.Component {
|
|||||||
scrollPastEnd={config.editor.scrollPastEnd}
|
scrollPastEnd={config.editor.scrollPastEnd}
|
||||||
fetchUrlTitle={config.editor.fetchUrlTitle}
|
fetchUrlTitle={config.editor.fetchUrlTitle}
|
||||||
storageKey={storageKey}
|
storageKey={storageKey}
|
||||||
|
noteKey={noteKey}
|
||||||
onChange={this.handleOnChange.bind(this)}
|
onChange={this.handleOnChange.bind(this)}
|
||||||
onScroll={this.handleScroll.bind(this)}
|
onScroll={this.handleScroll.bind(this)}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ const SideNavFilter = ({
|
|||||||
</button>
|
</button>
|
||||||
|
|
||||||
<button styleName={isTrashedActive ? 'menu-button-trash--active' : 'menu-button'}
|
<button styleName={isTrashedActive ? 'menu-button-trash--active' : 'menu-button'}
|
||||||
onClick={handleTrashedButtonClick}
|
onClick={handleTrashedButtonClick} onContextMenu={handleFilterButtonContextMenu}
|
||||||
>
|
>
|
||||||
<div styleName='iconWrap'>
|
<div styleName='iconWrap'>
|
||||||
<img src={isTrashedActive
|
<img src={isTrashedActive
|
||||||
@@ -60,7 +60,7 @@ const SideNavFilter = ({
|
|||||||
}
|
}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<span onContextMenu={handleFilterButtonContextMenu} styleName='menu-button-label'>{i18n.__('Trash')}</span>
|
<span styleName='menu-button-label'>{i18n.__('Trash')}</span>
|
||||||
<span styleName='counters'>{counterDelNote}</span>
|
<span styleName='counters'>{counterDelNote}</span>
|
||||||
</button>
|
</button>
|
||||||
|
|
||||||
|
|||||||
@@ -9,16 +9,26 @@ import CSSModules from 'browser/lib/CSSModules'
|
|||||||
/**
|
/**
|
||||||
* @param {string} name
|
* @param {string} name
|
||||||
* @param {Function} handleClickTagListItem
|
* @param {Function} handleClickTagListItem
|
||||||
|
* @param {Function} handleClickNarrowToTag
|
||||||
* @param {bool} isActive
|
* @param {bool} isActive
|
||||||
|
* @param {bool} isRelated
|
||||||
*/
|
*/
|
||||||
|
|
||||||
const TagListItem = ({name, handleClickTagListItem, isActive, count}) => (
|
const TagListItem = ({name, handleClickTagListItem, handleClickNarrowToTag, isActive, isRelated, count}) => (
|
||||||
|
<div styleName='tagList-itemContainer'>
|
||||||
|
{isRelated
|
||||||
|
? <button styleName={isActive ? 'tagList-itemNarrow-active' : 'tagList-itemNarrow'} onClick={() => handleClickNarrowToTag(name)}>
|
||||||
|
<i className={isActive ? 'fa fa-minus-circle' : 'fa fa-plus-circle'} />
|
||||||
|
</button>
|
||||||
|
: <div styleName={isActive ? 'tagList-itemNarrow-active' : 'tagList-itemNarrow'} />
|
||||||
|
}
|
||||||
<button styleName={isActive ? 'tagList-item-active' : 'tagList-item'} onClick={() => handleClickTagListItem(name)}>
|
<button styleName={isActive ? 'tagList-item-active' : 'tagList-item'} onClick={() => handleClickTagListItem(name)}>
|
||||||
<span styleName='tagList-item-name'>
|
<span styleName='tagList-item-name'>
|
||||||
{`# ${name}`}
|
{`# ${name}`}
|
||||||
<span styleName='tagList-item-count'>{count}</span>
|
<span styleName='tagList-item-count'>{count}</span>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
)
|
)
|
||||||
|
|
||||||
TagListItem.propTypes = {
|
TagListItem.propTypes = {
|
||||||
|
|||||||
@@ -1,5 +1,9 @@
|
|||||||
|
.tagList-itemContainer
|
||||||
|
display flex
|
||||||
|
|
||||||
.tagList-item
|
.tagList-item
|
||||||
display flex
|
display flex
|
||||||
|
flex 1
|
||||||
width 100%
|
width 100%
|
||||||
height 26px
|
height 26px
|
||||||
background-color transparent
|
background-color transparent
|
||||||
@@ -20,9 +24,16 @@
|
|||||||
color $ui-button-default-color
|
color $ui-button-default-color
|
||||||
background-color $ui-button-default--active-backgroundColor
|
background-color $ui-button-default--active-backgroundColor
|
||||||
|
|
||||||
|
.tagList-itemNarrow
|
||||||
|
composes tagList-item
|
||||||
|
flex none
|
||||||
|
width 20px
|
||||||
|
padding 0 4px
|
||||||
|
|
||||||
.tagList-item-active
|
.tagList-item-active
|
||||||
background-color $ui-button-default--active-backgroundColor
|
background-color $ui-button-default--active-backgroundColor
|
||||||
display flex
|
display flex
|
||||||
|
flex 1
|
||||||
width 100%
|
width 100%
|
||||||
height 26px
|
height 26px
|
||||||
padding 0
|
padding 0
|
||||||
@@ -36,10 +47,16 @@
|
|||||||
background-color alpha($ui-button-default--active-backgroundColor, 60%)
|
background-color alpha($ui-button-default--active-backgroundColor, 60%)
|
||||||
transition 0.2s
|
transition 0.2s
|
||||||
|
|
||||||
|
.tagList-itemNarrow-active
|
||||||
|
composes tagList-item-active
|
||||||
|
flex none
|
||||||
|
width 20px
|
||||||
|
padding 0 4px
|
||||||
|
|
||||||
.tagList-item-name
|
.tagList-item-name
|
||||||
display block
|
display block
|
||||||
flex 1
|
flex 1
|
||||||
padding 0 15px
|
padding 0 8px 0 4px
|
||||||
height 26px
|
height 26px
|
||||||
line-height 26px
|
line-height 26px
|
||||||
border-width 0 0 0 2px
|
border-width 0 0 0 2px
|
||||||
@@ -49,7 +66,10 @@
|
|||||||
text-overflow ellipsis
|
text-overflow ellipsis
|
||||||
|
|
||||||
.tagList-item-count
|
.tagList-item-count
|
||||||
padding 0 3px
|
float right
|
||||||
|
line-height 26px
|
||||||
|
padding-right 15px
|
||||||
|
font-size 13px
|
||||||
|
|
||||||
body[data-theme="white"]
|
body[data-theme="white"]
|
||||||
.tagList-item
|
.tagList-item
|
||||||
|
|||||||
75
browser/lib/Languages.js
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
const languages = [
|
||||||
|
{
|
||||||
|
name: 'Albanian',
|
||||||
|
locale: 'sq'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Chinese (zh-CN)',
|
||||||
|
locale: 'zh-CN'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Chinese (zh-TW)',
|
||||||
|
locale: 'zh-TW'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Danish',
|
||||||
|
locale: 'da'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'English',
|
||||||
|
locale: 'en'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'French',
|
||||||
|
locale: 'fr'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'German',
|
||||||
|
locale: 'de'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Hungarian',
|
||||||
|
locale: 'hu'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Japanese',
|
||||||
|
locale: 'ja'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Korean',
|
||||||
|
locale: 'ko'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Norwegian',
|
||||||
|
locale: 'no'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Polish',
|
||||||
|
locale: 'pl'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Portuguese',
|
||||||
|
locale: 'pt'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Russian',
|
||||||
|
locale: 'ru'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: 'Spanish',
|
||||||
|
locale: 'es-ES'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
getLocales () {
|
||||||
|
return languages.reduce(function (localeList, locale) {
|
||||||
|
localeList.push(locale.locale)
|
||||||
|
return localeList
|
||||||
|
}, [])
|
||||||
|
},
|
||||||
|
getLanguages () {
|
||||||
|
return languages
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const { remote } = require('electron')
|
const { remote } = require('electron')
|
||||||
const { app } = remote
|
const { app } = remote
|
||||||
|
const { getLocales } = require('./Languages.js')
|
||||||
|
|
||||||
// load package for localization
|
// load package for localization
|
||||||
const i18n = new (require('i18n-2'))({
|
const i18n = new (require('i18n-2'))({
|
||||||
// setup some locales - other locales default to the first locale
|
// setup some locales - other locales default to the first locale
|
||||||
locales: [ 'da', 'de', 'en', 'es-ES', 'fr', 'hu', 'ja', 'ko', 'pl', 'pt-BR', 'pt-PT', 'ru', 'sq', 'zh-CN', 'zh-TW' ],
|
locales: getLocales(),
|
||||||
extension: '.json',
|
extension: '.json',
|
||||||
directory: process.env.NODE_ENV === 'production'
|
directory: process.env.NODE_ENV === 'production'
|
||||||
? path.join(app.getAppPath(), './locales')
|
? path.join(app.getAppPath(), './locales')
|
||||||
|
|||||||
@@ -234,10 +234,6 @@ class Markdown {
|
|||||||
if (!_.isString(content)) content = ''
|
if (!_.isString(content)) content = ''
|
||||||
return this.md.render(content)
|
return this.md.render(content)
|
||||||
}
|
}
|
||||||
|
|
||||||
normalizeLinkText (linkText) {
|
|
||||||
return this.md.normalizeLinkText(linkText)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Markdown
|
export default Markdown
|
||||||
|
|||||||
@@ -289,6 +289,7 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
config={config}
|
config={config}
|
||||||
value={note.content}
|
value={note.content}
|
||||||
storageKey={note.storage}
|
storageKey={note.storage}
|
||||||
|
noteKey={note.key}
|
||||||
onChange={this.handleUpdateContent.bind(this)}
|
onChange={this.handleUpdateContent.bind(this)}
|
||||||
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
||||||
/>
|
/>
|
||||||
@@ -298,6 +299,7 @@ class MarkdownNoteDetail extends React.Component {
|
|||||||
config={config}
|
config={config}
|
||||||
value={note.content}
|
value={note.content}
|
||||||
storageKey={note.storage}
|
storageKey={note.storage}
|
||||||
|
noteKey={note.key}
|
||||||
onChange={this.handleUpdateContent.bind(this)}
|
onChange={this.handleUpdateContent.bind(this)}
|
||||||
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
ignorePreviewPointerEvents={ignorePreviewPointerEvents}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ import eventEmitter from 'browser/main/lib/eventEmitter'
|
|||||||
import { hashHistory } from 'react-router'
|
import { hashHistory } from 'react-router'
|
||||||
import store from 'browser/main/store'
|
import store from 'browser/main/store'
|
||||||
import i18n from 'browser/lib/i18n'
|
import i18n from 'browser/lib/i18n'
|
||||||
|
import { getLocales } from 'browser/lib/Languages'
|
||||||
const path = require('path')
|
const path = require('path')
|
||||||
const electron = require('electron')
|
const electron = require('electron')
|
||||||
const { remote } = electron
|
const { remote } = electron
|
||||||
@@ -152,24 +153,7 @@ class Main extends React.Component {
|
|||||||
document.body.setAttribute('data-theme', 'default')
|
document.body.setAttribute('data-theme', 'default')
|
||||||
}
|
}
|
||||||
|
|
||||||
const supportedLanguages = [
|
if (getLocales().indexOf(config.ui.language) !== -1) {
|
||||||
'sq',
|
|
||||||
'zh-CN',
|
|
||||||
'zh-TW',
|
|
||||||
'da',
|
|
||||||
'fr',
|
|
||||||
'de',
|
|
||||||
'hu',
|
|
||||||
'ja',
|
|
||||||
'ko',
|
|
||||||
'no',
|
|
||||||
'pl',
|
|
||||||
'pt',
|
|
||||||
'ru',
|
|
||||||
'es-ES'
|
|
||||||
]
|
|
||||||
|
|
||||||
if (supportedLanguages.indexOf(config.ui.language) !== -1) {
|
|
||||||
i18n.setLocale(config.ui.language)
|
i18n.setLocale(config.ui.language)
|
||||||
} else {
|
} else {
|
||||||
i18n.setLocale('en')
|
i18n.setLocale('en')
|
||||||
|
|||||||
@@ -282,8 +282,8 @@ class NoteList extends React.Component {
|
|||||||
ee.emit('detail:focus')
|
ee.emit('detail:focus')
|
||||||
}
|
}
|
||||||
|
|
||||||
// F or S key
|
// L or S key
|
||||||
if (e.keyCode === 70 || e.keyCode === 83) {
|
if (e.keyCode === 76 || e.keyCode === 83) {
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
ee.emit('top:focus-search')
|
ee.emit('top:focus-search')
|
||||||
}
|
}
|
||||||
@@ -343,11 +343,10 @@ class NoteList extends React.Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (location.pathname.match(/\/tags/)) {
|
if (location.pathname.match(/\/tags/)) {
|
||||||
|
const listOfTags = params.tagname.split(' ')
|
||||||
return data.noteMap.map(note => {
|
return data.noteMap.map(note => {
|
||||||
return note
|
return note
|
||||||
}).filter(note => {
|
}).filter(note => listOfTags.every(tag => note.tags.includes(tag)))
|
||||||
return note.tags.includes(params.tagname)
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getContextNotes()
|
return this.getContextNotes()
|
||||||
@@ -916,7 +915,7 @@ class NoteList extends React.Component {
|
|||||||
if (note.isTrashed !== true || location.pathname === '/trashed') return true
|
if (note.isTrashed !== true || location.pathname === '/trashed') return true
|
||||||
})
|
})
|
||||||
|
|
||||||
moment.locale('en', {
|
moment.updateLocale('en', {
|
||||||
relativeTime: {
|
relativeTime: {
|
||||||
future: 'in %s',
|
future: 'in %s',
|
||||||
past: '%s ago',
|
past: '%s ago',
|
||||||
|
|||||||
@@ -145,20 +145,27 @@ class SideNav extends React.Component {
|
|||||||
|
|
||||||
tagListComponent () {
|
tagListComponent () {
|
||||||
const { data, location, config } = this.props
|
const { data, location, config } = this.props
|
||||||
|
const relatedTags = this.getRelatedTags(this.getActiveTags(location.pathname), data.noteMap)
|
||||||
let tagList = _.sortBy(data.tagNoteMap.map(
|
let tagList = _.sortBy(data.tagNoteMap.map(
|
||||||
(tag, name) => ({name, size: tag.size})),
|
(tag, name) => ({ name, size: tag.size, related: relatedTags.has(name) })
|
||||||
['name']
|
), ['name'])
|
||||||
)
|
|
||||||
if (config.sortTagsBy === 'COUNTER') {
|
if (config.sortTagsBy === 'COUNTER') {
|
||||||
tagList = _.sortBy(tagList, item => (0 - item.size))
|
tagList = _.sortBy(tagList, item => (0 - item.size))
|
||||||
}
|
}
|
||||||
|
if (config.ui.showOnlyRelatedTags && (relatedTags.size > 0)) {
|
||||||
|
tagList = tagList.filter(
|
||||||
|
tag => tag.related
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
tagList.map(tag => {
|
tagList.map(tag => {
|
||||||
return (
|
return (
|
||||||
<TagListItem
|
<TagListItem
|
||||||
name={tag.name}
|
name={tag.name}
|
||||||
handleClickTagListItem={this.handleClickTagListItem.bind(this)}
|
handleClickTagListItem={this.handleClickTagListItem.bind(this)}
|
||||||
|
handleClickNarrowToTag={this.handleClickNarrowToTag.bind(this)}
|
||||||
isActive={this.getTagActive(location.pathname, tag.name)}
|
isActive={this.getTagActive(location.pathname, tag.name)}
|
||||||
|
isRelated={tag.related}
|
||||||
key={tag.name}
|
key={tag.name}
|
||||||
count={tag.size}
|
count={tag.size}
|
||||||
/>
|
/>
|
||||||
@@ -167,10 +174,30 @@ class SideNav extends React.Component {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
getRelatedTags (activeTags, noteMap) {
|
||||||
|
if (activeTags.length === 0) {
|
||||||
|
return new Set()
|
||||||
|
}
|
||||||
|
const relatedNotes = noteMap.map(
|
||||||
|
note => ({key: note.key, tags: note.tags})
|
||||||
|
).filter(
|
||||||
|
note => activeTags.every(tag => note.tags.includes(tag))
|
||||||
|
)
|
||||||
|
let relatedTags = new Set()
|
||||||
|
relatedNotes.forEach(note => note.tags.map(tag => relatedTags.add(tag)))
|
||||||
|
return relatedTags
|
||||||
|
}
|
||||||
|
|
||||||
getTagActive (path, tag) {
|
getTagActive (path, tag) {
|
||||||
|
return this.getActiveTags(path).includes(tag)
|
||||||
|
}
|
||||||
|
|
||||||
|
getActiveTags (path) {
|
||||||
const pathSegments = path.split('/')
|
const pathSegments = path.split('/')
|
||||||
const pathTag = pathSegments[pathSegments.length - 1]
|
const tags = pathSegments[pathSegments.length - 1]
|
||||||
return pathTag === tag
|
return (tags === 'alltags')
|
||||||
|
? []
|
||||||
|
: tags.split(' ')
|
||||||
}
|
}
|
||||||
|
|
||||||
handleClickTagListItem (name) {
|
handleClickTagListItem (name) {
|
||||||
@@ -192,6 +219,19 @@ class SideNav extends React.Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
handleClickNarrowToTag (tag) {
|
||||||
|
const { router } = this.context
|
||||||
|
const { location } = this.props
|
||||||
|
let listOfTags = this.getActiveTags(location.pathname)
|
||||||
|
const indexOfTag = listOfTags.indexOf(tag)
|
||||||
|
if (indexOfTag > -1) {
|
||||||
|
listOfTags.splice(indexOfTag, 1)
|
||||||
|
} else {
|
||||||
|
listOfTags.push(tag)
|
||||||
|
}
|
||||||
|
router.push(`/tags/${listOfTags.join(' ')}`)
|
||||||
|
}
|
||||||
|
|
||||||
emptyTrash (entries) {
|
emptyTrash (entries) {
|
||||||
const { dispatch } = this.props
|
const { dispatch } = this.props
|
||||||
const deletionPromises = entries.map((note) => {
|
const deletionPromises = entries.map((note) => {
|
||||||
|
|||||||
164
browser/main/lib/dataApi/attachmentManagement.js
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
const uniqueSlug = require('unique-slug')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const findStorage = require('browser/lib/findStorage')
|
||||||
|
const mdurl = require('mdurl')
|
||||||
|
|
||||||
|
const STORAGE_FOLDER_PLACEHOLDER = ':storage'
|
||||||
|
const DESTINATION_FOLDER = 'attachments'
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description
|
||||||
|
* Copies a copy of an attachment to the storage folder specified by the given key and return the generated attachment name.
|
||||||
|
* Renames the file to match a unique file name.
|
||||||
|
*
|
||||||
|
* @param {String} sourceFilePath The source path of the attachment to be copied
|
||||||
|
* @param {String} storageKey Storage key of the destination storage
|
||||||
|
* @param {String} noteKey Key of the current note. Will be used as subfolder in :storage
|
||||||
|
* @param {boolean} useRandomName determines whether a random filename for the new file is used. If false the source file name is used
|
||||||
|
* @return {Promise<String>} name (inclusive extension) of the generated file
|
||||||
|
*/
|
||||||
|
function copyAttachment (sourceFilePath, storageKey, noteKey, useRandomName = true) {
|
||||||
|
return new Promise((resolve, reject) => {
|
||||||
|
if (!sourceFilePath) {
|
||||||
|
reject('sourceFilePath has to be given')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!storageKey) {
|
||||||
|
reject('storageKey has to be given')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!noteKey) {
|
||||||
|
reject('noteKey has to be given')
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (!fs.existsSync(sourceFilePath)) {
|
||||||
|
reject('source file does not exist')
|
||||||
|
}
|
||||||
|
|
||||||
|
const targetStorage = findStorage.findStorage(storageKey)
|
||||||
|
|
||||||
|
const inputFile = fs.createReadStream(sourceFilePath)
|
||||||
|
let destinationName
|
||||||
|
if (useRandomName) {
|
||||||
|
destinationName = `${uniqueSlug()}${path.extname(sourceFilePath)}`
|
||||||
|
} else {
|
||||||
|
destinationName = path.basename(sourceFilePath)
|
||||||
|
}
|
||||||
|
const destinationDir = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey)
|
||||||
|
createAttachmentDestinationFolder(targetStorage.path, noteKey)
|
||||||
|
const outputFile = fs.createWriteStream(path.join(destinationDir, destinationName))
|
||||||
|
inputFile.pipe(outputFile)
|
||||||
|
resolve(destinationName)
|
||||||
|
} catch (e) {
|
||||||
|
return reject(e)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
function createAttachmentDestinationFolder (destinationStoragePath, noteKey) {
|
||||||
|
let destinationDir = path.join(destinationStoragePath, DESTINATION_FOLDER)
|
||||||
|
if (!fs.existsSync(destinationDir)) {
|
||||||
|
fs.mkdirSync(destinationDir)
|
||||||
|
}
|
||||||
|
destinationDir = path.join(destinationStoragePath, DESTINATION_FOLDER, noteKey)
|
||||||
|
if (!fs.existsSync(destinationDir)) {
|
||||||
|
fs.mkdirSync(destinationDir)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Fixes the URLs embedded in the generated HTML so that they again refer actual local files.
|
||||||
|
* @param {String} renderedHTML HTML in that the links should be fixed
|
||||||
|
* @param {String} storagePath Path of the current storage
|
||||||
|
* @returns {String} postprocessed HTML in which all :storage references are mapped to the actual paths.
|
||||||
|
*/
|
||||||
|
function fixLocalURLS (renderedHTML, storagePath) {
|
||||||
|
return renderedHTML.replace(new RegExp(mdurl.encode(path.sep), 'g'), path.sep).replace(new RegExp(STORAGE_FOLDER_PLACEHOLDER, 'g'), 'file:///' + path.join(storagePath, DESTINATION_FOLDER))
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Generates the markdown code for a given attachment
|
||||||
|
* @param {String} fileName Name of the attachment
|
||||||
|
* @param {String} path Path of the attachment
|
||||||
|
* @param {Boolean} showPreview Indicator whether the generated markdown should show a preview of the image. Note that at the moment only previews for images are supported
|
||||||
|
* @returns {String} Generated markdown code
|
||||||
|
*/
|
||||||
|
function generateAttachmentMarkdown (fileName, path, showPreview) {
|
||||||
|
return `${showPreview ? '!' : ''}[${fileName}](${path})`
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Handles the drop-event of a file. Includes the necessary markdown code and copies the file to the corresponding storage folder.
|
||||||
|
* The method calls {CodeEditor#insertAttachmentMd()} to include the generated markdown at the needed place!
|
||||||
|
* @param {CodeEditor} codeEditor Markdown editor. Its insertAttachmentMd() method will be called to include the markdown code
|
||||||
|
* @param {String} storageKey Key of the current storage
|
||||||
|
* @param {String} noteKey Key of the current note
|
||||||
|
* @param {Event} dropEvent DropEvent
|
||||||
|
*/
|
||||||
|
function handleAttachmentDrop (codeEditor, storageKey, noteKey, dropEvent) {
|
||||||
|
const file = dropEvent.dataTransfer.files[0]
|
||||||
|
const filePath = file.path
|
||||||
|
const originalFileName = path.basename(filePath)
|
||||||
|
const fileType = file['type']
|
||||||
|
|
||||||
|
copyAttachment(filePath, storageKey, noteKey).then((fileName) => {
|
||||||
|
let showPreview = fileType.startsWith('image')
|
||||||
|
let imageMd = generateAttachmentMarkdown(originalFileName, path.join(STORAGE_FOLDER_PLACEHOLDER, noteKey, fileName), showPreview)
|
||||||
|
codeEditor.insertAttachmentMd(imageMd)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description Creates a new file in the storage folder belonging to the current note and inserts the correct markdown code
|
||||||
|
* @param {CodeEditor} codeEditor Markdown editor. Its insertAttachmentMd() method will be called to include the markdown code
|
||||||
|
* @param {String} storageKey Key of the current storage
|
||||||
|
* @param {String} noteKey Key of the current note
|
||||||
|
* @param {DataTransferItem} dataTransferItem Part of the past-event
|
||||||
|
*/
|
||||||
|
function handlePastImageEvent (codeEditor, storageKey, noteKey, dataTransferItem) {
|
||||||
|
if (!codeEditor) {
|
||||||
|
throw new Error('codeEditor has to be given')
|
||||||
|
}
|
||||||
|
if (!storageKey) {
|
||||||
|
throw new Error('storageKey has to be given')
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!noteKey) {
|
||||||
|
throw new Error('noteKey has to be given')
|
||||||
|
}
|
||||||
|
if (!dataTransferItem) {
|
||||||
|
throw new Error('dataTransferItem has to be given')
|
||||||
|
}
|
||||||
|
|
||||||
|
const blob = dataTransferItem.getAsFile()
|
||||||
|
const reader = new FileReader()
|
||||||
|
let base64data
|
||||||
|
const targetStorage = findStorage.findStorage(storageKey)
|
||||||
|
const destinationDir = path.join(targetStorage.path, DESTINATION_FOLDER, noteKey)
|
||||||
|
createAttachmentDestinationFolder(targetStorage.path, noteKey)
|
||||||
|
|
||||||
|
let imageName = `${uniqueSlug()}.png`
|
||||||
|
const imagePath = path.join(destinationDir, imageName)
|
||||||
|
|
||||||
|
reader.onloadend = function () {
|
||||||
|
base64data = reader.result.replace(/^data:image\/png;base64,/, '')
|
||||||
|
base64data += base64data.replace('+', ' ')
|
||||||
|
const binaryData = new Buffer(base64data, 'base64').toString('binary')
|
||||||
|
fs.writeFile(imagePath, binaryData, 'binary')
|
||||||
|
let imageMd = generateAttachmentMarkdown(imageName, imagePath, true)
|
||||||
|
codeEditor.insertAttachmentMd(imageMd)
|
||||||
|
}
|
||||||
|
reader.readAsDataURL(blob)
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
copyAttachment,
|
||||||
|
fixLocalURLS,
|
||||||
|
generateAttachmentMarkdown,
|
||||||
|
handleAttachmentDrop,
|
||||||
|
handlePastImageEvent,
|
||||||
|
STORAGE_FOLDER_PLACEHOLDER,
|
||||||
|
DESTINATION_FOLDER
|
||||||
|
}
|
||||||
@@ -2,6 +2,8 @@ const fs = require('fs')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
const { findStorage } = require('browser/lib/findStorage')
|
const { findStorage } = require('browser/lib/findStorage')
|
||||||
|
|
||||||
|
// TODO: ehhc: delete this
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @description Copy an image and return the path.
|
* @description Copy an image and return the path.
|
||||||
* @param {String} filePath
|
* @param {String} filePath
|
||||||
@@ -21,8 +23,12 @@ function copyImage (filePath, storageKey, rename = true) {
|
|||||||
const imageDir = path.join(targetStorage.path, 'images')
|
const imageDir = path.join(targetStorage.path, 'images')
|
||||||
if (!fs.existsSync(imageDir)) fs.mkdirSync(imageDir)
|
if (!fs.existsSync(imageDir)) fs.mkdirSync(imageDir)
|
||||||
const outputImage = fs.createWriteStream(path.join(imageDir, basename))
|
const outputImage = fs.createWriteStream(path.join(imageDir, basename))
|
||||||
inputImage.pipe(outputImage)
|
outputImage.on('error', reject)
|
||||||
|
inputImage.on('error', reject)
|
||||||
|
inputImage.on('end', () => {
|
||||||
resolve(basename)
|
resolve(basename)
|
||||||
|
})
|
||||||
|
inputImage.pipe(outputImage)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
return reject(e)
|
return reject(e)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ const fs = require('fs')
|
|||||||
const path = require('path')
|
const path = require('path')
|
||||||
|
|
||||||
const LOCAL_STORED_REGEX = /!\[(.*?)]\(\s*?\/:storage\/(.*\.\S*?)\)/gi
|
const LOCAL_STORED_REGEX = /!\[(.*?)]\(\s*?\/:storage\/(.*\.\S*?)\)/gi
|
||||||
|
// TODO: ehhc: check this -> attachmentManagement
|
||||||
const IMAGES_FOLDER_NAME = 'images'
|
const IMAGES_FOLDER_NAME = 'images'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -68,6 +68,8 @@ function moveNote (storageKey, noteKey, newStorageKey, newFolderKey) {
|
|||||||
return noteData
|
return noteData
|
||||||
})
|
})
|
||||||
.then(function moveImages (noteData) {
|
.then(function moveImages (noteData) {
|
||||||
|
if (oldStorage.path === newStorage.path) return noteData
|
||||||
|
|
||||||
const searchImagesRegex = /!\[.*?]\(\s*?\/:storage\/(.*\.\S*?)\)/gi
|
const searchImagesRegex = /!\[.*?]\(\s*?\/:storage\/(.*\.\S*?)\)/gi
|
||||||
let match = searchImagesRegex.exec(noteData.content)
|
let match = searchImagesRegex.exec(noteData.content)
|
||||||
|
|
||||||
@@ -75,6 +77,7 @@ function moveNote (storageKey, noteKey, newStorageKey, newFolderKey) {
|
|||||||
while (match != null) {
|
while (match != null) {
|
||||||
const [, filename] = match
|
const [, filename] = match
|
||||||
const oldPath = path.join(oldStorage.path, 'images', filename)
|
const oldPath = path.join(oldStorage.path, 'images', filename)
|
||||||
|
// TODO: ehhc: attachmentManagement
|
||||||
moveTasks.push(
|
moveTasks.push(
|
||||||
copyImage(oldPath, noteData.storage, false)
|
copyImage(oldPath, noteData.storage, false)
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import CodeMirror from 'codemirror'
|
|||||||
import 'codemirror-mode-elixir'
|
import 'codemirror-mode-elixir'
|
||||||
import _ from 'lodash'
|
import _ from 'lodash'
|
||||||
import i18n from 'browser/lib/i18n'
|
import i18n from 'browser/lib/i18n'
|
||||||
|
import { getLanguages } from 'browser/lib/Languages'
|
||||||
|
|
||||||
const OSX = global.process.platform === 'darwin'
|
const OSX = global.process.platform === 'darwin'
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ class UiTab extends React.Component {
|
|||||||
language: this.refs.uiLanguage.value,
|
language: this.refs.uiLanguage.value,
|
||||||
showCopyNotification: this.refs.showCopyNotification.checked,
|
showCopyNotification: this.refs.showCopyNotification.checked,
|
||||||
confirmDeletion: this.refs.confirmDeletion.checked,
|
confirmDeletion: this.refs.confirmDeletion.checked,
|
||||||
|
showOnlyRelatedTags: this.refs.showOnlyRelatedTags.checked,
|
||||||
disableDirectWrite: this.refs.uiD2w != null
|
disableDirectWrite: this.refs.uiD2w != null
|
||||||
? this.refs.uiD2w.checked
|
? this.refs.uiD2w.checked
|
||||||
: false
|
: false
|
||||||
@@ -182,22 +184,9 @@ class UiTab extends React.Component {
|
|||||||
onChange={(e) => this.handleUIChange(e)}
|
onChange={(e) => this.handleUIChange(e)}
|
||||||
ref='uiLanguage'
|
ref='uiLanguage'
|
||||||
>
|
>
|
||||||
<option value='sq'>{i18n.__('Albanian')}</option>
|
{
|
||||||
<option value='zh-CN'>{i18n.__('Chinese (zh-CN)')}</option>
|
getLanguages().map((language) => <option value={language.locale} key={language.locale}>{i18n.__(language.name)}</option>)
|
||||||
<option value='zh-TW'>{i18n.__('Chinese (zh-TW)')}</option>
|
}
|
||||||
<option value='da'>{i18n.__('Danish')}</option>
|
|
||||||
<option value='en'>{i18n.__('English')}</option>
|
|
||||||
<option value='fr'>{i18n.__('French')}</option>
|
|
||||||
<option value='de'>{i18n.__('German')}</option>
|
|
||||||
<option value='hu'>{i18n.__('Hungarian')}</option>
|
|
||||||
<option value='ja'>{i18n.__('Japanese')}</option>
|
|
||||||
<option value='ko'>{i18n.__('Korean')}</option>
|
|
||||||
<option value='no'>{i18n.__('Norwegian')}</option>
|
|
||||||
<option value='pl'>{i18n.__('Polish')}</option>
|
|
||||||
<option value='pt-BR'>{i18n.__('Portuguese (Brazil)')}</option>
|
|
||||||
<option value='pt-PT'>{i18n.__('Portuguese (Portugal)')}</option>
|
|
||||||
<option value='ru'>{i18n.__('Russian')}</option>
|
|
||||||
<option value='es-ES'>{i18n.__('Spanish')}</option>
|
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -222,6 +211,16 @@ class UiTab extends React.Component {
|
|||||||
{i18n.__('Show a confirmation dialog when deleting notes')}
|
{i18n.__('Show a confirmation dialog when deleting notes')}
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<div styleName='group-checkBoxSection'>
|
||||||
|
<label>
|
||||||
|
<input onChange={(e) => this.handleUIChange(e)}
|
||||||
|
checked={this.state.config.ui.showOnlyRelatedTags}
|
||||||
|
ref='showOnlyRelatedTags'
|
||||||
|
type='checkbox'
|
||||||
|
/>
|
||||||
|
{i18n.__('Show only related tags')}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
{
|
{
|
||||||
global.process.platform === 'win32'
|
global.process.platform === 'win32'
|
||||||
? <div styleName='group-checkBoxSection'>
|
? <div styleName='group-checkBoxSection'>
|
||||||
|
|||||||
@@ -252,10 +252,20 @@ const view = {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
label: 'Focus Search',
|
label: 'Focus Search',
|
||||||
accelerator: 'Control+S',
|
accelerator: 'CommandOrControl+Shift+L',
|
||||||
click () {
|
click () {
|
||||||
mainWindow.webContents.send('top:focus-search')
|
mainWindow.webContents.send('top:focus-search')
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'separator'
|
||||||
|
},
|
||||||
|
{
|
||||||
|
label: 'Toggle Full Screen',
|
||||||
|
accelerator: macOS ? 'Command+Control+F' : 'F11',
|
||||||
|
click () {
|
||||||
|
mainWindow.setFullScreen(!mainWindow.isFullScreen())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -265,7 +275,7 @@ let editorFocused
|
|||||||
// Define extra shortcut keys
|
// Define extra shortcut keys
|
||||||
mainWindow.webContents.on('before-input-event', (event, input) => {
|
mainWindow.webContents.on('before-input-event', (event, input) => {
|
||||||
// Synonyms for Search (Find)
|
// Synonyms for Search (Find)
|
||||||
if (input.control && input.key === 'f' && input.type === 'keyDown') {
|
if (input.control && input.key === 'l' && input.type === 'keyDown') {
|
||||||
if (!editorFocused) {
|
if (!editorFocused) {
|
||||||
mainWindow.webContents.send('top:focus-search')
|
mainWindow.webContents.send('top:focus-search')
|
||||||
event.preventDefault()
|
event.preventDefault()
|
||||||
@@ -285,11 +295,6 @@ const window = {
|
|||||||
accelerator: 'Command+M',
|
accelerator: 'Command+M',
|
||||||
selector: 'performMiniaturize:'
|
selector: 'performMiniaturize:'
|
||||||
},
|
},
|
||||||
{
|
|
||||||
label: 'Toggle Full Screen',
|
|
||||||
accelerator: 'Command+Control+F',
|
|
||||||
selector: 'toggleFullScreen:'
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
label: 'Close',
|
label: 'Close',
|
||||||
accelerator: 'Command+W',
|
accelerator: 'Command+W',
|
||||||
|
|||||||
@@ -87,7 +87,7 @@
|
|||||||
"Boostnote is used in about 200 different countries and regions by an awesome community of developers.": "Boostnote es utilizado en alrededor de 200 países y regiones diferentes por una increíble comunidad de desarrolladores.",
|
"Boostnote is used in about 200 different countries and regions by an awesome community of developers.": "Boostnote es utilizado en alrededor de 200 países y regiones diferentes por una increíble comunidad de desarrolladores.",
|
||||||
"To continue supporting this growth, and to satisfy community expectations,": "Para continuar apoyando este crecimiento y satisfacer las expectativas de la comunidad,",
|
"To continue supporting this growth, and to satisfy community expectations,": "Para continuar apoyando este crecimiento y satisfacer las expectativas de la comunidad,",
|
||||||
"we would like to invest more time and resources in this project.": "nos gustaría invertir más tiempo y recursos en este proyecto.",
|
"we would like to invest more time and resources in this project.": "nos gustaría invertir más tiempo y recursos en este proyecto.",
|
||||||
"If you like this project and see its potential, you can help by supporting us on OpenCollective!": "Si te gusta este proyecto y ves potencial en él, ¡puedes ayudar apoyándonos en OpenCollective!",
|
"If you like this project and see its potential, you can help by supporting us on OpenCollective!": "Si te gusta este proyecto y ves su potencial, ¡puedes ayudar apoyándonos en OpenCollective!",
|
||||||
"Thanks,": "Gracias,",
|
"Thanks,": "Gracias,",
|
||||||
"Boostnote maintainers": "Equipo de Boostnote",
|
"Boostnote maintainers": "Equipo de Boostnote",
|
||||||
"Support via OpenCollective": "Contribuir vía OpenCollective",
|
"Support via OpenCollective": "Contribuir vía OpenCollective",
|
||||||
@@ -149,5 +149,5 @@
|
|||||||
"Sanitization": "Saneamiento",
|
"Sanitization": "Saneamiento",
|
||||||
"Only allow secure html tags (recommended)": "Solo permitir etiquetas html seguras (recomendado)",
|
"Only allow secure html tags (recommended)": "Solo permitir etiquetas html seguras (recomendado)",
|
||||||
"Allow styles": "Permitir estilos",
|
"Allow styles": "Permitir estilos",
|
||||||
"Allow dangerous html tags": "Permitir etiques html peligrosas"
|
"Allow dangerous html tags": "Permitir etiquetas html peligrosas"
|
||||||
}
|
}
|
||||||
|
|||||||
156
locales/fa.json
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
{
|
||||||
|
"Notes": "یادداشت ها",
|
||||||
|
"Tags": "تگ ها",
|
||||||
|
"Preferences": "تنظیمات",
|
||||||
|
"Make a note": "یک یادداشت بنویس",
|
||||||
|
"Ctrl": "Ctrl",
|
||||||
|
"Ctrl(^)": "Ctrl",
|
||||||
|
"to create a new note": "برای ساخت یک یادداشت",
|
||||||
|
"Toggle Mode": "تغییر حالت نمایش",
|
||||||
|
"Trash": "سطل آشغال",
|
||||||
|
"MODIFICATION DATE": "تاریخ تغییر",
|
||||||
|
"Words": "کلمات",
|
||||||
|
"Letters": "حروف",
|
||||||
|
"STORAGE": "ذخیره سازی",
|
||||||
|
"FOLDER": "پوشه",
|
||||||
|
"CREATION DATE": "تاریخ ایجاد",
|
||||||
|
"NOTE LINK": "لینک یادداشت",
|
||||||
|
".md": ".md",
|
||||||
|
".txt": ".txt",
|
||||||
|
".html": ".html",
|
||||||
|
"Print": "پرینت",
|
||||||
|
"Your preferences for Boostnote": "تنظیمات شما برای boostnote",
|
||||||
|
"Storages": "ذخیره سازی",
|
||||||
|
"Add Storage Location": "افزودن محل ذخیره سازی",
|
||||||
|
"Add Folder": "ساخت پوشه",
|
||||||
|
"Open Storage folder": "بازکردن پوشه ذخیره سازی",
|
||||||
|
"Unlink": "حذف لینک",
|
||||||
|
"Edit": "ویرایش",
|
||||||
|
"Delete": "حذف",
|
||||||
|
"Interface": "رابط کاربری",
|
||||||
|
"Interface Theme": "تم رابط کاربری",
|
||||||
|
"Default": "پیش فرض",
|
||||||
|
"White": "روشن",
|
||||||
|
"Solarized Dark": "سولارایز",
|
||||||
|
"Dark": "تاریک",
|
||||||
|
"Show a confirmation dialog when deleting notes": "هنگام حذف یادداشت ها یک پیام تایید نمایش بده.",
|
||||||
|
"Editor Theme": "تم ویرایشگر",
|
||||||
|
"Editor Font Size": "اندازه فونت ویرایشگر",
|
||||||
|
"Editor Font Family": "فونت ویرایشگر",
|
||||||
|
"Editor Indent Style": "حالت فاصله گذاری ویرایشگر",
|
||||||
|
"Spaces": "Spaces",
|
||||||
|
"Tabs": "Tabs",
|
||||||
|
"Switch to Preview": "دیدن پیش نمایش",
|
||||||
|
"When Editor Blurred": "وقتی ویرایشگر از حالت ویرایش خارج شد ",
|
||||||
|
"When Editor Blurred, Edit On Double Click": "وقتی ویرایشگر از حالت ویرایش خارج شد و با دبل کلیک ویرایش کنید.",
|
||||||
|
"On Right Click": "راست کلیک",
|
||||||
|
"Editor Keymap": "ویرایشگر Keymap",
|
||||||
|
"default": "پیش فرض",
|
||||||
|
"vim": "vim",
|
||||||
|
"emacs": "emacs",
|
||||||
|
"⚠️ Please restart boostnote after you change the keymap": "⚠️ برنامه را دوباره راه اندازی کنید keymap لطفا بعد از تغییر",
|
||||||
|
"Show line numbers in the editor": "شماره خطوط در ویرایشگر را نمایش بده.",
|
||||||
|
"Allow editor to scroll past the last line": "اجازه بده ویرایشگر بعد از آخرین خط اسکرول کند.",
|
||||||
|
"Bring in web page title when pasting URL on editor": "هنگامی که آدرس اینترنتی در ویرایشگر اضافه شد عنوان آنرا نمایش بده",
|
||||||
|
"Preview": "پیش نمایش",
|
||||||
|
"Preview Font Size": "اندازه فونتِ پیش نمایش",
|
||||||
|
"Preview Font Family": " فونتِ پیش نمایش",
|
||||||
|
"Code block Theme": "تم بخش کد",
|
||||||
|
"Allow preview to scroll past the last line": "اجازه بده پیش نمایش بعد از آخرین خط اسکرول کند.",
|
||||||
|
"Show line numbers for preview code blocks": "شماره خطوط در پیش نمایش را نمایش بده.",
|
||||||
|
"LaTeX Inline Open Delimiter": "جداکننده آغازین لاتکس خطی",
|
||||||
|
"LaTeX Inline Close Delimiter": "جداکننده پایانی لاتکس خطی",
|
||||||
|
"LaTeX Block Open Delimiter": "جداکننده آغازین بلوک لاتکس ",
|
||||||
|
"LaTeX Block Close Delimiter": "جداکننده آغازین بلوک لاتکس ",
|
||||||
|
"Community": "کامینیتی",
|
||||||
|
"Subscribe to Newsletter": "اشتراک در خبرنامه",
|
||||||
|
"GitHub": "گیت هاب",
|
||||||
|
"Blog": "بلاگ",
|
||||||
|
"Facebook Group": "گروه فیسبوک",
|
||||||
|
"Twitter": "توییتر",
|
||||||
|
"About": "درباره",
|
||||||
|
"Boostnote": "Boostnote",
|
||||||
|
"An open source note-taking app made for programmers just like you.": "یک دفترچه یادداشت متن باز ساخته شده برای برنامه نویسانی مثل تو.",
|
||||||
|
"Website": "وبسایت",
|
||||||
|
"Development": "توسعه",
|
||||||
|
" : Development configurations for Boostnote.": " : پیکربندی توسعه برای Boostnote.",
|
||||||
|
"Copyright (C) 2017 - 2018 BoostIO": "Copyright (C) 2017 - 2018 BoostIO",
|
||||||
|
"License: GPL v3": "لایسنس: GPL v3",
|
||||||
|
"Analytics": "تجزیه و تحلیل",
|
||||||
|
"Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.": "Bosstnote اطلاعات ناشناس را برای بهبود عملکرد برنامه جمع آوری میکند.اطلاعات شخصی شما مثل محتوای یادداشت ها هرگز برای هیچ هدفی جمع آوری نمیشوند",
|
||||||
|
"You can see how it works on ": "میتوانید ببینید چگونه کار میکند. ",
|
||||||
|
"You can choose to enable or disable this option.": "میتوانید این گزینه را فعال یا غیرفعال کنید.",
|
||||||
|
"Enable analytics to help improve Boostnote":".تجزیه تحلیل داده ها را برای کمک به بهبود برنامه فعال کن",
|
||||||
|
"Crowdfunding": "جمع سپاری (سرمایه گذاری جمعی )",
|
||||||
|
"Dear everyone,": "عزیزان,",
|
||||||
|
"Thank you for using Boostnote!": "از شما بخاطر استفاده از boostnote ممنونیم!",
|
||||||
|
"Boostnote is used in about 200 different countries and regions by an awesome community of developers.": "در ۲۰۰ کشور مختلف دنیا مورد توسط جمعی از برنامه نویسان بی نظیر مورد استفاده قرار میگیرد. Boostnote",
|
||||||
|
"To continue supporting this growth, and to satisfy community expectations,": "برای حمایت از این رشد ، و برآورده شدن انتظارات کامینیتی,",
|
||||||
|
"we would like to invest more time and resources in this project.": "ما می خواهیم زمان و منابع بیشتری را در این پروژه سرمایه گذاری کنیم.",
|
||||||
|
"If you like this project and see its potential, you can help by supporting us on OpenCollective!": "اگر این پروژه را دوست دارید و پتانسیلی در آن میبینید، میتوانید مارا در اوپن کالکتیو حمایت کنید.",
|
||||||
|
"Thanks,": "با تشکر,",
|
||||||
|
"Boostnote maintainers": "Boostnote نگهدارندگان",
|
||||||
|
"Support via OpenCollective": "حمایت کنید OpenCollective از طریق",
|
||||||
|
"Language": "زبان",
|
||||||
|
"English": "انگلیسی",
|
||||||
|
"German": "آلمانی",
|
||||||
|
"French": "فرانسوی",
|
||||||
|
"Show \"Saved to Clipboard\" notification when copying": "نمایش \"ذخیره در کلیپبورد\" اطلاع رسانی هنگام کپی کردن",
|
||||||
|
"All Notes": "همه یادداشت ها",
|
||||||
|
"Starred": "ستاره دار",
|
||||||
|
"Are you sure to ": " مطمئن هستید که",
|
||||||
|
" delete": "حذف ",
|
||||||
|
"this folder?": "این پوشه ؟",
|
||||||
|
"Confirm": "تایید",
|
||||||
|
"Cancel": "انصراف",
|
||||||
|
"Markdown Note": "Markdown یادداشتِ",
|
||||||
|
"This format is for creating text documents. Checklists, code blocks and Latex blocks are available.": "این قالب برای ساخت سند های متنی است. چک لیست ها و تکه کد ها و بلاک های لاتکس قابل استفاده اند.",
|
||||||
|
"Snippet Note": "Snippet یادداشتِ",
|
||||||
|
"This format is for creating code snippets. Multiple snippets can be grouped into a single note.": "این قالب برای ساخت تکه کد هاست. چند تکه کد میتوانند تبدیل به یک یادداشت شوند.",
|
||||||
|
"Tab to switch format": "را بزنید Tab برای تغییر فرمت",
|
||||||
|
"Updated": "بروزرسانی شد",
|
||||||
|
"Created": "ایجاد شد",
|
||||||
|
"Alphabetically": "بر اساس حروف الفبا",
|
||||||
|
"Counter": "شمارشگر",
|
||||||
|
"Default View": "نمایش پیشفرض",
|
||||||
|
"Compressed View": "نمایش فشرده",
|
||||||
|
"Search": "جستجو",
|
||||||
|
"Blog Type": "نوع وبلاگ",
|
||||||
|
"Blog Address": "آدرس وبلاگ",
|
||||||
|
"Save": "ذخیره",
|
||||||
|
"Auth": "هویت",
|
||||||
|
"Authentication Method": "متد احراز هویت",
|
||||||
|
"JWT": "JWT",
|
||||||
|
"USER": "کاربر",
|
||||||
|
"Token": "توکن",
|
||||||
|
"Storage": "ذخیره سازی",
|
||||||
|
"Hotkeys": "کلید های میانبر",
|
||||||
|
"Show/Hide Boostnote": "Boostnote نمایش/پنهان کردن",
|
||||||
|
"Restore": "بازگرداندن به حالت اول",
|
||||||
|
"Permanent Delete": "حذف بدون بازگشت",
|
||||||
|
"Confirm note deletion": ".حذف یادداشت را تایید کنید",
|
||||||
|
"This will permanently remove this note.": ".این کار یادداشت را بطور دائمی حذف خواهد کرد",
|
||||||
|
"Successfully applied!": "!با موفقیت اجرا شد",
|
||||||
|
"Albanian": "آلبانی",
|
||||||
|
"Chinese (zh-CN)": "چینی (zh-CN)",
|
||||||
|
"Chinese (zh-TW)": "چینی (zh-TW)",
|
||||||
|
"Danish": "دانمارکی",
|
||||||
|
"Japanese": "ژاپنی",
|
||||||
|
"Korean": "کره ای",
|
||||||
|
"Norwegian": "نروژی",
|
||||||
|
"Polish": "لهستانی",
|
||||||
|
"Portuguese": "پرتغالی",
|
||||||
|
"Spanish": "اسپانیایی",
|
||||||
|
"You have to save!": "!باید ذخیره کنید",
|
||||||
|
"UserName": "نام کاربری",
|
||||||
|
"Password": "رمز عبور",
|
||||||
|
"Russian": "روسی",
|
||||||
|
"Command(⌘)": "Command(⌘)",
|
||||||
|
"Editor Rulers": "Editor Rulers",
|
||||||
|
"Enable": "فعال",
|
||||||
|
"Disable": "غیرفعال",
|
||||||
|
"Sanitization": "پاکسازی کردن",
|
||||||
|
"Only allow secure html tags (recommended)": "(فقط تگ های امن اچ تی ام ال مجاز اند.(پیشنهاد میشود",
|
||||||
|
"Allow styles": "حالت های مجاز",
|
||||||
|
"Allow dangerous html tags": "تگ های خطرناک اچ تی ام ال مجاز اند"
|
||||||
|
}
|
||||||
156
locales/it.json
Normal file
@@ -0,0 +1,156 @@
|
|||||||
|
{
|
||||||
|
"Notes": "Note",
|
||||||
|
"Tags": "Tags",
|
||||||
|
"Preferences": "Preferenze",
|
||||||
|
"Make a note": "Crea una nota",
|
||||||
|
"Ctrl": "Ctrl",
|
||||||
|
"Ctrl(^)": "Ctrl",
|
||||||
|
"to create a new note": "per creare una nuova nota",
|
||||||
|
"Toggle Mode": "Cambia Modalità",
|
||||||
|
"Trash": "Cestino",
|
||||||
|
"MODIFICATION DATE": "DATA DI MODIFICA",
|
||||||
|
"Words": "Parole",
|
||||||
|
"Letters": "Lettere",
|
||||||
|
"STORAGE": "POSIZIONE",
|
||||||
|
"FOLDER": "CARTELLA",
|
||||||
|
"CREATION DATE": "DATA DI CREAZIONE",
|
||||||
|
"NOTE LINK": "LINK NOTA",
|
||||||
|
".md": ".md",
|
||||||
|
".txt": ".txt",
|
||||||
|
".html": ".html",
|
||||||
|
"Print": "Stampa",
|
||||||
|
"Your preferences for Boostnote": "Le tue preferenze per Boostnote",
|
||||||
|
"Storages": "Posizioni",
|
||||||
|
"Add Storage Location": "Aggiungi posizione",
|
||||||
|
"Add Folder": "Aggiungi cartella",
|
||||||
|
"Open Storage folder": "Apri cartella di memoria",
|
||||||
|
"Unlink": "Scollega",
|
||||||
|
"Edit": "Modifica",
|
||||||
|
"Delete": "Elimina",
|
||||||
|
"Interface": "Interfaccia",
|
||||||
|
"Interface Theme": "Tema interfaccia",
|
||||||
|
"Default": "Default",
|
||||||
|
"White": "White",
|
||||||
|
"Solarized Dark": "Solarized Dark",
|
||||||
|
"Dark": "Dark",
|
||||||
|
"Show a confirmation dialog when deleting notes": "Mostra finestra di conferma quando elimini delle note",
|
||||||
|
"Editor Theme": "Tema dell'Editor",
|
||||||
|
"Editor Font Size": "Dimensione font dell'editor",
|
||||||
|
"Editor Font Family": "Famiglia del font dell'editor",
|
||||||
|
"Editor Indent Style": "Stile di indentazione dell'editor",
|
||||||
|
"Spaces": "Spazi",
|
||||||
|
"Tabs": "Tabs",
|
||||||
|
"Switch to Preview": "Passa all'anteprima",
|
||||||
|
"When Editor Blurred": "Quando l'editor è sfocato",
|
||||||
|
"When Editor Blurred, Edit On Double Click": "Quando l'Editor è sfocato, Modifica facendo doppio click",
|
||||||
|
"On Right Click": "Cliccando con il tasto destro",
|
||||||
|
"Editor Keymap": "keymapping dell'editor",
|
||||||
|
"default": "default",
|
||||||
|
"vim": "vim",
|
||||||
|
"emacs": "emacs",
|
||||||
|
"⚠️ Please restart boostnote after you change the keymap": "⚠️ Riavvia Boostnote dopo aver cambiato il keymapping",
|
||||||
|
"Show line numbers in the editor": "Mostra numero di linea nell'editor",
|
||||||
|
"Allow editor to scroll past the last line": "Consenti scrolling oltre l'ultima linea nell'editor",
|
||||||
|
"Bring in web page title when pasting URL on editor": "Mostra il titolo della pagina web quando incolli un URL nell'editor",
|
||||||
|
"Preview": "Anteprima",
|
||||||
|
"Preview Font Size": "Dimensione font nell'anteprima",
|
||||||
|
"Preview Font Family": "Famiglia del font dell'anteprima",
|
||||||
|
"Code block Theme": "Tema blocco di codice",
|
||||||
|
"Allow preview to scroll past the last line": "Consenti scrolling oltre l'ultima linea",
|
||||||
|
"Show line numbers for preview code blocks": "Mostra numero di linea per i blocchi di codice nell'Anteprima",
|
||||||
|
"LaTeX Inline Open Delimiter": "Delimitatore inline per apertura LaTex",
|
||||||
|
"LaTeX Inline Close Delimiter": "Delimitatore inline per chiusura LaTex",
|
||||||
|
"LaTeX Block Open Delimiter": "Delimitatore apertura LaTex",
|
||||||
|
"LaTeX Block Close Delimiter": "Delimitatore chiusura LaTex",
|
||||||
|
"Community": "Community",
|
||||||
|
"Subscribe to Newsletter": "Iscriviti alla Newsletter",
|
||||||
|
"GitHub": "GitHub",
|
||||||
|
"Blog": "Blog",
|
||||||
|
"Facebook Group": "Gruppo Facebook",
|
||||||
|
"Twitter": "Twitter",
|
||||||
|
"About": "About",
|
||||||
|
"Boostnote": "Boostnote",
|
||||||
|
"An open source note-taking app made for programmers just like you.": "Un'app open-source per prendere appunti, fatta per sviluppatori come te.",
|
||||||
|
"Website": "Sito Web",
|
||||||
|
"Development": "Sviluppo",
|
||||||
|
" : Development configurations for Boostnote.": " : Configurazioni di sviluppo per Boostnote.",
|
||||||
|
"Copyright (C) 2017 - 2018 BoostIO": "Copyright (C) 2017 - 2018 BoostIO",
|
||||||
|
"License: GPL v3": "Licenza: GPL v3",
|
||||||
|
"Analytics": "Statistiche",
|
||||||
|
"Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.": "Boostnote raccoglie dati anonimi al solo scopo di migliorare l'applicazione, e non raccoglie nessuna informazione personale rigurado il contenuto delle note.",
|
||||||
|
"You can see how it works on ": "Ypuoi vedere come su ",
|
||||||
|
"You can choose to enable or disable this option.": "Puoi scegliere se attivare o disattivare questa opzione.",
|
||||||
|
"Enable analytics to help improve Boostnote": "Attiva raccolta dati per aiutare a migliorare Boostnote",
|
||||||
|
"Crowdfunding": "Crowdfunding",
|
||||||
|
"Dear everyone,": "Cari utenti,",
|
||||||
|
"Thank you for using Boostnote!": "Grazie per stare utilizzando Boostnote!",
|
||||||
|
"Boostnote is used in about 200 different countries and regions by an awesome community of developers.": "Boostnote è usato in circa 200 Paesi da una fantastica community di sviluppatori.",
|
||||||
|
"To continue supporting this growth, and to satisfy community expectations,": "Per continuare a supportarne la crescita, e per soddisfare le aspettative della comunità,",
|
||||||
|
"we would like to invest more time and resources in this project.": "ci piacerebbe investire più tempo e risorse in questo progetto.",
|
||||||
|
"If you like this project and see its potential, you can help by supporting us on OpenCollective!": "Se ti piace questo progetto e ci vedi del potenziale, puoi aiutarci dandodci supporto su OpenCollective!",
|
||||||
|
"Thanks,": "Grazie,",
|
||||||
|
"Boostnote maintainers": "I mantainers di Boostnote",
|
||||||
|
"Support via OpenCollective": "Supporta su OpenCollective",
|
||||||
|
"Language": "Lingua",
|
||||||
|
"English": "Inglese",
|
||||||
|
"German": "Tedesco",
|
||||||
|
"French": "Francese",
|
||||||
|
"Show \"Saved to Clipboard\" notification when copying": "Mostra la notifica \"Salvato negli Appunti\" quando copi:",
|
||||||
|
"All Notes": "Tutte le note",
|
||||||
|
"Starred": "Contribuite",
|
||||||
|
"Are you sure to ": "Sei sicuro di ",
|
||||||
|
" delete": " eliminare",
|
||||||
|
"this folder?": "questa cartella?",
|
||||||
|
"Confirm": "Conferma",
|
||||||
|
"Cancel": "Cancella",
|
||||||
|
"Markdown Note": "Nota in Markdown",
|
||||||
|
"This format is for creating text documents. Checklists, code blocks and Latex blocks are available.": "Questo formato è per creare documenti di testo. Sono disponibili checklist, blocchi di codice and blocchi in Latex",
|
||||||
|
"Snippet Note": "Nota Snippet",
|
||||||
|
"This format is for creating code snippets. Multiple snippets can be grouped into a single note.": "Questo formato è per creare snippets. Più snippet possono essere raccolti in un'unica nota.",
|
||||||
|
"Tab to switch format": "Premi Tab per cambiare formato",
|
||||||
|
"Updated": "Aggiornato",
|
||||||
|
"Created": "Creato",
|
||||||
|
"Alphabetically": "Ordine alfabetico",
|
||||||
|
"Counter": "Contatore",
|
||||||
|
"Default View": "Visione di default",
|
||||||
|
"Compressed View": "Visione compressa",
|
||||||
|
"Search": "Cerca",
|
||||||
|
"Blog Type": "Tipo di blog",
|
||||||
|
"Blog Address": "Indirizzo del blog",
|
||||||
|
"Save": "Salva",
|
||||||
|
"Auth": "Autorizzazione",
|
||||||
|
"Authentication Method": "Metodo di autenticazione",
|
||||||
|
"JWT": "JWT",
|
||||||
|
"USER": "USER",
|
||||||
|
"Token": "Token",
|
||||||
|
"Storage": "Storage",
|
||||||
|
"Hotkeys": "Hotkeys",
|
||||||
|
"Show/Hide Boostnote": "Mostra/Nascondi Boostnote",
|
||||||
|
"Restore": "Ripristina",
|
||||||
|
"Permanent Delete": "Elimina permanentemente",
|
||||||
|
"Confirm note deletion": "Conferma eliiminazione della nota",
|
||||||
|
"This will permanently remove this note.": "Questo eliminerà permanentemente questa nota.",
|
||||||
|
"Successfully applied!": "Applicato con successo!",
|
||||||
|
"Albanian": "Albanese",
|
||||||
|
"Chinese (zh-CN)": "Cinese (zh-CN)",
|
||||||
|
"Chinese (zh-TW)": "Cinese (zh-TW)",
|
||||||
|
"Danish": "Danese",
|
||||||
|
"Japanese": "Giapponese",
|
||||||
|
"Korean": "Koreano",
|
||||||
|
"Norwegian": "Novergese",
|
||||||
|
"Polish": "Polacco",
|
||||||
|
"Portuguese": "Portoghese",
|
||||||
|
"Spanish": "Spagnolo",
|
||||||
|
"You have to save!": "Devi salvare!",
|
||||||
|
"UserName": "UserName",
|
||||||
|
"Password": "Password",
|
||||||
|
"Russian": "Russo",
|
||||||
|
"Command(⌘)": "Comando(⌘)",
|
||||||
|
"Editor Rulers": "Regole dell'editor",
|
||||||
|
"Enable": "Abilita",
|
||||||
|
"Disable": "Disabilia",
|
||||||
|
"Sanitization": "Bonifica",
|
||||||
|
"Only allow secure html tags (recommended)": "Consenti solo tag HTML sicuri (raccomandato)",
|
||||||
|
"Allow styles": "Consenti stili",
|
||||||
|
"Allow dangerous html tags": "Consenti tag HTML pericolosi"
|
||||||
|
}"
|
||||||
274
locales/ja.json
@@ -1,153 +1,153 @@
|
|||||||
{
|
{
|
||||||
"Notes": "Notes",
|
"Notes": "ノート",
|
||||||
"Tags": "Tags",
|
"Tags": "タグ",
|
||||||
"Preferences": "Preferences",
|
"Preferences": "設定",
|
||||||
"Make a note": "Make a note",
|
"Make a note": "ノート作成",
|
||||||
"Ctrl": "Ctrl",
|
"Ctrl": "Ctrl",
|
||||||
"Ctrl(^)": "Ctrl",
|
"Ctrl(^)": "Ctrl",
|
||||||
"to create a new note": "to create a new note",
|
"to create a new note": "ノートを新規に作成",
|
||||||
"Toggle Mode": "Toggle Mode",
|
"Toggle Mode": "モード切替",
|
||||||
"Trash": "Trash",
|
"Trash": "ゴミ箱",
|
||||||
"MODIFICATION DATE": "MODIFICATION DATE",
|
"MODIFICATION DATE": "修正日",
|
||||||
"Words": "Words",
|
"Words": "ワード",
|
||||||
"Letters": "Letters",
|
"Letters": "文字",
|
||||||
"STORAGE": "STORAGE",
|
"STORAGE": "ストレージ",
|
||||||
"FOLDER": "FOLDER",
|
"FOLDER": "フォルダ",
|
||||||
"CREATION DATE": "CREATION DATE",
|
"CREATION DATE": "作成日",
|
||||||
"NOTE LINK": "NOTE LINK",
|
"NOTE LINK": "リンク",
|
||||||
".md": ".md",
|
".md": ".md",
|
||||||
".txt": ".txt",
|
".txt": ".txt",
|
||||||
".html": ".html",
|
".html": ".html",
|
||||||
"Print": "Print",
|
"Print": "印刷",
|
||||||
"Your preferences for Boostnote": "Your preferences for Boostnote",
|
"Your preferences for Boostnote": "Boostnoteの個人設定",
|
||||||
"Storages": "Storages",
|
"Storages": "ストレージ",
|
||||||
"Add Storage Location": "Add Storage Location",
|
"Add Storage Location": "ストレージロケーションを追加",
|
||||||
"Add Folder": "Add Folder",
|
"Add Folder": "フォルダを追加",
|
||||||
"Open Storage folder": "Open Storage folder",
|
"Open Storage folder": "ストレージフォルダを開く",
|
||||||
"Unlink": "Unlink",
|
"Unlink": "リンク解除",
|
||||||
"Edit": "Edit",
|
"Edit": "編集",
|
||||||
"Delete": "Delete",
|
"Delete": "削除",
|
||||||
"Interface": "Interface",
|
"Interface": "インターフェース",
|
||||||
"Interface Theme": "Interface Theme",
|
"Interface Theme": "インターフェーステーマ",
|
||||||
"Default": "Default",
|
"Default": "デフォルト",
|
||||||
"White": "White",
|
"White": "白",
|
||||||
"Solarized Dark": "Solarized Dark",
|
"Solarized Dark": "明灰",
|
||||||
"Dark": "Dark",
|
"Dark": "暗灰",
|
||||||
"Show a confirmation dialog when deleting notes": "Show a confirmation dialog when deleting notes",
|
"Show a confirmation dialog when deleting notes": "ノートを削除する時に確認ダイアログを表示する",
|
||||||
"Editor Theme": "Editor Theme",
|
"Editor Theme": "エディタのテーマ",
|
||||||
"Editor Font Size": "Editor Font Size",
|
"Editor Font Size": "エディタのフォントサイズ",
|
||||||
"Editor Font Family": "Editor Font Family",
|
"Editor Font Family": "エディタのフォント",
|
||||||
"Editor Indent Style": "Editor Indent Style",
|
"Editor Indent Style": "エディタのインデント方法",
|
||||||
"Spaces": "Spaces",
|
"Spaces": "スペース",
|
||||||
"Tabs": "Tabs",
|
"Tabs": "タブ",
|
||||||
"Switch to Preview": "Switch to Preview",
|
"Switch to Preview": "プレビューへ移動",
|
||||||
"When Editor Blurred": "When Editor Blurred",
|
"When Editor Blurred": "エディタがフォーカスを失った時",
|
||||||
"When Editor Blurred, Edit On Double Click": "When Editor Blurred, Edit On Double Click",
|
"When Editor Blurred, Edit On Double Click": "エディタがフォーカスを失った時、ダブルクリックで編集",
|
||||||
"On Right Click": "On Right Click",
|
"On Right Click": "右クリック",
|
||||||
"Editor Keymap": "Editor Keymap",
|
"Editor Keymap": "エディタのキーマップ",
|
||||||
"default": "default",
|
"default": "デフォルト",
|
||||||
"vim": "vim",
|
"vim": "vim",
|
||||||
"emacs": "emacs",
|
"emacs": "emacs",
|
||||||
"⚠️ Please restart boostnote after you change the keymap": "⚠️ Please restart boostnote after you change the keymap",
|
"⚠️ Please restart boostnote after you change the keymap": "⚠️ Plキーマップ変更後は Boostnote を再起動してください",
|
||||||
"Show line numbers in the editor": "Show line numbers in the editor",
|
"Show line numbers in the editor": "エディタ内に行番号を表示",
|
||||||
"Allow editor to scroll past the last line": "Allow editor to scroll past the last line",
|
"Allow editor to scroll past the last line": "エディタが最終行以降にスクロールできるようにする",
|
||||||
"Bring in web page title when pasting URL on editor": "Bring in web page title when pasting URL on editor",
|
"Bring in web page title when pasting URL on editor": "Bring in web page title when pasting URL on editor",
|
||||||
"Preview": "Preview",
|
"Preview": "プレビュー",
|
||||||
"Preview Font Size": "Preview Font Size",
|
"Preview Font Size": "プレビュー時フォントサイズ",
|
||||||
"Preview Font Family": "Preview Font Family",
|
"Preview Font Family": "プレビュー時フォント",
|
||||||
"Code block Theme": "Code block Theme",
|
"Code block Theme": "コードブロックのテーマ",
|
||||||
"Allow preview to scroll past the last line": "Allow preview to scroll past the last line",
|
"Allow preview to scroll past the last line": "プレビュー時に最終行以降にスクロールできるようにする",
|
||||||
"Show line numbers for preview code blocks": "Show line numbers for preview code blocks",
|
"Show line numbers for preview code blocks": "プレビュー時のコードブロック内に行番号を表示する",
|
||||||
"LaTeX Inline Open Delimiter": "LaTeX Inline Open Delimiter",
|
"LaTeX Inline Open Delimiter": "LaTeX 開始デリミタ(インライン)Inline Open Delimiter",
|
||||||
"LaTeX Inline Close Delimiter": "LaTeX Inline Close Delimiter",
|
"LaTeX Inline Close Delimiter": "LaTeX 終了デリミタ(インライン)",
|
||||||
"LaTeX Block Open Delimiter": "LaTeX Block Open Delimiter",
|
"LaTeX Block Open Delimiter": "LaTeX 開始デリミタ(ブロック)",
|
||||||
"LaTeX Block Close Delimiter": "LaTeX Block Close Delimiter",
|
"LaTeX Block Close Delimiter": "LaTeX 終了デリミタ(ブロック)",
|
||||||
"Community": "Community",
|
"Community": "コミュニティ",
|
||||||
"Subscribe to Newsletter": "Subscribe to Newsletter",
|
"Subscribe to Newsletter": "ニュースレターを購読する",
|
||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Blog": "Blog",
|
"Blog": "ブログ",
|
||||||
"Facebook Group": "Facebook Group",
|
"Facebook Group": "Facebook グループ",
|
||||||
"Twitter": "Twitter",
|
"Twitter": "Twitter",
|
||||||
"About": "About",
|
"About": "について",
|
||||||
"Boostnote": "Boostnote",
|
"Boostnote": "Boostnote",
|
||||||
"An open source note-taking app made for programmers just like you.": "An open source note-taking app made for programmers just like you.",
|
"An open source note-taking app made for programmers just like you.": "あなたのようなプログラマー向けのオープンソースメモ書きアプリケーション",
|
||||||
"Website": "Website",
|
"Website": "ウェブサイト",
|
||||||
"Development": "Development",
|
"Development": "開発",
|
||||||
" : Development configurations for Boostnote.": " : Development configurations for Boostnote.",
|
" : Development configurations for Boostnote.": " : Boostnote の開発構成",
|
||||||
"Copyright (C) 2017 - 2018 BoostIO": "Copyright (C) 2017 - 2018 BoostIO",
|
"Copyright (C) 2017 - 2018 BoostIO": "Copyright (C) 2017 - 2018 BoostIO",
|
||||||
"License: GPL v3": "License: GPL v3",
|
"License: GPL v3": "ライセンス: GPL v3",
|
||||||
"Analytics": "Analytics",
|
"Analytics": "解析",
|
||||||
"Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.": "Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.",
|
"Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.": "Boostnote はアプリケーションの機能向上だけを目的に匿名データを収集します。ノートの内容を含めた個人の情報は一切収集しません。",
|
||||||
"You can see how it works on ": "You can see how it works on ",
|
"You can see how it works on ": "どのように動くかをこちらで確認できます ",
|
||||||
"You can choose to enable or disable this option.": "You can choose to enable or disable this option.",
|
"You can choose to enable or disable this option.": "このオプションは有効/無効を選択できます。",
|
||||||
"Enable analytics to help improve Boostnote": "Enable analytics to help improve Boostnote",
|
"Enable analytics to help improve Boostnote": "Boostnote の機能向上のための解析機能を有効にする",
|
||||||
"Crowdfunding": "Crowdfunding",
|
"Crowdfunding": "クラウドファンディング",
|
||||||
"Dear everyone,": "Dear everyone,",
|
"Dear everyone,": "Dear everyone,",
|
||||||
"Thank you for using Boostnote!": "Thank you for using Boostnote!",
|
"Thank you for using Boostnote!": "Boostnote を利用いただき、ありがとうございます!",
|
||||||
"Boostnote is used in about 200 different countries and regions by an awesome community of developers.": "Boostnote is used in about 200 different countries and regions by an awesome community of developers.",
|
"Boostnote is used in about 200 different countries and regions by an awesome community of developers.": "Boostnote はおよそ 200 の国と地域において、開発者コミュニティを中心に利用されています。",
|
||||||
"To continue supporting this growth, and to satisfy community expectations,": "To continue supporting this growth, and to satisfy community expectations,",
|
"To continue supporting this growth, and to satisfy community expectations,": "この成長を持続し、またコミュニティからの要望に答えるため、",
|
||||||
"we would like to invest more time and resources in this project.": "we would like to invest more time and resources in this project.",
|
"we would like to invest more time and resources in this project.": "私達はこのプロジェクトにより多くの時間とリソースを投資したいと考えています。",
|
||||||
"If you like this project and see its potential, you can help by supporting us on OpenCollective!": "If you like this project and see its potential, you can help by supporting us on OpenCollective!",
|
"If you like this project and see its potential, you can help by supporting us on OpenCollective!": "もしあなたがこのプロジェクトとそのポテンシャルを気に入っていただけたのであれば、OpenCollective を通じて支援いただくことができます!",
|
||||||
"Thanks,": "Thanks,",
|
"Thanks,": "ありがとうございます。",
|
||||||
"Boostnote maintainers": "Boostnote maintainers",
|
"Boostnote maintainers": "Boostnote メンテナンスチーム",
|
||||||
"Support via OpenCollective": "Support via OpenCollective",
|
"Support via OpenCollective": "OpenCollective を通じて支援します",
|
||||||
"Language": "Language",
|
"Language": "言語",
|
||||||
"English": "English",
|
"English": "英語",
|
||||||
"German": "German",
|
"German": "ドイツ語",
|
||||||
"French": "French",
|
"French": "フランス語",
|
||||||
"Show \"Saved to Clipboard\" notification when copying": "Show \"Saved to Clipboard\" notification when copying",
|
"Show \"Saved to Clipboard\" notification when copying": "クリップボードコピー時に \"クリップボードに保存\" 通知を表示する",
|
||||||
"All Notes": "All Notes",
|
"All Notes": "すべてのノート",
|
||||||
"Starred": "Starred",
|
"Starred": "スター付き",
|
||||||
"Are you sure to ": "Are you sure to ",
|
"Are you sure to ": "本当に ",
|
||||||
" delete": " delete",
|
" delete": "このフォルダを",
|
||||||
"this folder?": "this folder?",
|
"this folder?": "削除しますか?",
|
||||||
"Confirm": "Confirm",
|
"Confirm": "確認",
|
||||||
"Cancel": "Cancel",
|
"Cancel": "キャンセル",
|
||||||
"Markdown Note": "Markdown Note",
|
"Markdown Note": "マークダウン",
|
||||||
"This format is for creating text documents. Checklists, code blocks and Latex blocks are available.": "This format is for creating text documents. Checklists, code blocks and Latex blocks are available.",
|
"This format is for creating text documents. Checklists, code blocks and Latex blocks are available.": "このフォーマットはテキスト文書を作成することを目的としています。チェックリストや比較的長いコード、LaTeX にも向いています。",
|
||||||
"Snippet Note": "Snippet Note",
|
"Snippet Note": "スニペット",
|
||||||
"This format is for creating code snippets. Multiple snippets can be grouped into a single note.": "This format is for creating code snippets. Multiple snippets can be grouped into a single note.",
|
"This format is for creating code snippets. Multiple snippets can be grouped into a single note.": "このフォーマットは短いコードスニペットを作成することを目的としています。複数のコードスニペットを1つのグループにまとめて1つのノートとして扱うことも可能です。",
|
||||||
"Tab to switch format": "Tab to switch format",
|
"Tab to switch format": "フォーマット切り替えタブ",
|
||||||
"Updated": "Updated",
|
"Updated": "更新日時",
|
||||||
"Created": "Created",
|
"Created": "作成日時",
|
||||||
"Alphabetically": "Alphabetically",
|
"Alphabetically": "アルファベット順",
|
||||||
"Default View": "Default View",
|
"Default View": "デフォルトビュー",
|
||||||
"Compressed View": "Compressed View",
|
"Compressed View": "圧縮ビュー",
|
||||||
"Search": "Search",
|
"Search": "検索",
|
||||||
"Blog Type": "Blog Type",
|
"Blog Type": "ブログの種類",
|
||||||
"Blog Address": "Blog Address",
|
"Blog Address": "ブログのアドレス",
|
||||||
"Save": "Save",
|
"Save": "保存",
|
||||||
"Auth": "Auth",
|
"Auth": "認証",
|
||||||
"Authentication Method": "Authentication Method",
|
"Authentication Method": "認証方法",
|
||||||
"JWT": "JWT",
|
"JWT": "JWT",
|
||||||
"USER": "USER",
|
"USER": "ユーザー",
|
||||||
"Token": "Token",
|
"Token": "トークン",
|
||||||
"Storage": "Storage",
|
"Storage": "ストレージ",
|
||||||
"Hotkeys": "Hotkeys",
|
"Hotkeys": "ホットキー",
|
||||||
"Show/Hide Boostnote": "Show/Hide Boostnote",
|
"Show/Hide Boostnote": "Boostnote の表示/非表示",
|
||||||
"Restore": "Restore",
|
"Restore": "リストア",
|
||||||
"Permanent Delete": "Permanent Delete",
|
"Permanent Delete": "永久に削除",
|
||||||
"Confirm note deletion": "Confirm note deletion",
|
"Confirm note deletion": "ノート削除確認",
|
||||||
"This will permanently remove this note.": "This will permanently remove this note.",
|
"This will permanently remove this note.": "本当にこのノートを削除します。",
|
||||||
"Successfully applied!": "Successfully applied!",
|
"Successfully applied!": "成功しました!",
|
||||||
"Albanian": "Albanian",
|
"Albanian": "アルバニア語",
|
||||||
"Chinese (zh-CN)": "Chinese (zh-CN)",
|
"Chinese (zh-CN)": "簡体字中国語 (zh-CN)",
|
||||||
"Chinese (zh-TW)": "Chinese (zh-TW)",
|
"Chinese (zh-TW)": "繁体字中国語 (zh-TW)",
|
||||||
"Danish": "Danish",
|
"Danish": "デンマーク語",
|
||||||
"Japanese": "Japanese",
|
"Japanese": "日本語",
|
||||||
"Korean": "Korean",
|
"Korean": "韓国語",
|
||||||
"Norwegian": "Norwegian",
|
"Norwegian": "ノルウェー語",
|
||||||
"Polish": "Polish",
|
"Polish": "ポーランド語",
|
||||||
"Portuguese": "Portuguese",
|
"Portuguese": "ポルトガル語",
|
||||||
"Spanish": "Spanish",
|
"Spanish": "スペイン語",
|
||||||
"You have to save!": "You have to save!",
|
"You have to save!": "保存してください!",
|
||||||
"Russian": "Russian",
|
"Russian": "ロシア語",
|
||||||
"Command(⌘)": "Command(⌘)",
|
"Command(⌘)": "コマンド(⌘)",
|
||||||
"Editor Rulers": "Editor Rulers",
|
"Editor Rulers": "罫線",
|
||||||
"Enable": "Enable",
|
"Enable": "有効",
|
||||||
"Disable": "Disable",
|
"Disable": "無効",
|
||||||
"Sanitization": "Sanitization",
|
"Sanitization": "サニタイズ",
|
||||||
"Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)",
|
"Only allow secure html tags (recommended)": "安全なHTMLタグのみ利用を許可する(推奨)",
|
||||||
"Allow styles": "Allow styles",
|
"Allow styles": "スタイルを許可する",
|
||||||
"Allow dangerous html tags": "Allow dangerous html tags"
|
"Allow dangerous html tags": "安全でないHTMLタグの利用を許可する"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,91 +1,91 @@
|
|||||||
{
|
{
|
||||||
"Notes": "筆記",
|
"Notes": "筆記",
|
||||||
"Tags": "標籤",
|
"Tags": "標籤",
|
||||||
"Preferences": "首選項",
|
"Preferences": "偏好設定",
|
||||||
"Make a note": "新建筆記",
|
"Make a note": "做點筆記",
|
||||||
"Ctrl": "Ctrl",
|
"Ctrl": "Ctrl",
|
||||||
"Ctrl(^)": "Ctrl",
|
"Ctrl(^)": "Ctrl",
|
||||||
"to create a new note": "新建筆記",
|
"to create a new note": "新增筆記",
|
||||||
"Toggle Mode": "切換模式",
|
"Toggle Mode": "切換模式",
|
||||||
"Trash": "廢紙簍",
|
"Trash": "廢紙簍",
|
||||||
"MODIFICATION DATE": "更改時間",
|
"MODIFICATION DATE": "修改時間",
|
||||||
"Words": "單詞",
|
"Words": "單字",
|
||||||
"Letters": "字數",
|
"Letters": "字數",
|
||||||
"STORAGE": "本地儲存",
|
"STORAGE": "本機儲存空間",
|
||||||
"FOLDER": "資料夾",
|
"FOLDER": "資料夾",
|
||||||
"CREATION DATE": "創建時間",
|
"CREATION DATE": "建立時間",
|
||||||
"NOTE LINK": "筆記鏈接",
|
"NOTE LINK": "筆記連結",
|
||||||
".md": ".md",
|
".md": ".md",
|
||||||
".txt": ".txt",
|
".txt": ".txt",
|
||||||
".html": ".html",
|
".html": ".html",
|
||||||
"Print": "列印",
|
"Print": "列印",
|
||||||
"Your preferences for Boostnote": "個性設置",
|
"Your preferences for Boostnote": "Boostnote 偏好設定",
|
||||||
"Storages": "本地儲存",
|
"Storages": "本機儲存空間",
|
||||||
"Add Storage Location": "添加一個本地儲存位置",
|
"Add Storage Location": "新增一個本機儲存位置",
|
||||||
"Add Folder": "新建資料夾",
|
"Add Folder": "新增資料夾",
|
||||||
"Open Storage folder": "打開一個本地儲存位置",
|
"Open Storage folder": "開啟儲存資料夾",
|
||||||
"Unlink": "取消鏈接",
|
"Unlink": "解除連結",
|
||||||
"Edit": "編輯",
|
"Edit": "編輯",
|
||||||
"Delete": "刪除",
|
"Delete": "刪除",
|
||||||
"Interface": "界面",
|
"Interface": "界面",
|
||||||
"Interface Theme": "主題",
|
"Interface Theme": "主題",
|
||||||
"Default": "默認",
|
"Default": "預設",
|
||||||
"White": "White",
|
"White": "White",
|
||||||
"Solarized Dark": "Solarized Dark",
|
"Solarized Dark": "Solarized Dark",
|
||||||
"Dark": "Dark",
|
"Dark": "Dark",
|
||||||
"Show a confirmation dialog when deleting notes": "刪除筆記的時候,顯示確認框",
|
"Show a confirmation dialog when deleting notes": "刪除筆記的時候,顯示確認對話框",
|
||||||
"Editor Theme": "編輯器主題",
|
"Editor Theme": "編輯器主題",
|
||||||
"Editor Font Size": "編輯器字型大小",
|
"Editor Font Size": "編輯器字型大小",
|
||||||
"Editor Font Family": "編輯器字體",
|
"Editor Font Family": "編輯器字體",
|
||||||
"Editor Indent Style": "縮進風格",
|
"Editor Indent Style": "縮排風格",
|
||||||
"Spaces": "空格",
|
"Spaces": "空格",
|
||||||
"Tabs": "Tabs",
|
"Tabs": "Tabs",
|
||||||
"Switch to Preview": "快速切換到預覽界面",
|
"Switch to Preview": "切回預覽頁面的時機",
|
||||||
"When Editor Blurred": "當編輯器失去焦點的時候,切換到預覽界面",
|
"When Editor Blurred": "當編輯器失去焦點時",
|
||||||
"When Editor Blurred, Edit On Double Click": "當編輯器失去焦點的時候預覽,雙擊切換到編輯界面",
|
"When Editor Blurred, Edit On Double Click": "當編輯器失去焦點時,雙擊切換到編輯畫面",
|
||||||
"On Right Click": "右鍵點擊切換兩個界面",
|
"On Right Click": "點擊右鍵切換兩個頁面",
|
||||||
"Editor Keymap": "編輯器 Keymap",
|
"Editor Keymap": "編輯器 Keymap",
|
||||||
"default": "默認",
|
"default": "預設",
|
||||||
"vim": "vim",
|
"vim": "vim",
|
||||||
"emacs": "emacs",
|
"emacs": "emacs",
|
||||||
"⚠️ Please restart boostnote after you change the keymap": "⚠️ 設置好快捷鍵後,記得重啟设置好快捷键后,记得重启boostnote",
|
"⚠️ Please restart boostnote after you change the keymap": "⚠️ 請重新開啟 Boostnote 以完成設定。",
|
||||||
"Show line numbers in the editor": "在編輯器中顯示行號",
|
"Show line numbers in the editor": "在編輯器中顯示行號",
|
||||||
"Allow editor to scroll past the last line": "允許編輯器滾動到最後一行",
|
"Allow editor to scroll past the last line": "允許編輯器捲軸捲動超過最後一行",
|
||||||
"Bring in web page title when pasting URL on editor": "粘貼網頁鏈接的時候,顯示為網頁標題",
|
"Bring in web page title when pasting URL on editor": "在編輯器貼上網址的時候,自動加上網頁標題",
|
||||||
"Preview": "預覽器",
|
"Preview": "預覽頁面",
|
||||||
"Preview Font Size": "預覽器字型大小",
|
"Preview Font Size": "預覽頁面字型大小",
|
||||||
"Preview Font Family": "預覽器字體",
|
"Preview Font Family": "預覽頁面字體",
|
||||||
"Code block Theme": "代碼塊主題",
|
"Code block Theme": "程式碼區塊主題",
|
||||||
"Allow preview to scroll past the last line": "允許預覽器滾動到最後一行",
|
"Allow preview to scroll past the last line": "允許預覽頁面捲軸捲動超過最後一行",
|
||||||
"Show line numbers for preview code blocks": "在預覽器中顯示行號",
|
"Show line numbers for preview code blocks": "在預覽頁面的程式碼區塊中顯示行號",
|
||||||
"LaTeX Inline Open Delimiter": "LaTeX 單行開頭分隔符",
|
"LaTeX Inline Open Delimiter": "LaTeX 單行開頭符號",
|
||||||
"LaTeX Inline Close Delimiter": "LaTeX 單行結尾分隔符",
|
"LaTeX Inline Close Delimiter": "LaTeX 單行結尾符號",
|
||||||
"LaTeX Block Open Delimiter": "LaTeX 多行開頭分隔符",
|
"LaTeX Block Open Delimiter": "LaTeX 多行開頭符號",
|
||||||
"LaTeX Block Close Delimiter": "LaTeX 多行結尾分隔符",
|
"LaTeX Block Close Delimiter": "LaTeX 多行結尾符號",
|
||||||
"Community": "社區",
|
"Community": "社群",
|
||||||
"Subscribe to Newsletter": "訂閱郵件",
|
"Subscribe to Newsletter": "訂閱郵件",
|
||||||
"GitHub": "GitHub",
|
"GitHub": "GitHub",
|
||||||
"Blog": "部落格",
|
"Blog": "部落格",
|
||||||
"Facebook Group": "Facebook Group",
|
"Facebook Group": "Facebook 社團",
|
||||||
"Twitter": "Twitter",
|
"Twitter": "Twitter",
|
||||||
"About": "關於",
|
"About": "關於",
|
||||||
"Boostnote": "Boostnote",
|
"Boostnote": "Boostnote",
|
||||||
"An open source note-taking app made for programmers just like you.": "一款專門為程式員朋友量身打造的開源筆記",
|
"An open source note-taking app made for programmers just like you.": "一款專門為程式設計師朋友量身打造的開源筆記軟體",
|
||||||
"Website": "官網",
|
"Website": "官網",
|
||||||
"Development": "開發",
|
"Development": "開發",
|
||||||
" : Development configurations for Boostnote.": " : Boostnote的開發配置",
|
" : Development configurations for Boostnote.": " : Boostnote 的開發組態",
|
||||||
"Copyright (C) 2017 - 2018 BoostIO": "Copyright (C) 2017 - 2018 BoostIO",
|
"Copyright (C) 2017 - 2018 BoostIO": "Copyright (C) 2017 - 2018 BoostIO",
|
||||||
"License: GPL v3": "License: GPL v3",
|
"License: GPL v3": "License: GPL v3",
|
||||||
"Analytics": "分析",
|
"Analytics": "分析",
|
||||||
"Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.": "Boostnote 收集匿名數據只為了提升軟體使用體驗,絕對不收集任何個人信息(包括筆記內容)",
|
"Boostnote collects anonymous data for the sole purpose of improving the application, and strictly does not collect any personal information such the contents of your notes.": "Boostnote 收集匿名資料單純只為了提升軟體使用體驗,絕對不收集任何個人資料(包括筆記內容)",
|
||||||
"You can see how it works on ": "你可以看看它的源碼是如何運作的 ",
|
"You can see how it works on ": "你可以看看它的程式碼是如何運作 ",
|
||||||
"You can choose to enable or disable this option.": "你可以選擇開啟或不開啟這個功能",
|
"You can choose to enable or disable this option.": "你可以選擇啟用或禁用這項功能",
|
||||||
"Enable analytics to help improve Boostnote": "允許對數據進行分析,幫助我們改進Boostnote",
|
"Enable analytics to help improve Boostnote": "允許數據分析以協助我們改進 Boostnote",
|
||||||
"Crowdfunding": "眾籌",
|
"Crowdfunding": "群眾募資",
|
||||||
"Dear everyone,": "親愛的用戶:",
|
"Dear everyone,": "親愛的用戶:",
|
||||||
"Thank you for using Boostnote!": "謝謝你使用 Boostnote!",
|
"Thank you for using Boostnote!": "謝謝你使用 Boostnote!",
|
||||||
"Boostnote is used in about 200 different countries and regions by an awesome community of developers.": "大約有 200 個不同的國家和地區的優秀開發者們都在使用 Boostnote!",
|
"Boostnote is used in about 200 different countries and regions by an awesome community of developers.": "大約有 200 個不同的國家和地區的優秀開發者們都在使用 Boostnote!",
|
||||||
"To continue supporting this growth, and to satisfy community expectations,": "為了繼續支持這種發展,和滿足社區的期待,",
|
"To continue supporting this growth, and to satisfy community expectations,": "為了繼續支持這種發展,和滿足社群的期待,",
|
||||||
"we would like to invest more time and resources in this project.": "我們非常願意投入更多的時間和資源到這個專案中。",
|
"we would like to invest more time and resources in this project.": "我們非常願意投入更多的時間和資源到這個專案中。",
|
||||||
"If you like this project and see its potential, you can help by supporting us on OpenCollective!": "如果你喜歡這款軟體並且看好它的潛力, 請在 OpenCollective 上支持我們!",
|
"If you like this project and see its potential, you can help by supporting us on OpenCollective!": "如果你喜歡這款軟體並且看好它的潛力, 請在 OpenCollective 上支持我們!",
|
||||||
"Thanks,": "十分感謝!",
|
"Thanks,": "十分感謝!",
|
||||||
@@ -95,41 +95,41 @@
|
|||||||
"English": "English",
|
"English": "English",
|
||||||
"German": "German",
|
"German": "German",
|
||||||
"French": "French",
|
"French": "French",
|
||||||
"Show \"Saved to Clipboard\" notification when copying": "複製的時候,顯示 \"已複製\" 提示",
|
"Show \"Saved to Clipboard\" notification when copying": "複製的時候,顯示 \"已複製到剪貼簿\" 的通知",
|
||||||
"All Notes": "所有筆記",
|
"All Notes": "所有筆記",
|
||||||
"Starred": "星標收藏",
|
"Starred": "星號收藏",
|
||||||
"Are you sure to ": "你確定要 ",
|
"Are you sure to ": "你確定要 ",
|
||||||
" delete": " 刪除",
|
" delete": " 刪除",
|
||||||
"this folder?": "這個資料夾嗎?",
|
"this folder?": "這個資料夾嗎?",
|
||||||
"Confirm": "確認",
|
"Confirm": "確認",
|
||||||
"Cancel": "取消",
|
"Cancel": "取消",
|
||||||
"Markdown Note": "Markdown 筆記",
|
"Markdown Note": "Markdown 筆記",
|
||||||
"This format is for creating text documents. Checklists, code blocks and Latex blocks are available.": "創建文檔,清單,代碼塊甚至是Latex格式文檔",
|
"This format is for creating text documents. Checklists, code blocks and Latex blocks are available.": "建立文件、清單,也可以使用程式碼區塊甚至是 Latex 區塊。",
|
||||||
"Snippet Note": "代碼筆記",
|
"Snippet Note": "程式碼片段筆記",
|
||||||
"This format is for creating code snippets. Multiple snippets can be grouped into a single note.": "創建代碼片段,支持多種語法代碼片段",
|
"This format is for creating code snippets. Multiple snippets can be grouped into a single note.": "建立程式碼區塊片段。數個程式碼區塊可以合在同一個筆記裡。",
|
||||||
"Tab to switch format": "使用 Tab 鍵切換格式",
|
"Tab to switch format": "使用 Tab 鍵切換格式",
|
||||||
"Updated": "更新時間",
|
"Updated": "依更新時間排序",
|
||||||
"Created": "創建時間",
|
"Created": "依建立時間排序",
|
||||||
"Alphabetically": "A~Z排序",
|
"Alphabetically": "依字母排序",
|
||||||
"Default View": "默認視圖",
|
"Default View": "預設顯示",
|
||||||
"Compressed View": "列表視圖",
|
"Compressed View": "緊密顯示",
|
||||||
"Search": "搜索",
|
"Search": "搜尋",
|
||||||
"Blog Type": "部落格類型",
|
"Blog Type": "部落格類型",
|
||||||
"Blog Address": "部落格地址",
|
"Blog Address": "部落格網址",
|
||||||
"Save": "保存",
|
"Save": "儲存",
|
||||||
"Auth": "Auth",
|
"Auth": "Auth",
|
||||||
"Authentication Method": "認證方法",
|
"Authentication Method": "認證方法",
|
||||||
"JWT": "JWT",
|
"JWT": "JWT",
|
||||||
"USER": "USER",
|
"USER": "USER",
|
||||||
"Token": "Token",
|
"Token": "Token",
|
||||||
"Storage": "本地儲存",
|
"Storage": "本機儲存空間",
|
||||||
"Hotkeys": "快捷鍵",
|
"Hotkeys": "快捷鍵",
|
||||||
"Show/Hide Boostnote": "顯示/隱藏 Boostnote",
|
"Show/Hide Boostnote": "顯示/隱藏 Boostnote",
|
||||||
"Restore": "恢復",
|
"Restore": "還原",
|
||||||
"Permanent Delete": "永久刪除",
|
"Permanent Delete": "永久刪除",
|
||||||
"Confirm note deletion": "確認刪除筆記",
|
"Confirm note deletion": "確認刪除筆記",
|
||||||
"This will permanently remove this note.": "永久地刪除這條筆記",
|
"This will permanently remove this note.": "這將會永久地刪除這條筆記",
|
||||||
"Successfully applied!": "設置成功",
|
"Successfully applied!": "設定成功",
|
||||||
"Albanian": "Albanian",
|
"Albanian": "Albanian",
|
||||||
"Chinese (zh-CN)": "简体中文",
|
"Chinese (zh-CN)": "简体中文",
|
||||||
"Chinese (zh-TW)": "繁體中文",
|
"Chinese (zh-TW)": "繁體中文",
|
||||||
@@ -142,11 +142,11 @@
|
|||||||
"Spanish": "Spanish",
|
"Spanish": "Spanish",
|
||||||
"You have to save!": "你必須儲存一下!",
|
"You have to save!": "你必須儲存一下!",
|
||||||
"Russian": "Russian",
|
"Russian": "Russian",
|
||||||
"Editor Rulers": "Editor Rulers",
|
"Editor Rulers": "編輯器中顯示垂直尺規",
|
||||||
"Enable": "開啟",
|
"Enable": "啟用",
|
||||||
"Disable": "關閉",
|
"Disable": "禁用",
|
||||||
"Sanitization": "代碼處理",
|
"Sanitization": "過濾 HTML 程式碼",
|
||||||
"Only allow secure html tags (recommended)": "只允許安全的html標籤(推薦)",
|
"Only allow secure html tags (recommended)": "只允許安全的 HTML 標籤 (建議)",
|
||||||
"Allow styles": "允許樣式",
|
"Allow styles": "允許樣式",
|
||||||
"Allow dangerous html tags": "允許危險的html標籤"
|
"Allow dangerous html tags": "允許危險的 HTML 標籤"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -92,6 +92,7 @@
|
|||||||
"striptags": "^2.2.1",
|
"striptags": "^2.2.1",
|
||||||
"superagent": "^1.2.0",
|
"superagent": "^1.2.0",
|
||||||
"superagent-promise": "^1.0.3",
|
"superagent-promise": "^1.0.3",
|
||||||
|
"unique-slug": "2.0.0",
|
||||||
"uuid": "^3.2.1"
|
"uuid": "^3.2.1"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ Boostnote is an open source project. It's an independent project with its ongoin
|
|||||||
## Community
|
## Community
|
||||||
- [Facebook Group](https://www.facebook.com/groups/boostnote/)
|
- [Facebook Group](https://www.facebook.com/groups/boostnote/)
|
||||||
- [Twitter](https://twitter.com/boostnoteapp)
|
- [Twitter](https://twitter.com/boostnoteapp)
|
||||||
- [Slack Group](https://join.slack.com/t/boostnote-group/shared_invite/enQtMzI3NTIxMTQzMTQzLTUyYWZmZWM1YzcwYzQ5OWQ5YzA3Y2M2NzUzNmIwNzYzMjg5NmQyOGJlNzcyZDJhMGY0ZDc0ZjdlZDFhMDdiMWE)
|
- [Slack Group](https://join.slack.com/t/boostnote-group/shared_invite/enQtMzUxODgwMTc2MDg3LTgwZjA2Zjg3NjFlMzczNTVjNGMzZTk0MmIyNmE3ZjEwYTNhMTA0Y2Y4NDNlNWU4YjZlNmJiNGZhNDViOTA1ZjM)
|
||||||
- [Blog](https://boostlog.io/tags/boostnote)
|
- [Blog](https://boostlog.io/tags/boostnote)
|
||||||
- [Reddit](https://www.reddit.com/r/Boostnote/)
|
- [Reddit](https://www.reddit.com/r/Boostnote/)
|
||||||
|
|
||||||
|
|||||||
|
Before Width: | Height: | Size: 36 KiB After Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 71 KiB After Width: | Height: | Size: 34 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 5.3 KiB |
|
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 11 KiB |
|
Before Width: | Height: | Size: 596 KiB After Width: | Height: | Size: 394 KiB |
|
Before Width: | Height: | Size: 498 B After Width: | Height: | Size: 307 B |
|
Before Width: | Height: | Size: 937 B After Width: | Height: | Size: 589 B |
|
Before Width: | Height: | Size: 624 B After Width: | Height: | Size: 423 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 701 B |
|
Before Width: | Height: | Size: 624 B After Width: | Height: | Size: 423 B |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 701 B |
@@ -1,6 +1,12 @@
|
|||||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||||
|
|
||||||
exports[`TagListItem renders correctly 1`] = `
|
exports[`TagListItem renders correctly 1`] = `
|
||||||
|
<div
|
||||||
|
className="tagList-itemContainer"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="tagList-itemNarrow"
|
||||||
|
/>
|
||||||
<button
|
<button
|
||||||
className="tagList-item"
|
className="tagList-item"
|
||||||
onClick={[Function]}
|
onClick={[Function]}
|
||||||
@@ -16,4 +22,5 @@ exports[`TagListItem renders correctly 1`] = `
|
|||||||
</span>
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</button>
|
</button>
|
||||||
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|||||||
168
tests/dataApi/attachmentManagement.test.js
Normal file
@@ -0,0 +1,168 @@
|
|||||||
|
'use strict'
|
||||||
|
|
||||||
|
jest.mock('fs')
|
||||||
|
const fs = require('fs')
|
||||||
|
const path = require('path')
|
||||||
|
const findStorage = require('browser/lib/findStorage')
|
||||||
|
jest.mock('unique-slug')
|
||||||
|
const uniqueSlug = require('unique-slug')
|
||||||
|
const mdurl = require('mdurl')
|
||||||
|
|
||||||
|
const systemUnderTest = require('browser/main/lib/dataApi/attachmentManagement')
|
||||||
|
|
||||||
|
it('should test that copyAttachment should throw an error if sourcePath or storageKey or noteKey are undefined', function () {
|
||||||
|
systemUnderTest.copyAttachment(undefined, 'storageKey').then(() => {}, error => {
|
||||||
|
expect(error).toBe('sourceFilePath has to be given')
|
||||||
|
})
|
||||||
|
systemUnderTest.copyAttachment(null, 'storageKey', 'noteKey').then(() => {}, error => {
|
||||||
|
expect(error).toBe('sourceFilePath has to be given')
|
||||||
|
})
|
||||||
|
systemUnderTest.copyAttachment('source', undefined, 'noteKey').then(() => {}, error => {
|
||||||
|
expect(error).toBe('storageKey has to be given')
|
||||||
|
})
|
||||||
|
systemUnderTest.copyAttachment('source', null, 'noteKey').then(() => {}, error => {
|
||||||
|
expect(error).toBe('storageKey has to be given')
|
||||||
|
})
|
||||||
|
systemUnderTest.copyAttachment('source', 'storageKey', null).then(() => {}, error => {
|
||||||
|
expect(error).toBe('noteKey has to be given')
|
||||||
|
})
|
||||||
|
systemUnderTest.copyAttachment('source', 'storageKey', undefined).then(() => {}, error => {
|
||||||
|
expect(error).toBe('noteKey has to be given')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should test that copyAttachment should throw an error if sourcePath dosen\'t exists', function () {
|
||||||
|
fs.existsSync = jest.fn()
|
||||||
|
fs.existsSync.mockReturnValue(false)
|
||||||
|
|
||||||
|
systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey').then(() => {}, error => {
|
||||||
|
expect(error).toBe('source file does not exist')
|
||||||
|
expect(fs.existsSync).toHaveBeenCalledWith('path')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should test that copyAttachment works correctly assuming correct working of fs', function () {
|
||||||
|
const dummyExtension = '.ext'
|
||||||
|
const sourcePath = 'path' + dummyExtension
|
||||||
|
const storageKey = 'storageKey'
|
||||||
|
const noteKey = 'noteKey'
|
||||||
|
const dummyUniquePath = 'dummyPath'
|
||||||
|
const dummyStorage = {path: 'dummyStoragePath'}
|
||||||
|
|
||||||
|
fs.existsSync = jest.fn()
|
||||||
|
fs.existsSync.mockReturnValue(true)
|
||||||
|
fs.createReadStream = jest.fn()
|
||||||
|
fs.createReadStream.mockReturnValue({pipe: jest.fn()})
|
||||||
|
fs.createWriteStream = jest.fn()
|
||||||
|
|
||||||
|
findStorage.findStorage = jest.fn()
|
||||||
|
findStorage.findStorage.mockReturnValue(dummyStorage)
|
||||||
|
uniqueSlug.mockReturnValue(dummyUniquePath)
|
||||||
|
|
||||||
|
systemUnderTest.copyAttachment(sourcePath, storageKey, noteKey).then(
|
||||||
|
function (newFileName) {
|
||||||
|
expect(findStorage.findStorage).toHaveBeenCalledWith(storageKey)
|
||||||
|
expect(fs.createReadStream).toHaveBeenCalledWith(sourcePath)
|
||||||
|
expect(fs.existsSync).toHaveBeenCalledWith(sourcePath)
|
||||||
|
expect(fs.createReadStream().pipe).toHaveBeenCalled()
|
||||||
|
expect(fs.createWriteStream).toHaveBeenCalledWith(path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, noteKey, dummyUniquePath + dummyExtension))
|
||||||
|
expect(newFileName).toBe(dummyUniquePath + dummyExtension)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should test that copyAttachment creates a new folder if the attachment folder doesn\'t exist', function () {
|
||||||
|
const dummyStorage = {path: 'dummyStoragePath'}
|
||||||
|
const noteKey = 'noteKey'
|
||||||
|
const attachmentFolderPath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER)
|
||||||
|
const attachmentFolderNoteKyPath = path.join(dummyStorage.path, systemUnderTest.DESTINATION_FOLDER, noteKey)
|
||||||
|
|
||||||
|
fs.existsSync = jest.fn()
|
||||||
|
fs.existsSync.mockReturnValueOnce(true)
|
||||||
|
fs.existsSync.mockReturnValueOnce(false)
|
||||||
|
fs.existsSync.mockReturnValueOnce(false)
|
||||||
|
fs.mkdirSync = jest.fn()
|
||||||
|
|
||||||
|
findStorage.findStorage = jest.fn()
|
||||||
|
findStorage.findStorage.mockReturnValue(dummyStorage)
|
||||||
|
uniqueSlug.mockReturnValue('dummyPath')
|
||||||
|
|
||||||
|
systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey').then(
|
||||||
|
function () {
|
||||||
|
expect(fs.existsSync).toHaveBeenCalledWith(attachmentFolderPath)
|
||||||
|
expect(fs.mkdirSync).toHaveBeenCalledWith(attachmentFolderPath)
|
||||||
|
expect(fs.existsSync).toHaveBeenLastCalledWith(attachmentFolderNoteKyPath)
|
||||||
|
expect(fs.mkdirSync).toHaveBeenLastCalledWith(attachmentFolderNoteKyPath)
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should test that copyAttachment don\'t uses a random file name if not intended ', function () {
|
||||||
|
const dummyStorage = {path: 'dummyStoragePath'}
|
||||||
|
|
||||||
|
fs.existsSync = jest.fn()
|
||||||
|
fs.existsSync.mockReturnValueOnce(true)
|
||||||
|
fs.existsSync.mockReturnValueOnce(false)
|
||||||
|
fs.mkdirSync = jest.fn()
|
||||||
|
|
||||||
|
findStorage.findStorage = jest.fn()
|
||||||
|
findStorage.findStorage.mockReturnValue(dummyStorage)
|
||||||
|
uniqueSlug.mockReturnValue('dummyPath')
|
||||||
|
|
||||||
|
systemUnderTest.copyAttachment('path', 'storageKey', 'noteKey', false).then(
|
||||||
|
function (newFileName) {
|
||||||
|
expect(newFileName).toBe('path')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should replace the all ":storage" path with the actual storage path', function () {
|
||||||
|
const storageFolder = systemUnderTest.DESTINATION_FOLDER
|
||||||
|
const testInput =
|
||||||
|
'<html>\n' +
|
||||||
|
' <head>\n' +
|
||||||
|
' //header\n' +
|
||||||
|
' </head>\n' +
|
||||||
|
' <body data-theme="default">\n' +
|
||||||
|
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
|
||||||
|
' <p data-line="2">\n' +
|
||||||
|
' <img src=":storage' + mdurl.encode(path.sep) + '0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
|
||||||
|
' </p>\n' +
|
||||||
|
' <p data-line="4">\n' +
|
||||||
|
' <a href=":storage' + 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) + 'd6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
|
||||||
|
' </p>\n' +
|
||||||
|
' </body>\n' +
|
||||||
|
'</html>'
|
||||||
|
const storagePath = '<<dummyStoragePath>>'
|
||||||
|
const expectedOutput =
|
||||||
|
'<html>\n' +
|
||||||
|
' <head>\n' +
|
||||||
|
' //header\n' +
|
||||||
|
' </head>\n' +
|
||||||
|
' <body data-theme="default">\n' +
|
||||||
|
' <h2 data-line="0" id="Headline">Headline</h2>\n' +
|
||||||
|
' <p data-line="2">\n' +
|
||||||
|
' <img src="file:///' + storagePath + '\\' + storageFolder + '\\0.6r4zdgc22xp.png" alt="dummyImage.png" >\n' +
|
||||||
|
' </p>\n' +
|
||||||
|
' <p data-line="4">\n' +
|
||||||
|
' <a href="file:///' + storagePath + '\\' + storageFolder + '\\0.q2i4iw0fyx.pdf">dummyPDF.pdf</a>\n' +
|
||||||
|
' </p>\n' +
|
||||||
|
' <p data-line="6">\n' +
|
||||||
|
' <img src="file:///' + storagePath + '\\' + storageFolder + '\\d6c5ee92.jpg" alt="dummyImage2.jpg">\n' +
|
||||||
|
' </p>\n' +
|
||||||
|
' </body>\n' +
|
||||||
|
'</html>'
|
||||||
|
const actual = systemUnderTest.fixLocalURLS(testInput, storagePath)
|
||||||
|
expect(actual).toEqual(expectedOutput)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('should test that generateAttachmentMarkdown works correct both with previews and without', function () {
|
||||||
|
const fileName = 'fileName'
|
||||||
|
const path = 'path'
|
||||||
|
let expected = ``
|
||||||
|
let actual = systemUnderTest.generateAttachmentMarkdown(fileName, path, true)
|
||||||
|
expect(actual).toEqual(expected)
|
||||||
|
expected = `[${fileName}](${path})`
|
||||||
|
actual = systemUnderTest.generateAttachmentMarkdown(fileName, path, false)
|
||||||
|
expect(actual).toEqual(expected)
|
||||||
|
})
|
||||||
@@ -8714,6 +8714,12 @@ uniqs@^2.0.0:
|
|||||||
version "2.0.0"
|
version "2.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
|
resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02"
|
||||||
|
|
||||||
|
unique-slug@2.0.0:
|
||||||
|
version "2.0.0"
|
||||||
|
resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.0.tgz#db6676e7c7cc0629878ff196097c78855ae9f4ab"
|
||||||
|
dependencies:
|
||||||
|
imurmurhash "^0.1.4"
|
||||||
|
|
||||||
unique-string@^1.0.0:
|
unique-string@^1.0.0:
|
||||||
version "1.0.0"
|
version "1.0.0"
|
||||||
resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
|
resolved "https://registry.yarnpkg.com/unique-string/-/unique-string-1.0.0.tgz#9e1057cca851abb93398f8b33ae187b99caec11a"
|
||||||
|
|||||||