1
0
mirror of https://github.com/BoostIo/Boostnote synced 2025-12-13 01:36:22 +00:00

Merge branch 'master' into spellchecker

This commit is contained in:
ehhc
2018-11-06 08:36:59 +01:00
committed by GitHub
48 changed files with 433 additions and 67 deletions

View File

@@ -16,7 +16,6 @@ import convertModeName from 'browser/lib/convertModeName'
import copy from 'copy-to-clipboard' import copy from 'copy-to-clipboard'
import mdurl from 'mdurl' import mdurl from 'mdurl'
import exportNote from 'browser/main/lib/dataApi/exportNote' import exportNote from 'browser/main/lib/dataApi/exportNote'
import { escapeHtmlCharacters } from 'browser/lib/utils'
import context from 'browser/lib/context' import context from 'browser/lib/context'
import i18n from 'browser/lib/i18n' import i18n from 'browser/lib/i18n'
import fs from 'fs' import fs from 'fs'
@@ -331,9 +330,7 @@ export default class MarkdownPreview extends React.Component {
allowCustomCSS, allowCustomCSS,
customCSS customCSS
) )
let body = this.markdown.render( let body = this.markdown.render(noteContent)
escapeHtmlCharacters(noteContent, { detectCodeBlock: true })
)
const files = [this.GetCodeThemeLink(codeBlockTheme), ...CSS_FILES] const files = [this.GetCodeThemeLink(codeBlockTheme), ...CSS_FILES]
const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent( const attachmentsAbsolutePaths = attachmentManagement.getAbsolutePathsOfAttachmentsInContent(
noteContent, noteContent,

View File

@@ -24,16 +24,19 @@ const TagElement = ({ tagName }) => (
/** /**
* @description Tag element list component. * @description Tag element list component.
* @param {Array|null} tags * @param {Array|null} tags
* @param {boolean} showTagsAlphabetically
* @return {React.Component} * @return {React.Component}
*/ */
const TagElementList = tags => { const TagElementList = (tags, showTagsAlphabetically) => {
if (!isArray(tags)) { if (!isArray(tags)) {
return [] return []
} }
const tagElements = tags.map(tag => TagElement({ tagName: tag })) if (showTagsAlphabetically) {
return _.sortBy(tags).map(tag => TagElement({ tagName: tag }))
return tagElements } else {
return tags.map(tag => TagElement({ tagName: tag }))
}
} }
/** /**
@@ -55,7 +58,8 @@ const NoteItem = ({
pathname, pathname,
storageName, storageName,
folderName, folderName,
viewType viewType,
showTagsAlphabetically
}) => ( }) => (
<div <div
styleName={isActive ? 'item--active' : 'item'} styleName={isActive ? 'item--active' : 'item'}
@@ -93,7 +97,7 @@ const NoteItem = ({
<div styleName='item-bottom'> <div styleName='item-bottom'>
<div styleName='item-bottom-tagList'> <div styleName='item-bottom-tagList'>
{note.tags.length > 0 {note.tags.length > 0
? TagElementList(note.tags) ? TagElementList(note.tags, showTagsAlphabetically)
: <span : <span
style={{ fontStyle: 'italic', opacity: 0.5 }} style={{ fontStyle: 'italic', opacity: 0.5 }}
styleName='item-bottom-tagList-empty' styleName='item-bottom-tagList-empty'

View File

@@ -7,18 +7,18 @@ import styles from './StorageList.styl'
import CSSModules from 'browser/lib/CSSModules' import CSSModules from 'browser/lib/CSSModules'
/** /**
* @param {Array} storgaeList * @param {Array} storageList
*/ */
const StorageList = ({storageList, isFolded}) => ( const StorageList = ({storageList, isFolded}) => (
<div styleName={isFolded ? 'storageList-folded' : 'storageList'}> <div styleName={isFolded ? 'storageList-folded' : 'storageList'}>
{storageList.length > 0 ? storageList : ( {storageList.length > 0 ? storageList : (
<div styleName='storgaeList-empty'>No storage mount.</div> <div styleName='storageList-empty'>No storage mount.</div>
)} )}
</div> </div>
) )
StorageList.propTypes = { StorageList.propTypes = {
storgaeList: PropTypes.arrayOf(PropTypes.element).isRequired storageList: PropTypes.arrayOf(PropTypes.element).isRequired
} }
export default CSSModules(StorageList, styles) export default CSSModules(StorageList, styles)

View File

@@ -25,7 +25,7 @@ const TagListItem = ({name, handleClickTagListItem, handleClickNarrowToTag, hand
<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 !== 0 ? count : ''}</span>
</span> </span>
</button> </button>
</div> </div>

View File

@@ -61,6 +61,9 @@ const languages = [
}, { }, {
name: 'Turkish', name: 'Turkish',
locale: 'tr' locale: 'tr'
}, {
name: 'Thai',
locale: 'th'
} }
] ]

View File

@@ -2,6 +2,7 @@
import sanitizeHtml from 'sanitize-html' import sanitizeHtml from 'sanitize-html'
import { escapeHtmlCharacters } from './utils' import { escapeHtmlCharacters } from './utils'
import url from 'url'
module.exports = function sanitizePlugin (md, options) { module.exports = function sanitizePlugin (md, options) {
options = options || {} options = options || {}
@@ -25,7 +26,7 @@ module.exports = function sanitizePlugin (md, options) {
const inlineTokens = state.tokens[tokenIdx].children const inlineTokens = state.tokens[tokenIdx].children
for (let childIdx = 0; childIdx < inlineTokens.length; childIdx++) { for (let childIdx = 0; childIdx < inlineTokens.length; childIdx++) {
if (inlineTokens[childIdx].type === 'html_inline') { if (inlineTokens[childIdx].type === 'html_inline') {
inlineTokens[childIdx].content = sanitizeHtml( inlineTokens[childIdx].content = sanitizeInline(
inlineTokens[childIdx].content, inlineTokens[childIdx].content,
options options
) )
@@ -35,3 +36,89 @@ module.exports = function sanitizePlugin (md, options) {
} }
}) })
} }
const tagRegex = /<([A-Z][A-Z0-9]*)\s*((?:\s*[A-Z][A-Z0-9]*(?:=("|')(?:[^\3]+?)\3)?)*)\s*\/?>|<\/([A-Z][A-Z0-9]*)\s*>/i
const attributesRegex = /([A-Z][A-Z0-9]*)(?:=("|')([^\2]+?)\2)?/ig
function sanitizeInline (html, options) {
let match = tagRegex.exec(html)
if (!match) {
return ''
}
const { allowedTags, allowedAttributes, selfClosing, allowedSchemesAppliedToAttributes } = options
if (match[1] !== undefined) {
// opening tag
const tag = match[1].toLowerCase()
if (allowedTags.indexOf(tag) === -1) {
return ''
}
const attributes = match[2]
let attrs = ''
let name
let value
while ((match = attributesRegex.exec(attributes))) {
name = match[1].toLowerCase()
value = match[3]
if (allowedAttributes['*'].indexOf(name) !== -1 || (allowedAttributes[tag] && allowedAttributes[tag].indexOf(name) !== -1)) {
if (allowedSchemesAppliedToAttributes.indexOf(name) !== -1) {
if (naughtyHRef(value, options) || (tag === 'iframe' && name === 'src' && naughtyIFrame(value, options))) {
continue
}
}
attrs += ` ${name}`
if (match[2]) {
attrs += `="${value}"`
}
}
}
if (selfClosing.indexOf(tag) === -1) {
return '<' + tag + attrs + '>'
} else {
return '<' + tag + attrs + ' />'
}
} else {
// closing tag
if (allowedTags.indexOf(match[4].toLowerCase()) !== -1) {
return html
} else {
return ''
}
}
}
function naughtyHRef (href, options) {
// href = href.replace(/[\x00-\x20]+/g, '')
href = href.replace(/<\!\-\-.*?\-\-\>/g, '')
const matches = href.match(/^([a-zA-Z]+)\:/)
if (!matches) {
if (href.match(/^[\/\\]{2}/)) {
return !options.allowProtocolRelative
}
// No scheme
return false
}
const scheme = matches[1].toLowerCase()
return options.allowedSchemes.indexOf(scheme) === -1
}
function naughtyIFrame (src, options) {
try {
const parsed = url.parse(src, false, true)
return options.allowedIframeHostnames.index(parsed.hostname) === -1
} catch (e) {
return true
}
}

View File

@@ -106,7 +106,11 @@ class Markdown {
'iframe': ['src', 'width', 'height', 'frameborder', 'allowfullscreen'], 'iframe': ['src', 'width', 'height', 'frameborder', 'allowfullscreen'],
'input': ['type', 'id', 'checked'] 'input': ['type', 'id', 'checked']
}, },
allowedIframeHostnames: ['www.youtube.com'] allowedIframeHostnames: ['www.youtube.com'],
selfClosing: [ 'img', 'br', 'hr', 'input' ],
allowedSchemes: [ 'http', 'https', 'ftp', 'mailto' ],
allowedSchemesAppliedToAttributes: [ 'href', 'src', 'cite' ],
allowProtocolRelative: true
}) })
} }

View File

@@ -348,7 +348,7 @@ class MarkdownNoteDetail extends React.Component {
} }
render () { render () {
const { data, location } = this.props const { data, location, config } = this.props
const { note, editorType } = this.state const { note, editorType } = this.state
const storageKey = note.storage const storageKey = note.storage
const folderKey = note.folder const folderKey = note.folder
@@ -399,6 +399,8 @@ class MarkdownNoteDetail extends React.Component {
<TagSelect <TagSelect
ref='tags' ref='tags'
value={this.state.note.tags} value={this.state.note.tags}
saveTagsAlphabetically={config.ui.saveTagsAlphabetically}
showTagsAlphabetically={config.ui.showTagsAlphabetically}
data={data} data={data}
onChange={this.handleUpdateTag.bind(this)} onChange={this.handleUpdateTag.bind(this)}
/> />

View File

@@ -354,12 +354,10 @@ class SnippetNoteDetail extends React.Component {
this.refs['code-' + this.state.snippetIndex].reload() this.refs['code-' + this.state.snippetIndex].reload()
if (this.visibleTabs.offsetWidth > this.allTabs.scrollWidth) { if (this.visibleTabs.offsetWidth > this.allTabs.scrollWidth) {
console.log('no need for arrows')
this.moveTabBarBy(0) this.moveTabBarBy(0)
} else { } else {
const lastTab = this.allTabs.lastChild const lastTab = this.allTabs.lastChild
if (lastTab.offsetLeft + lastTab.offsetWidth < this.visibleTabs.offsetWidth) { if (lastTab.offsetLeft + lastTab.offsetWidth < this.visibleTabs.offsetWidth) {
console.log('need to scroll')
const width = this.visibleTabs.offsetWidth const width = this.visibleTabs.offsetWidth
const newLeft = lastTab.offsetLeft + lastTab.offsetWidth - width const newLeft = lastTab.offsetLeft + lastTab.offsetWidth - width
this.moveTabBarBy(newLeft > 0 ? -newLeft : 0) this.moveTabBarBy(newLeft > 0 ? -newLeft : 0)
@@ -627,7 +625,6 @@ class SnippetNoteDetail extends React.Component {
} }
focusEditor () { focusEditor () {
console.log('code-' + this.state.snippetIndex)
this.refs['code-' + this.state.snippetIndex].focus() this.refs['code-' + this.state.snippetIndex].focus()
} }
@@ -759,6 +756,8 @@ class SnippetNoteDetail extends React.Component {
<TagSelect <TagSelect
ref='tags' ref='tags'
value={this.state.note.tags} value={this.state.note.tags}
saveTagsAlphabetically={config.ui.saveTagsAlphabetically}
showTagsAlphabetically={config.ui.showTagsAlphabetically}
data={data} data={data}
onChange={(e) => this.handleChange(e)} onChange={(e) => this.handleChange(e)}
/> />

View File

@@ -179,10 +179,10 @@ class TagSelect extends React.Component {
} }
render () { render () {
const { value, className } = this.props const { value, className, showTagsAlphabetically } = this.props
const tagList = _.isArray(value) const tagList = _.isArray(value)
? value.map((tag) => { ? (showTagsAlphabetically ? _.sortBy(value) : value).map((tag) => {
return ( return (
<span styleName='tag' <span styleName='tag'
key={tag} key={tag}

View File

@@ -80,7 +80,6 @@ class Main extends React.Component {
} }
}) })
.then(data => { .then(data => {
console.log(data)
store.dispatch({ store.dispatch({
type: 'ADD_STORAGE', type: 'ADD_STORAGE',
storage: data.storage, storage: data.storage,

View File

@@ -56,7 +56,6 @@ class NoteList extends React.Component {
super(props) super(props)
this.selectNextNoteHandler = () => { this.selectNextNoteHandler = () => {
console.log('fired next')
this.selectNextNote() this.selectNextNote()
} }
this.selectPriorNoteHandler = () => { this.selectPriorNoteHandler = () => {
@@ -616,7 +615,6 @@ class NoteList extends React.Component {
.catch((err) => { .catch((err) => {
console.error('Cannot Delete note: ' + err) console.error('Cannot Delete note: ' + err)
}) })
console.log('Notes were all deleted')
} else { } else {
if (!confirmDeleteNote(confirmDeletion, false)) return if (!confirmDeleteNote(confirmDeletion, false)) return
@@ -636,7 +634,6 @@ class NoteList extends React.Component {
}) })
}) })
AwsMobileAnalyticsConfig.recordDynamicCustomEvent('EDIT_NOTE') AwsMobileAnalyticsConfig.recordDynamicCustomEvent('EDIT_NOTE')
console.log('Notes went to trash')
}) })
.catch((err) => { .catch((err) => {
console.error('Notes could not go to trash: ' + err) console.error('Notes could not go to trash: ' + err)
@@ -996,6 +993,7 @@ class NoteList extends React.Component {
folderName={this.getNoteFolder(note).name} folderName={this.getNoteFolder(note).name}
storageName={this.getNoteStorage(note).name} storageName={this.getNoteStorage(note).name}
viewType={viewType} viewType={viewType}
showTagsAlphabetically={config.ui.showTagsAlphabetically}
/> />
) )
} }

View File

@@ -20,6 +20,10 @@ import i18n from 'browser/lib/i18n'
import context from 'browser/lib/context' import context from 'browser/lib/context'
import { remote } from 'electron' import { remote } from 'electron'
function matchActiveTags (tags, activeTags) {
return _.every(activeTags, v => tags.indexOf(v) >= 0)
}
class SideNav extends React.Component { class SideNav extends React.Component {
// TODO: should not use electron stuff v0.7 // TODO: should not use electron stuff v0.7
@@ -202,12 +206,20 @@ 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) const activeTags = this.getActiveTags(location.pathname)
const relatedTags = this.getRelatedTags(activeTags, data.noteMap)
let tagList = _.sortBy(data.tagNoteMap.map( let tagList = _.sortBy(data.tagNoteMap.map(
(tag, name) => ({ name, size: tag.size, related: relatedTags.has(name) }) (tag, name) => ({ name, size: tag.size, related: relatedTags.has(name) })
), ['name']).filter( ).filter(
tag => tag.size > 0 tag => tag.size > 0
) ), ['name'])
if (config.ui.enableLiveNoteCounts && activeTags.length !== 0) {
const notesTags = data.noteMap.map(note => note.tags)
tagList = tagList.map(tag => {
tag.size = notesTags.filter(tags => tags.includes(tag.name) && matchActiveTags(tags, activeTags)).length
return tag
})
}
if (config.sortTagsBy === 'COUNTER') { if (config.sortTagsBy === 'COUNTER') {
tagList = _.sortBy(tagList, item => (0 - item.size)) tagList = _.sortBy(tagList, item => (0 - item.size))
} }
@@ -306,7 +318,6 @@ class SideNav extends React.Component {
.catch((err) => { .catch((err) => {
console.error('Cannot Delete note: ' + err) console.error('Cannot Delete note: ' + err)
}) })
console.log('Trash emptied')
} }
handleFilterButtonContextMenu (event) { handleFilterButtonContextMenu (event) {

View File

@@ -45,7 +45,6 @@ function initAwsMobileAnalytics () {
if (getSendEventCond()) return if (getSendEventCond()) return
AWS.config.credentials.get((err) => { AWS.config.credentials.get((err) => {
if (!err) { if (!err) {
console.log('Cognito Identity ID: ' + AWS.config.credentials.identityId)
recordDynamicCustomEvent('APP_STARTED') recordDynamicCustomEvent('APP_STARTED')
recordStaticCustomEvent() recordStaticCustomEvent()
} }
@@ -58,7 +57,7 @@ function recordDynamicCustomEvent (type, options = {}) {
mobileAnalyticsClient.recordEvent(type, options) mobileAnalyticsClient.recordEvent(type, options)
} catch (analyticsError) { } catch (analyticsError) {
if (analyticsError instanceof ReferenceError) { if (analyticsError instanceof ReferenceError) {
console.log(analyticsError.name + ': ' + analyticsError.message) console.error(analyticsError.name + ': ' + analyticsError.message)
} }
} }
} }
@@ -71,7 +70,7 @@ function recordStaticCustomEvent () {
}) })
} catch (analyticsError) { } catch (analyticsError) {
if (analyticsError instanceof ReferenceError) { if (analyticsError instanceof ReferenceError) {
console.log(analyticsError.name + ': ' + analyticsError.message) console.error(analyticsError.name + ': ' + analyticsError.message)
} }
} }
} }

View File

@@ -529,7 +529,6 @@ function handleAttachmentLinkPaste (storageKey, noteKey, linkText) {
return modifiedLinkText return modifiedLinkText
}) })
} else { } else {
console.log('One if the parameters was null -> Do nothing..')
return Promise.resolve(linkText) return Promise.resolve(linkText)
} }
} }

View File

@@ -14,7 +14,6 @@ function renameStorage (key, name) {
cachedStorageList = JSON.parse(localStorage.getItem('storages')) cachedStorageList = JSON.parse(localStorage.getItem('storages'))
if (!_.isArray(cachedStorageList)) throw new Error('invalid storages') if (!_.isArray(cachedStorageList)) throw new Error('invalid storages')
} catch (err) { } catch (err) {
console.log('error got')
console.error(err) console.error(err)
return Promise.reject(err) return Promise.reject(err)
} }

View File

@@ -31,13 +31,9 @@ function resolveStorageData (storageCache) {
const version = parseInt(storage.version, 10) const version = parseInt(storage.version, 10)
if (version >= 1) { if (version >= 1) {
if (version > 1) {
console.log('The repository version is newer than one of current app.')
}
return Promise.resolve(storage) return Promise.resolve(storage)
} }
console.log('Transform Legacy storage', storage.path)
return migrateFromV6Storage(storage.path) return migrateFromV6Storage(storage.path)
.then(() => storage) .then(() => storage)
} }

View File

@@ -9,7 +9,7 @@ function resolveStorageNotes (storage) {
notePathList = sander.readdirSync(notesDirPath) notePathList = sander.readdirSync(notesDirPath)
} catch (err) { } catch (err) {
if (err.code === 'ENOENT') { if (err.code === 'ENOENT') {
console.log(notesDirPath, ' doesn\'t exist.') console.error(notesDirPath, ' doesn\'t exist.')
sander.mkdirSync(notesDirPath) sander.mkdirSync(notesDirPath)
} else { } else {
console.warn('Failed to find note dir', notesDirPath, err) console.warn('Failed to find note dir', notesDirPath, err)

View File

@@ -12,7 +12,6 @@ function toggleStorage (key, isOpen) {
cachedStorageList = JSON.parse(localStorage.getItem('storages')) cachedStorageList = JSON.parse(localStorage.getItem('storages'))
if (!_.isArray(cachedStorageList)) throw new Error('invalid storages') if (!_.isArray(cachedStorageList)) throw new Error('invalid storages')
} catch (err) { } catch (err) {
console.log('error got')
console.error(err) console.error(err)
return Promise.reject(err) return Promise.reject(err)
} }

View File

@@ -14,7 +14,6 @@ function once (name, listener) {
} }
function emit (name, ...args) { function emit (name, ...args) {
console.log(name)
remote.getCurrentWindow().webContents.send(name, ...args) remote.getCurrentWindow().webContents.send(name, ...args)
} }

View File

@@ -14,14 +14,13 @@ nodeIpc.connectTo(
path.join(app.getPath('userData'), 'boostnote.service'), path.join(app.getPath('userData'), 'boostnote.service'),
function () { function () {
nodeIpc.of.node.on('error', function (err) { nodeIpc.of.node.on('error', function (err) {
console.log(err) console.error(err)
}) })
nodeIpc.of.node.on('connect', function () { nodeIpc.of.node.on('connect', function () {
console.log('Connected successfully')
ipcRenderer.send('config-renew', {config: ConfigManager.get()}) ipcRenderer.send('config-renew', {config: ConfigManager.get()})
}) })
nodeIpc.of.node.on('disconnect', function () { nodeIpc.of.node.on('disconnect', function () {
console.log('disconnected') return
}) })
} }
) )

View File

@@ -28,11 +28,21 @@ class HotkeyTab extends React.Component {
}}) }})
} }
this.handleSettingError = (err) => { this.handleSettingError = (err) => {
if (
this.state.config.hotkey.toggleMain === '' ||
this.state.config.hotkey.toggleMode === ''
) {
this.setState({keymapAlert: {
type: 'success',
message: i18n.__('Successfully applied!')
}})
} else {
this.setState({keymapAlert: { this.setState({keymapAlert: {
type: 'error', type: 'error',
message: err.message != null ? err.message : i18n.__('An error occurred!') message: err.message != null ? err.message : i18n.__('An error occurred!')
}}) }})
} }
}
this.oldHotkey = this.state.config.hotkey this.oldHotkey = this.state.config.hotkey
ipc.addListener('APP_SETTING_DONE', this.handleSettingDone) ipc.addListener('APP_SETTING_DONE', this.handleSettingDone)
ipc.addListener('APP_SETTING_ERROR', this.handleSettingError) ipc.addListener('APP_SETTING_ERROR', this.handleSettingError)

View File

@@ -71,6 +71,9 @@ class UiTab extends React.Component {
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, showOnlyRelatedTags: this.refs.showOnlyRelatedTags.checked,
showTagsAlphabetically: this.refs.showTagsAlphabetically.checked,
saveTagsAlphabetically: this.refs.saveTagsAlphabetically.checked,
enableLiveNoteCounts: this.refs.enableLiveNoteCounts.checked,
disableDirectWrite: this.refs.uiD2w != null disableDirectWrite: this.refs.uiD2w != null
? this.refs.uiD2w.checked ? this.refs.uiD2w.checked
: false : false
@@ -249,16 +252,6 @@ 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'
/>&nbsp;
{i18n.__('Show only related tags')}
</label>
</div>
{ {
global.process.platform === 'win32' global.process.platform === 'win32'
? <div styleName='group-checkBoxSection'> ? <div styleName='group-checkBoxSection'>
@@ -274,6 +267,52 @@ class UiTab extends React.Component {
</div> </div>
: null : null
} }
<div styleName='group-header2'>Tags</div>
<div styleName='group-checkBoxSection'>
<label>
<input onChange={(e) => this.handleUIChange(e)}
checked={this.state.config.ui.saveTagsAlphabetically}
ref='saveTagsAlphabetically'
type='checkbox'
/>&nbsp;
{i18n.__('Save tags of a note in alphabetical order')}
</label>
</div>
<div styleName='group-checkBoxSection'>
<label>
<input onChange={(e) => this.handleUIChange(e)}
checked={this.state.config.ui.showTagsAlphabetically}
ref='showTagsAlphabetically'
type='checkbox'
/>&nbsp;
{i18n.__('Show tags of a note in alphabetical order')}
</label>
</div>
<div styleName='group-checkBoxSection'>
<label>
<input onChange={(e) => this.handleUIChange(e)}
checked={this.state.config.ui.showOnlyRelatedTags}
ref='showOnlyRelatedTags'
type='checkbox'
/>&nbsp;
{i18n.__('Show only related tags')}
</label>
</div>
<div styleName='group-checkBoxSection'>
<label>
<input onChange={(e) => this.handleUIChange(e)}
checked={this.state.config.ui.enableLiveNoteCounts}
ref='enableLiveNoteCounts'
type='checkbox'
/>&nbsp;
{i18n.__('Enable live count of notes')}
</label>
</div>
<div styleName='group-header2'>Editor</div> <div styleName='group-header2'>Editor</div>
<div styleName='group-section'> <div styleName='group-section'>

View File

@@ -113,7 +113,6 @@ function data (state = defaultDataMap(), action) {
// If storage chanced, origin key must be discarded // If storage chanced, origin key must be discarded
if (originKey !== uniqueKey) { if (originKey !== uniqueKey) {
console.log('diffrent storage')
// From isStarred // From isStarred
if (originNote.isStarred) { if (originNote.isStarred) {
state.starredSet = new Set(state.starredSet) state.starredSet = new Set(state.starredSet)

View File

@@ -49,7 +49,7 @@ function startServer () {
} }
function startElectron () { function startElectron () {
spawn(electron, ['--hot', './index.js']) spawn(electron, ['--hot', './index.js'], { stdio: 'inherit' })
.on('close', () => { .on('close', () => {
server.close() server.close()
}) })

View File

@@ -59,7 +59,7 @@ updater.on('update-downloaded', (info) => {
}) })
updater.autoUpdater.on('error', (err) => { updater.autoUpdater.on('error', (err) => {
console.log(err) console.error(err)
}) })
ipc.on('update-app-confirm', function (event, msg) { ipc.on('update-app-confirm', function (event, msg) {

View File

@@ -7,13 +7,19 @@ const config = new Config()
const _ = require('lodash') const _ = require('lodash')
var showMenu = process.platform !== 'win32' var showMenu = process.platform !== 'win32'
const windowSize = config.get('windowsize') || { x: null, y: null, width: 1080, height: 720 } const windowSize = config.get('windowsize') || {
x: null,
y: null,
width: 1080,
height: 720
}
const mainWindow = new BrowserWindow({ const mainWindow = new BrowserWindow({
x: windowSize.x, x: windowSize.x,
y: windowSize.y, y: windowSize.y,
width: windowSize.width, width: windowSize.width,
height: windowSize.height, height: windowSize.height,
useContentSize: true,
minWidth: 500, minWidth: 500,
minHeight: 320, minHeight: 320,
autoHideMenuBar: showMenu, autoHideMenuBar: showMenu,

View File

@@ -145,6 +145,7 @@
"UserName": "Benutzername", "UserName": "Benutzername",
"Password": "Passwort", "Password": "Passwort",
"Russian": "Russisch", "Russian": "Russisch",
"Thai": "Thai (ภาษาไทย)",
"Command(⌘)": "Befehlstaste(⌘)", "Command(⌘)": "Befehlstaste(⌘)",
"Editor Rulers": "Editor Trennline", "Editor Rulers": "Editor Trennline",
"Enable": "Aktiviert", "Enable": "Aktiviert",

View File

@@ -156,6 +156,7 @@
"Password": "Password", "Password": "Password",
"Russian": "Russian", "Russian": "Russian",
"Hungarian": "Hungarian", "Hungarian": "Hungarian",
"Thai": "Thai (ภาษาไทย)",
"Command(⌘)": "Command(⌘)", "Command(⌘)": "Command(⌘)",
"Add Storage": "Add Storage", "Add Storage": "Add Storage",
"Name": "Name", "Name": "Name",
@@ -178,6 +179,8 @@
"Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.", "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.",
"⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠", "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠",
"Disabled": "Disabled", "Disabled": "Disabled",
"Save tags of a note in alphabetical order": "Save tags of a note in alphabetical order",
"Enable live count of notes": "Enable live count of notes",
"Enable smart table editor": "Enable smart table editor", "Enable smart table editor": "Enable smart table editor",
"Snippet Default Language": "Snippet Default Language" "Snippet Default Language": "Snippet Default Language"
} }

View File

@@ -143,6 +143,7 @@
"Spanish": "Español", "Spanish": "Español",
"Unsaved Changes!": "¡Tienes que guardar!", "Unsaved Changes!": "¡Tienes que guardar!",
"Russian": "Ruso", "Russian": "Ruso",
"Thai": "Thai (ภาษาไทย)",
"Command(⌘)": "Comando(⌘)", "Command(⌘)": "Comando(⌘)",
"Editor Rulers": "Reglas del editor", "Editor Rulers": "Reglas del editor",
"Enable": "Activar", "Enable": "Activar",

View File

@@ -146,6 +146,7 @@
"UserName": "نام کاربری", "UserName": "نام کاربری",
"Password": "رمز عبور", "Password": "رمز عبور",
"Russian": "روسی", "Russian": "روسی",
"Thai": "Thai (ภาษาไทย)",
"Command(⌘)": "Command(⌘)", "Command(⌘)": "Command(⌘)",
"Editor Rulers": "Editor Rulers", "Editor Rulers": "Editor Rulers",
"Enable": "فعال", "Enable": "فعال",

View File

@@ -142,6 +142,7 @@
"Spanish": "Espagnol", "Spanish": "Espagnol",
"Unsaved Changes!": "Il faut sauvegarder !", "Unsaved Changes!": "Il faut sauvegarder !",
"Russian": "Russe", "Russian": "Russe",
"Thai": "Thai (ภาษาไทย)",
"Command(⌘)": "Command(⌘)", "Command(⌘)": "Command(⌘)",
"Editor Rulers": "Règles dans l'éditeur", "Editor Rulers": "Règles dans l'éditeur",
"Enable": "Activer", "Enable": "Activer",
@@ -153,6 +154,9 @@
"Allow dangerous html tags": "Accepter les tags html dangereux", "Allow dangerous html tags": "Accepter les tags html dangereux",
"Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "Convertir des flèches textuelles en jolis signes. ⚠ Cela va interferérer avec les éventuels commentaires HTML dans votre Markdown.", "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "Convertir des flèches textuelles en jolis signes. ⚠ Cela va interferérer avec les éventuels commentaires HTML dans votre Markdown.",
"⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ Vous avez collé un lien qui référence une pièce-jointe qui n'a pas pu être récupéré dans le dossier de stockage de la note. Coller des liens qui font référence à des pièces-jointes ne fonctionne que si la source et la destination et la même. Veuillez plutôt utiliser du Drag & Drop ! ⚠", "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ Vous avez collé un lien qui référence une pièce-jointe qui n'a pas pu être récupéré dans le dossier de stockage de la note. Coller des liens qui font référence à des pièces-jointes ne fonctionne que si la source et la destination et la même. Veuillez plutôt utiliser du Drag & Drop ! ⚠",
"Save tags of a note in alphabetical order": "Sauvegarder les tags d'une note en ordre alphabétique",
"Show tags of a note in alphabetical order": "Afficher les tags d'une note par ordre alphabétique",
"Enable live count of notes": "Activer le comptage live des notes",
"Enable smart table editor": "Activer l'intelligent éditeur de tableaux", "Enable smart table editor": "Activer l'intelligent éditeur de tableaux",
"Snippet Default Language": "Langage par défaut d'un snippet", "Snippet Default Language": "Langage par défaut d'un snippet",
"Disabled": "Disabled", "Disabled": "Disabled",

View File

@@ -155,6 +155,7 @@
"Password": "Jelszo", "Password": "Jelszo",
"Russian": "Russian", "Russian": "Russian",
"Hungarian": "Hungarian", "Hungarian": "Hungarian",
"Thai": "Thai (ภาษาไทย)",
"Command(⌘)": "Command(⌘)", "Command(⌘)": "Command(⌘)",
"Add Storage": "Tároló hozzáadása", "Add Storage": "Tároló hozzáadása",
"Name": "Név", "Name": "Név",

View File

@@ -146,6 +146,7 @@
"UserName": "UserName", "UserName": "UserName",
"Password": "Password", "Password": "Password",
"Russian": "Russo", "Russian": "Russo",
"Thai": "Thai (ภาษาไทย)",
"Command(⌘)": "Comando(⌘)", "Command(⌘)": "Comando(⌘)",
"Editor Rulers": "Regole dell'editor", "Editor Rulers": "Regole dell'editor",
"Enable": "Abilita", "Enable": "Abilita",

View File

@@ -155,6 +155,7 @@
"Password": "パスワード", "Password": "パスワード",
"Russian": "ロシア語", "Russian": "ロシア語",
"Hungarian": "ハンガリー語", "Hungarian": "ハンガリー語",
"Thai": "Thai (ภาษาไทย)",
"Command(⌘)": "コマンド(⌘)", "Command(⌘)": "コマンド(⌘)",
"Add Storage": "ストレージを追加", "Add Storage": "ストレージを追加",
"Name": "名前", "Name": "名前",

View File

@@ -143,6 +143,7 @@
"Spanish": "Spanish", "Spanish": "Spanish",
"Unsaved Changes!": "저장해주세요!", "Unsaved Changes!": "저장해주세요!",
"Russian": "Russian", "Russian": "Russian",
"Thai": "Thai (ภาษาไทย)",
"Command(⌘)": "Command(⌘)", "Command(⌘)": "Command(⌘)",
"Delete Folder": "폴더 삭제", "Delete Folder": "폴더 삭제",
"This will delete all notes in the folder and can not be undone.": "폴더의 모든 노트를 지우게 되고, 되돌릴 수 없습니다.", "This will delete all notes in the folder and can not be undone.": "폴더의 모든 노트를 지우게 되고, 되돌릴 수 없습니다.",

View File

@@ -143,6 +143,7 @@
"Spanish": "Spanish", "Spanish": "Spanish",
"Unsaved Changes!": "Unsaved Changes!", "Unsaved Changes!": "Unsaved Changes!",
"Russian": "Russian", "Russian": "Russian",
"Thai": "Thai (ภาษาไทย)",
"Editor Rulers": "Editor Rulers", "Editor Rulers": "Editor Rulers",
"Enable": "Enable", "Enable": "Enable",
"Disable": "Disable", "Disable": "Disable",

View File

@@ -149,6 +149,7 @@
"Spanish": "Hiszpański", "Spanish": "Hiszpański",
"Unsaved Changes!": "Musisz zapisać!", "Unsaved Changes!": "Musisz zapisać!",
"Russian": "Rosyjski", "Russian": "Rosyjski",
"Thai": "Thai (ภาษาไทย)",
"Editor Rulers": "Margines", "Editor Rulers": "Margines",
"Enable": "Włącz", "Enable": "Włącz",
"Disable": "Wyłącz", "Disable": "Wyłącz",

View File

@@ -143,6 +143,7 @@
"Spanish": "Espanhol", "Spanish": "Espanhol",
"Unsaved Changes!": "Você precisa salvar!", "Unsaved Changes!": "Você precisa salvar!",
"Russian": "Russo", "Russian": "Russo",
"Thai": "Thai (ภาษาไทย)",
"Editor Rulers": "Réguas do Editor", "Editor Rulers": "Réguas do Editor",
"Enable": "Habilitado", "Enable": "Habilitado",
"Disable": "Desabilitado", "Disable": "Desabilitado",

View File

@@ -143,6 +143,7 @@
"Spanish": "Spanish", "Spanish": "Spanish",
"Unsaved Changes!": "Unsaved Changes!", "Unsaved Changes!": "Unsaved Changes!",
"Russian": "Russian", "Russian": "Russian",
"Thai": "Thai (ภาษาไทย)",
"Editor Rulers": "Editor Rulers", "Editor Rulers": "Editor Rulers",
"Enable": "Enable", "Enable": "Enable",
"Disable": "Disable", "Disable": "Disable",

View File

@@ -144,6 +144,7 @@
"UserName": "Имя пользователя", "UserName": "Имя пользователя",
"Password": "Пароль", "Password": "Пароль",
"Russian": "Русский", "Russian": "Русский",
"Thai": "Thai (ภาษาไทย)",
"Editor Rulers": "Editor Rulers", "Editor Rulers": "Editor Rulers",
"Enable": "Enable", "Enable": "Enable",
"Disable": "Disable", "Disable": "Disable",

View File

@@ -142,6 +142,7 @@
"Spanish": "Spanish", "Spanish": "Spanish",
"Unsaved Changes!": "Unsaved Changes!", "Unsaved Changes!": "Unsaved Changes!",
"Russian": "Russian", "Russian": "Russian",
"Thai": "Thai (ภาษาไทย)",
"Editor Rulers": "Editor Rulers", "Editor Rulers": "Editor Rulers",
"Enable": "Enable", "Enable": "Enable",
"Disable": "Disable", "Disable": "Disable",

182
locales/th.json Normal file
View File

@@ -0,0 +1,182 @@
{
"Notes": "โน๊ต",
"Tags": "แท็ก",
"Preferences": "ตั้งค่า",
"Make a note": "สร้างโน๊ต",
"Ctrl": "Ctrl",
"Ctrl(^)": "Ctrl(^)",
"to create a new note": "เพื่อสร้างโน๊ต",
"Toggle Mode": "Toggle Mode",
"Add tag...": "เพิ่มแท็ก...",
"Trash": "ถังขยะ",
"MODIFICATION DATE": "แก้ไขเมื่อ",
"Words": "คำ",
"Letters": "ตัวอักษร",
"STORAGE": "แหล่งจัดเก็บ",
"FOLDER": "โฟลเดอร์",
"CREATION DATE": "สร้างเมื่อ",
"NOTE LINK": "NOTE LINK",
".md": ".md",
".txt": ".txt",
".html": ".html",
"Print": "พิมพ์",
"Your preferences for Boostnote": "การตั้งค่าของคุณสำหรับ Boostnote",
"Help": "ช่วยเหลือ",
"Hide Help": "ซ่อนการช่วยเหลือ",
"Storages": "แหล่งจัดเก็บ",
"Add Storage Location": "เพิ่มแหล่งจัดเก็บ",
"Add Folder": "เพิ่มโฟลเดอร์",
"Select Folder": "เลือกโฟลเดอร์",
"Open Storage folder": "เปิดโฟลเดอร์แหล่งจัดเก็บ",
"Unlink": "ยกเลิกการลิงค์",
"Edit": "แก้ไข",
"Delete": "ลบ",
"Interface": "หน้าตาโปรแกรม",
"Interface Theme": "ธีมของโปรแกรม",
"Default": "ค่าเริ่มต้น",
"White": "โทนสว่าง",
"Solarized Dark": "Solarized Dark",
"Dark": "โทนมืด",
"Show a confirmation dialog when deleting notes": "แสดงหน้าต่างยืนยันเมื่อทำการลบโน๊ต",
"Disable Direct Write (It will be applied after restarting)": "ปิด Direct Write (It will be applied after restarting)",
"Show only related tags": "แสดงเฉพาะแท็กที่เกี่ยวข้อง",
"Editor Theme": "ธีมของ Editor",
"Editor Font Size": "ขนาดอักษรของ Editor",
"Editor Font Family": "แบบอักษรของ Editor",
"Editor Indent Style": "รูปแบบการย่อหน้าของ Editor",
"Spaces": "ช่องว่าง",
"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": "รูปแบบคีย์ลัดของ Editor",
"default": "ค่าเริ่มต้น",
"vim": "vim",
"emacs": "emacs",
"⚠️ Please restart boostnote after you change the keymap": "⚠️ กรุณาปิดและเปิดโปรแกรมใหม่ หลังจากคุณเปลี่ยนคีย์ลัด",
"Show line numbers in the editor": "แสดงหมายเลขบรรทัด",
"Allow editor to scroll past the last line": "อนุญาตให้เลื่อน Scroll เลยบรรทัดสุดท้ายได้",
"Enable smart quotes": "เปิด Smart quotes",
"Bring in web page title when pasting URL on editor": "แสดงชื่อ Title ของเว็บไซต์เมื่อวางลิงค์ใน Editor",
"Preview": "พรีวิว",
"Preview Font Size": "ขนาดอักษร",
"Preview Font Family": "แบบอักษร",
"Code block Theme": "ธีมของ Code block",
"Allow preview to scroll past the last line": "อนุญาตให้เลื่อน Scroll เลยบรรทัดสุดท้ายได้",
"Show line numbers for preview code blocks": "แสดงหมายเลขบรรทัดใน Code block",
"LaTeX Inline Open Delimiter": "LaTeX Inline Open Delimiter",
"LaTeX Inline Close Delimiter": "LaTeX Inline Close Delimiter",
"LaTeX Block Open Delimiter": "LaTeX Block Open Delimiter",
"LaTeX Block Close Delimiter": "LaTeX Block Close Delimiter",
"PlantUML Server": "เซิฟเวอร์ของ PlantUML",
"Community": "ชุมชนผู้ใช้",
"Subscribe to Newsletter": "สมัครรับข่าวสาร",
"GitHub": "GitHub",
"Blog": "บล็อก",
"Facebook Group": "กลุ่ม Facebook",
"Twitter": "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": "สงวนลิขสิทธิ์ (C) 2017 - 2018 BoostIO",
"License: GPL v3": "License: 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.": "Boostnote จะเก็บข้อมูลแบบไม่ระบุตัวตนเพื่อนำไปใช้ในการปรับปรุงแอพพลิเคชันเท่านั้น, และจะไม่มีการเก็บข้อมูลส่วนตัวใดๆของคุณ เช่น ข้อมูลในโน๊ตของคุณอย่างเด็ดขาด.",
"You can see how it works on ": "คุณสามารถดูรายละเอียดเพิ่มเติมได้ที่ ",
"You can choose to enable or disable this option.": "คุณสามารถเลือกที่จะเปิดหรือปิดตัวเลือกนี้ได้.",
"Enable analytics to help improve Boostnote": "เปิดการวิเคราะห์ สำหรับการนำไปปรับปรุงพัฒนา 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 จากสังคมผู้ใช้ที่เป็น Developer มากกว่า 200 ประเทศทั่วโลกจากหลากหลายภูมิภาค.",
"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!": "ถ้าคุณชอบและมองเห็นความเป็นไปได้ในอนาคต, คุณสามารถช่วยเหลือด้วยการสนับสนุนเราผ่าน OpenCollective!",
"Thanks,": "ขอขอบคุณ,",
"Boostnote maintainers": "กลุ่มผู้พัฒนา Boostnote",
"Support via OpenCollective": "สนับสนุนผ่าน OpenCollective",
"Language": "ภาษา",
"English": "English",
"German": "German",
"French": "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.": "รูปแบบนี้ใช้สำหรับสร้างเอกสารทั่วไป. รองรับการเขียนเช็คลิสต์, แทรกโค้ด และการเขียนโดยใช้ Latex.",
"Snippet Note": "โน๊ต Snippet",
"This format is for creating code snippets. Multiple snippets can be grouped into a single note.": "รูปแบบนี้ใช้สำหรับสร้าง Code snippets. สามารถรวมหลาย Snippets เป็นโน๊ตเดียวกันได้.",
"Tab to switch format": "กด Tab เพื่อเปลี่ยนรูปแบบที่เลือก",
"Updated": "เรียงตามอัพเดท",
"Created": "เรียงตามเวลาที่สร้างโน๊ต",
"Alphabetically": "เรียงตามอักษร",
"Counter": "Counter",
"Default View": "มุมมองปกติ",
"Compressed View": "มุมมองหนาแน่น",
"Search": "ค้นหา",
"Blog Type": "ประเภทของบล็อก",
"Blog Address": "ที่อยู่ของบล็อก",
"Save": "บันทึก",
"Auth": "การยืนยันตัวตน",
"Authentication Method": "รูปแบบการยืนยันตัวตน",
"JWT": "JWT",
"USER": "USER",
"Token": "Token",
"Storage": "แหล่งจัดเก็บ",
"Hotkeys": "คีย์ลัด",
"Show/Hide Boostnote": "แสดง/ซ่อน Boostnote",
"Toggle editor mode": "เปิด/ปิด Editor mode",
"Restore": "กู้คืน",
"Permanent Delete": "ลบถาวร",
"Confirm note deletion": "ยืนยันการลบโน๊ต",
"This will permanently remove this note.": "โน๊ตของคุณจะถูกลบอย่างถาวร.",
"Successfully applied!": "สำเร็จ!",
"Albanian": "Albanian",
"Chinese (zh-CN)": "Chinese (zh-CN)",
"Chinese (zh-TW)": "Chinese (zh-TW)",
"Danish": "Danish",
"Japanese": "Japanese",
"Korean": "Korean",
"Norwegian": "Norwegian",
"Polish": "Polish",
"Portuguese": "Portuguese",
"Spanish": "Spanish",
"You have to save!": "คุณจำเป็นต้องบันทึก!",
"UserName": "UserName",
"Password": "Password",
"Russian": "Russian",
"Hungarian": "Hungarian",
"Thai": "Thai (ภาษาไทย)",
"Command(⌘)": "Command(⌘)",
"Add Storage": "เพิ่มแหล่งจัดเก็บ",
"Name": "ชื่อ",
"Type": "ชนิด",
"File System": "ระบบไฟล์",
"Setting up 3rd-party cloud storage integration:": "ดูวิธีการตั้งค่า หากต้องการใช้งานแบบลิงค์ไฟล์ร่วมกับผู้ให้บริการเก็บข้อมูลบนคลาวด์",
"Cloud-Syncing-and-Backup": "Cloud-Syncing-and-Backup",
"Location": "ที่อยู่",
"Add": "เพิ่ม",
"Unlink Storage": "ยกเลิกการลิงค์ Storage",
"Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.": "การยกเลิกการลิงค์ จะเป็นการลบการลิงค์แหล่งจัดเก็บออกไปจาก Boostnote. แต่ไฟล์ข้อมูลจะไม่ถูกลบ, หากต้องการลบข้อมูล กรุณาลบโพลเดอร์ของข้อมูลในเครื่องของท่านด้วยตัวเอง.",
"Editor Rulers": "ไม้บรรทัด Editor",
"Enable": "เปิด",
"Disable": "ปิด",
"Sanitization": "Sanitization",
"Only allow secure html tags (recommended)": "อนุญาตเฉพาะ HTML tag ที่มีความปลอดภัย (แนะนำ)",
"Render newlines in Markdown paragraphs as <br>": "ใช้ <br> แทนอักขระขึ้นบรรทัดใหม่ในข้อความ Markdown",
"Allow styles": "อนุญาตการใช้ styles",
"Allow dangerous html tags": "อนุญาตให้ใช้ html tags ที่ไม่ปลอดภัย",
"Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "แปลงลูกศรจากรูปแบบข้อความให้เป็นสัญลักษณ์. ⚠ สิ่งนี้จะเป็นการแทรกโดยใช้ HTML comment ลงไปใน Markdown ที่คุณเขียน.",
"⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ ไม่พบไฟล์แนบในโน๊ตนี้ จากลิงค์ที่คุณได้วาง. คุณสามารถวางลิงค์ที่อ้างอิงไปยังไฟล์แนบ เฉพาะกรณีที่ต้นทาง และปลายทางที่อ้างถึงนั้นอยู่ใน 'แหล่งจัดเก็บ เดียวกัน. กรุณาใช้การลากและวางเพื่อใส่ไฟล์แนบแทน! ⚠",
"Enable smart table editor": "เปิดการใช้ Smart table editor",
"Snippet Default Language": "ทำการ Snippet ภาษาที่เป็นค่าเริ่มต้น"
}

View File

@@ -15,7 +15,7 @@
"dev": "node dev-scripts/dev.js" "dev": "node dev-scripts/dev.js"
}, },
"config": { "config": {
"electron-version": "2.0.7" "electron-version": "3.0.3"
}, },
"repository": { "repository": {
"type": "git", "type": "git",
@@ -56,7 +56,7 @@
"codemirror": "^5.40.2", "codemirror": "^5.40.2",
"codemirror-mode-elixir": "^1.1.1", "codemirror-mode-elixir": "^1.1.1",
"electron-config": "^1.0.0", "electron-config": "^1.0.0",
"electron-gh-releases": "^2.0.2", "electron-gh-releases": "^2.0.4",
"escape-string-regexp": "^1.0.5", "escape-string-regexp": "^1.0.5",
"file-uri-to-path": "^1.0.0", "file-uri-to-path": "^1.0.0",
"file-url": "^2.0.2", "file-url": "^2.0.2",
@@ -126,7 +126,7 @@
"css-loader": "^0.19.0", "css-loader": "^0.19.0",
"devtron": "^1.1.0", "devtron": "^1.1.0",
"dom-storage": "^2.0.2", "dom-storage": "^2.0.2",
"electron": "2.0.7", "electron": "3.0.3",
"electron-packager": "^12.0.0", "electron-packager": "^12.0.0",
"eslint": "^3.13.1", "eslint": "^3.13.1",
"eslint-config-standard": "^6.2.1", "eslint-config-standard": "^6.2.1",

View File

@@ -50,11 +50,14 @@ const smartQuotes = 'This is a "QUOTE".'
const breaks = 'This is the first line.\nThis is the second line.' const breaks = 'This is the first line.\nThis is the second line.'
const shortcuts = '<kbd>Ctrl</kbd>\n\n[[Ctrl]]'
export default { export default {
basic, basic,
codeblock, codeblock,
katex, katex,
checkboxes, checkboxes,
smartQuotes, smartQuotes,
breaks breaks,
shortcuts
} }

View File

@@ -43,3 +43,8 @@ test('Markdown.render() should render line breaks correctly', t => {
const renderedNonBreaks = newmd.render(markdownFixtures.breaks) const renderedNonBreaks = newmd.render(markdownFixtures.breaks)
t.snapshot(renderedNonBreaks) t.snapshot(renderedNonBreaks)
}) })
test('Markdown.render() should render shortcuts correctly', t => {
const rendered = md.render(markdownFixtures.shortcuts)
t.snapshot(rendered)
})

View File

@@ -18,6 +18,14 @@ Generated by [AVA](https://ava.li).
This is the second line.</p>␊ This is the second line.</p>␊
` `
## Markdown.render() should render shortcuts correctly
> Snapshot 1
`<p data-line="0"><kbd>Ctrl</kbd></p>␊
<p data-line="2"><kbd>Ctrl</kbd></p>␊
`
## Markdown.render() should renders KaTeX correctly ## Markdown.render() should renders KaTeX correctly
> Snapshot 1 > Snapshot 1