From 6c4206a2dd637783437ca67cd8aede60d5c5dde8 Mon Sep 17 00:00:00 2001 From: Junyoung Choi Date: Tue, 20 Mar 2018 16:18:18 +0900 Subject: [PATCH 1/7] Fix lint errors --- .eslintignore | 1 + .eslintrc | 4 +++- browser/main/lib/ipcClient.js | 1 - 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.eslintignore b/.eslintignore index e9a81977..5f7deaa8 100644 --- a/.eslintignore +++ b/.eslintignore @@ -1,3 +1,4 @@ node_modules/ compiled/ dist/ +extra_scripts/ \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index a1646659..a460b507 100644 --- a/.eslintrc +++ b/.eslintrc @@ -3,7 +3,9 @@ "plugins": ["react"], "rules": { "no-useless-escape": 0, - "prefer-const": "warn", + "prefer-const": ["warn", { + "destructuring": "all" + }], "no-unused-vars": "warn", "no-undef": "warn", "no-lone-blocks": "warn", diff --git a/browser/main/lib/ipcClient.js b/browser/main/lib/ipcClient.js index 80d67b47..0c916617 100644 --- a/browser/main/lib/ipcClient.js +++ b/browser/main/lib/ipcClient.js @@ -1,5 +1,4 @@ import ConfigManager from './ConfigManager' -import store from 'browser/main/store' const nodeIpc = require('node-ipc') const { remote, ipcRenderer } = require('electron') From 055969f5c645e19326f918c5b400c4a09361b889 Mon Sep 17 00:00:00 2001 From: Frank Kanis Date: Wed, 21 Mar 2018 22:17:34 +0100 Subject: [PATCH 2/7] Update text for internationalization --- browser/main/Detail/FolderSelect.js | 3 +- browser/main/Detail/FullscreenButton.js | 5 ++- browser/main/Detail/InfoButton.js | 3 +- browser/main/Detail/SnippetNoteDetail.js | 10 ++--- browser/main/Detail/StarButton.js | 3 +- browser/main/Detail/TagSelect.js | 3 +- browser/main/NewNoteButton/index.js | 4 +- browser/main/NoteList/index.js | 40 +++++++++---------- browser/main/SideNav/StorageItem.js | 18 ++++----- browser/main/SideNav/index.js | 5 ++- browser/main/modals/CreateFolderModal.js | 5 ++- browser/main/modals/NewNoteModal.js | 2 +- browser/main/modals/PreferencesModal/Blog.js | 6 +-- .../modals/PreferencesModal/FolderList.js | 3 +- .../main/modals/PreferencesModal/HotkeyTab.js | 2 +- .../modals/PreferencesModal/StoragesTab.js | 2 +- browser/main/modals/PreferencesModal/UiTab.js | 2 +- browser/main/modals/RenameFolderModal.js | 2 +- 18 files changed, 63 insertions(+), 55 deletions(-) diff --git a/browser/main/Detail/FolderSelect.js b/browser/main/Detail/FolderSelect.js index ed76c5dd..66ca1552 100644 --- a/browser/main/Detail/FolderSelect.js +++ b/browser/main/Detail/FolderSelect.js @@ -3,6 +3,7 @@ import React from 'react' import CSSModules from 'browser/lib/CSSModules' import styles from './FolderSelect.styl' import _ from 'lodash' +import i18n from 'browser/lib/i18n' class FolderSelect extends React.Component { constructor (props) { @@ -249,7 +250,7 @@ class FolderSelect extends React.Component { this.handleSearchInputChange(e)} onBlur={(e) => this.handleSearchInputBlur(e)} onKeyDown={(e) => this.handleSearchInputKeyDown(e)} diff --git a/browser/main/Detail/FullscreenButton.js b/browser/main/Detail/FullscreenButton.js index a0e8c790..3d29c264 100644 --- a/browser/main/Detail/FullscreenButton.js +++ b/browser/main/Detail/FullscreenButton.js @@ -2,13 +2,14 @@ import PropTypes from 'prop-types' import React from 'react' import CSSModules from 'browser/lib/CSSModules' import styles from './FullscreenButton.styl' +import i18n from 'browser/lib/i18n' const FullscreenButton = ({ onClick }) => ( - ) diff --git a/browser/main/Detail/InfoButton.js b/browser/main/Detail/InfoButton.js index 8a78ab4e..38c1c0cf 100644 --- a/browser/main/Detail/InfoButton.js +++ b/browser/main/Detail/InfoButton.js @@ -2,6 +2,7 @@ import PropTypes from 'prop-types' import React from 'react' import CSSModules from 'browser/lib/CSSModules' import styles from './InfoButton.styl' +import i18n from 'browser/lib/i18n' const InfoButton = ({ onClick @@ -10,7 +11,7 @@ const InfoButton = ({ onClick={(e) => onClick(e)} > - Info + {i18n.__('Info')} ) diff --git a/browser/main/Detail/SnippetNoteDetail.js b/browser/main/Detail/SnippetNoteDetail.js index 53f67146..620de512 100644 --- a/browser/main/Detail/SnippetNoteDetail.js +++ b/browser/main/Detail/SnippetNoteDetail.js @@ -640,7 +640,7 @@ class SnippetNoteDetail extends React.Component { type: 'warning', message: i18n.__('Sorry!'), detail: i18n.__('md/text import is available only a markdown note.'), - buttons: ['OK'] + buttons: [i18n.__('OK')] }) } @@ -766,10 +766,10 @@ class SnippetNoteDetail extends React.Component { isActive={note.isStarred} /> - this.handleTrashButtonClick(e)} /> @@ -807,7 +807,7 @@ class SnippetNoteDetail extends React.Component { fontSize: parseInt(config.preview.fontSize, 10) }} ref='description' - placeholder='Description...' + placeholder={i18n.__('Description...')} value={this.state.note.description} onChange={(e) => this.handleChange(e)} /> @@ -846,7 +846,7 @@ class SnippetNoteDetail extends React.Component { onClick={(e) => this.handleModeButtonClick(e, this.state.snippetIndex)} > {this.state.note.snippets[this.state.snippetIndex].mode == null - ? 'Select Syntax...' + ? i18n.__('Select Syntax...') : this.state.note.snippets[this.state.snippetIndex].mode }  diff --git a/browser/main/Detail/StarButton.js b/browser/main/Detail/StarButton.js index 57ba79c8..d74809cd 100644 --- a/browser/main/Detail/StarButton.js +++ b/browser/main/Detail/StarButton.js @@ -3,6 +3,7 @@ import React from 'react' import CSSModules from 'browser/lib/CSSModules' import styles from './StarButton.styl' import _ from 'lodash' +import i18n from 'browser/lib/i18n' class StarButton extends React.Component { constructor (props) { @@ -53,7 +54,7 @@ class StarButton extends React.Component { : '../resources/icon/icon-star.svg' } /> - Star + {i18n.__('Star')} ) } diff --git a/browser/main/Detail/TagSelect.js b/browser/main/Detail/TagSelect.js index 191d9120..e45d05bc 100644 --- a/browser/main/Detail/TagSelect.js +++ b/browser/main/Detail/TagSelect.js @@ -4,6 +4,7 @@ import CSSModules from 'browser/lib/CSSModules' import styles from './TagSelect.styl' import _ from 'lodash' import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig' +import i18n from 'browser/lib/i18n' class TagSelect extends React.Component { constructor (props) { @@ -137,7 +138,7 @@ class TagSelect extends React.Component { this.handleNewTagInputChange(e)} onKeyDown={(e) => this.handleNewTagInputKeyDown(e)} onBlur={(e) => this.handleNewTagBlur(e)} diff --git a/browser/main/NewNoteButton/index.js b/browser/main/NewNoteButton/index.js index b2d8cec6..a9b8de58 100644 --- a/browser/main/NewNoteButton/index.js +++ b/browser/main/NewNoteButton/index.js @@ -57,9 +57,9 @@ class NewNoteButton extends React.Component { } } - if (storage == null) this.showMessageBox('No storage to create a note') + if (storage == null) this.showMessageBox(i18n.__('No storage to create a note')) const folder = _.find(storage.folders, {key: params.folderKey}) || storage.folders[0] - if (folder == null) this.showMessageBox('No folder to create a note') + if (folder == null) this.showMessageBox(i18n.__('No folder to create a note')) return { storage, diff --git a/browser/main/NoteList/index.js b/browser/main/NoteList/index.js index 4826814f..1369637a 100644 --- a/browser/main/NoteList/index.js +++ b/browser/main/NoteList/index.js @@ -445,9 +445,9 @@ class NoteList extends React.Component { if (this.notes[targetIndex].type === 'SNIPPET_NOTE') { dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', - message: 'Sorry!', - detail: 'md/text import is available only a markdown note.', - buttons: ['OK', 'Cancel'] + message: i18n.__('Sorry!'), + detail: i18n.__('md/text import is available only a markdown note.'), + buttons: [i18n.__('OK'), i18n.__('Cancel')] }) } } @@ -471,14 +471,14 @@ class NoteList extends React.Component { this.handleNoteClick(e, uniqueKey) } - const pinLabel = note.isPinned ? 'Remove pin' : 'Pin to Top' - const deleteLabel = 'Delete Note' - const cloneNote = 'Clone Note' - const restoreNote = 'Restore Note' - const copyNoteLink = 'Copy Note Link' - const publishLabel = 'Publish Blog' - const updateLabel = 'Update Blog' - const openBlogLabel = 'Open Blog' + const pinLabel = note.isPinned ? i18n.__('Remove pin') : i18n.__('Pin to Top') + const deleteLabel = i18n.__('Delete Note') + const cloneNote = i18n.__('Clone Note') + const restoreNote = i18n.__('Restore Note') + const copyNoteLink = i18n.__('Copy Note Link') + const publishLabel = i18n.__('Publish Blog') + const updateLabel = i18n.__('Update Blog') + const openBlogLabel = i18n.__('Open Blog') const menu = new Menu() if (!location.pathname.match(/\/starred|\/trash/)) { @@ -585,9 +585,9 @@ class NoteList extends React.Component { const noteExp = selectedNotes.length > 1 ? 'notes' : 'note' const dialogueButtonIndex = dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', - message: 'Confirm note deletion', + message: i18n.__('Confirm note deletion'), detail: `This will permanently remove ${selectedNotes.length} ${noteExp}.`, - buttons: ['Confirm', 'Cancel'] + buttons: [i18n.__('Confirm'), i18n.__('Cancel')] }) if (dialogueButtonIndex === 1) return Promise.all( @@ -757,9 +757,9 @@ class NoteList extends React.Component { const { dialog } = remote const alertError = { type: 'warning', - message: 'Publish Failed', - detail: 'Check and update your blog setting and try again.', - buttons: ['Confirm'] + message: i18n.__('Publish Failed'), + detail: i18n.__('Check and update your blog setting and try again.'), + buttons: [i18n.__('Confirm')] } dialog.showMessageBox(remote.getCurrentWindow(), alertError) } @@ -767,9 +767,9 @@ class NoteList extends React.Component { confirmPublish (note) { const buttonIndex = dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', - message: 'Publish Succeeded', + message: i18n.__('Publish Succeeded'), detail: `${note.title} is published at ${note.blog.blogLink}`, - buttons: ['Confirm', 'Open Blog'] + buttons: [i18n.__('Confirm'), i18n.__('Open Blog')] }) if (buttonIndex === 1) { @@ -874,7 +874,7 @@ class NoteList extends React.Component { dialog.showMessageBox(remote.getCurrentWindow(), { type: 'warning', message: message, - buttons: ['OK'] + buttons: [i18n.__('OK')] }) } @@ -992,7 +992,7 @@ class NoteList extends React.Component {
this.handleKeyDown(e)} >
-
Make a note
+
{i18n.__('Make a note')}
this.handleCloseButtonClick(e)} />
diff --git a/browser/main/modals/PreferencesModal/Blog.js b/browser/main/modals/PreferencesModal/Blog.js index 87ee9dcc..9f4d33f6 100644 --- a/browser/main/modals/PreferencesModal/Blog.js +++ b/browser/main/modals/PreferencesModal/Blog.js @@ -43,7 +43,7 @@ class Blog extends React.Component { this.handleSettingError = (err) => { this.setState({BlogAlert: { type: 'error', - message: err.message != null ? err.message : 'Error occurs!' + message: err.message != null ? err.message : i18n.__('Error occurs!') }}) } this.oldBlog = this.state.config.blog @@ -70,7 +70,7 @@ class Blog extends React.Component { this.props.haveToSave({ tab: 'Blog', type: 'warning', - message: 'You have to save!' + message: i18n.__('You have to save!') }) } } @@ -111,7 +111,7 @@ class Blog extends React.Component { ref='typeDropdown' onChange={(e) => this.handleBlogChange(e)} > - +
diff --git a/browser/main/modals/PreferencesModal/FolderList.js b/browser/main/modals/PreferencesModal/FolderList.js index 8585f641..e7cc6f94 100644 --- a/browser/main/modals/PreferencesModal/FolderList.js +++ b/browser/main/modals/PreferencesModal/FolderList.js @@ -6,6 +6,7 @@ import styles from './FolderList.styl' import store from 'browser/main/store' import FolderItem from './FolderItem' import { SortableContainer } from 'react-sortable-hoc' +import i18n from 'browser/lib/i18n' class FolderList extends React.Component { render () { @@ -24,7 +25,7 @@ class FolderList extends React.Component {
{folderList.length > 0 ? folderList - :
No Folders
+ :
{i18n.__('No Folders')}
}
) diff --git a/browser/main/modals/PreferencesModal/HotkeyTab.js b/browser/main/modals/PreferencesModal/HotkeyTab.js index 91473c3b..d896a7c6 100644 --- a/browser/main/modals/PreferencesModal/HotkeyTab.js +++ b/browser/main/modals/PreferencesModal/HotkeyTab.js @@ -30,7 +30,7 @@ class HotkeyTab extends React.Component { this.handleSettingError = (err) => { this.setState({keymapAlert: { type: 'error', - message: err.message != null ? err.message : 'Error occurs!' + message: err.message != null ? err.message : i18n.__('Error occurs!') }}) } this.oldHotkey = this.state.config.hotkey diff --git a/browser/main/modals/PreferencesModal/StoragesTab.js b/browser/main/modals/PreferencesModal/StoragesTab.js index d666b02a..d85ed8e3 100644 --- a/browser/main/modals/PreferencesModal/StoragesTab.js +++ b/browser/main/modals/PreferencesModal/StoragesTab.js @@ -15,7 +15,7 @@ function browseFolder () { const defaultPath = remote.app.getPath('home') return new Promise((resolve, reject) => { dialog.showOpenDialog({ - title: 'Select Directory', + title: i18n.__('Select Directory'), defaultPath, properties: ['openDirectory', 'createDirectory'] }, function (targetPaths) { diff --git a/browser/main/modals/PreferencesModal/UiTab.js b/browser/main/modals/PreferencesModal/UiTab.js index 81e29746..a8030c34 100644 --- a/browser/main/modals/PreferencesModal/UiTab.js +++ b/browser/main/modals/PreferencesModal/UiTab.js @@ -36,7 +36,7 @@ class UiTab extends React.Component { this.handleSettingError = (err) => { this.setState({UiAlert: { type: 'error', - message: err.message != null ? err.message : 'Error occurs!' + message: err.message != null ? err.message : i18n.__('Error occurs!') }}) } ipc.addListener('APP_SETTING_DONE', this.handleSettingDone) diff --git a/browser/main/modals/RenameFolderModal.js b/browser/main/modals/RenameFolderModal.js index f4197196..e0ed96f2 100644 --- a/browser/main/modals/RenameFolderModal.js +++ b/browser/main/modals/RenameFolderModal.js @@ -79,7 +79,7 @@ class RenameFolderModal extends React.Component {
this.handleChange(e)} From 5ea24f650b459ec678f48e6431a6838dd1ff4c78 Mon Sep 17 00:00:00 2001 From: Junyoung Choi Date: Thu, 22 Mar 2018 12:01:16 +0900 Subject: [PATCH 3/7] Make sanitization configurable --- browser/components/MarkdownEditor.js | 1 + browser/components/MarkdownPreview.js | 9 +- browser/components/MarkdownSplitEditor.js | 1 + browser/lib/markdown.js | 86 +++++++++++-------- browser/main/lib/ConfigManager.js | 3 +- browser/main/modals/PreferencesModal/UiTab.js | 20 ++++- locales/da.json | 6 +- locales/de.json | 6 +- locales/en.json | 6 +- locales/es.json | 6 +- locales/fr.json | 10 ++- locales/ja.json | 6 +- locales/ko.json | 6 +- locales/no.json | 6 +- locales/pl.json | 6 +- locales/pt.json | 6 +- locales/sq.json | 6 +- locales/zh-CN.json | 6 +- locales/zh-TW.json | 6 +- 19 files changed, 145 insertions(+), 57 deletions(-) diff --git a/browser/components/MarkdownEditor.js b/browser/components/MarkdownEditor.js index d0e2f505..98c1942b 100644 --- a/browser/components/MarkdownEditor.js +++ b/browser/components/MarkdownEditor.js @@ -280,6 +280,7 @@ class MarkdownEditor extends React.Component { indentSize={editorIndentSize} scrollPastEnd={config.preview.scrollPastEnd} smartQuotes={config.preview.smartQuotes} + sanitize={config.preview.sanitize} ref='preview' onContextMenu={(e) => this.handleContextMenu(e)} onDoubleClick={(e) => this.handleDoubleClick(e)} diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index e4298a71..bd5d3939 100755 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -135,8 +135,11 @@ export default class MarkdownPreview extends React.Component { } initMarkdown () { - const { smartQuotes } = this.props - this.markdown = new Markdown({ typographer: smartQuotes }) + const { smartQuotes, sanitize } = this.props + this.markdown = new Markdown({ + typographer: smartQuotes, + sanitize + }) } handlePreviewAnchorClick (e) { @@ -318,7 +321,7 @@ export default class MarkdownPreview extends React.Component { componentDidUpdate (prevProps) { if (prevProps.value !== this.props.value) this.rewriteIframe() - if (prevProps.smartQuotes !== this.props.smartQuotes) { + if (prevProps.smartQuotes !== this.props.smartQuotes || prevProps.sanitize !== this.props.sanitize) { this.initMarkdown() this.rewriteIframe() } diff --git a/browser/components/MarkdownSplitEditor.js b/browser/components/MarkdownSplitEditor.js index 0aa2d16c..945f5d62 100644 --- a/browser/components/MarkdownSplitEditor.js +++ b/browser/components/MarkdownSplitEditor.js @@ -128,6 +128,7 @@ class MarkdownSplitEditor extends React.Component { lineNumber={config.preview.lineNumber} scrollPastEnd={config.preview.scrollPastEnd} smartQuotes={config.preview.smartQuotes} + sanitize={config.preview.sanitize} ref='preview' tabInde='0' value={value} diff --git a/browser/lib/markdown.js b/browser/lib/markdown.js index ee38c27d..6f1f2f00 100644 --- a/browser/lib/markdown.js +++ b/browser/lib/markdown.js @@ -45,52 +45,62 @@ class Markdown { '' + str + '' - } + }, + sanitize: 'STRICT' } const updatedOptions = Object.assign(defaultOptions, options) this.md = markdownit(updatedOptions) - // Sanitize use rinput before other plugins - this.md.use(sanitize, { - allowedTags: ['iframe', 'input', 'b', + if (updatedOptions.sanitize !== 'NONE') { + const allowedTags = ['iframe', 'input', 'b', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'h7', 'h8', 'br', 'b', 'i', 'strong', 'em', 'a', 'pre', 'code', 'img', 'tt', 'div', 'ins', 'del', 'sup', 'sub', 'p', 'ol', 'ul', 'table', 'thead', 'tbody', 'tfoot', 'blockquote', 'dl', 'dt', 'dd', 'kbd', 'q', 'samp', 'var', 'hr', 'ruby', 'rt', 'rp', 'li', 'tr', 'td', 'th', 's', 'strike', 'summary', 'details' - ], - allowedAttributes: { - '*': [ - 'style', - 'abbr', 'accept', 'accept-charset', - 'accesskey', 'action', 'align', 'alt', 'axis', - 'border', 'cellpadding', 'cellspacing', 'char', - 'charoff', 'charset', 'checked', - 'clear', 'cols', 'colspan', 'color', - 'compact', 'coords', 'datetime', 'dir', - 'disabled', 'enctype', 'for', 'frame', - 'headers', 'height', 'hreflang', - 'hspace', 'ismap', 'label', 'lang', - 'maxlength', 'media', 'method', - 'multiple', 'name', 'nohref', 'noshade', - 'nowrap', 'open', 'prompt', 'readonly', 'rel', 'rev', - 'rows', 'rowspan', 'rules', 'scope', - 'selected', 'shape', 'size', 'span', - 'start', 'summary', 'tabindex', 'target', - 'title', 'type', 'usemap', 'valign', 'value', - 'vspace', 'width', 'itemprop' - ], - 'a': ['href'], - 'div': ['itemscope', 'itemtype'], - 'blockquote': ['cite'], - 'del': ['cite'], - 'ins': ['cite'], - 'q': ['cite'], - 'img': ['src', 'width', 'height'], - 'iframe': ['src', 'width', 'height', 'frameborder', 'allowfullscreen'], - 'input': ['type', 'id', 'checked'] - }, - allowedIframeHostnames: ['www.youtube.com'] - }) + ] + const allowedAttributes = [ + 'abbr', 'accept', 'accept-charset', + 'accesskey', 'action', 'align', 'alt', 'axis', + 'border', 'cellpadding', 'cellspacing', 'char', + 'charoff', 'charset', 'checked', + 'clear', 'cols', 'colspan', 'color', + 'compact', 'coords', 'datetime', 'dir', + 'disabled', 'enctype', 'for', 'frame', + 'headers', 'height', 'hreflang', + 'hspace', 'ismap', 'label', 'lang', + 'maxlength', 'media', 'method', + 'multiple', 'name', 'nohref', 'noshade', + 'nowrap', 'open', 'prompt', 'readonly', 'rel', 'rev', + 'rows', 'rowspan', 'rules', 'scope', + 'selected', 'shape', 'size', 'span', + 'start', 'summary', 'tabindex', 'target', + 'title', 'type', 'usemap', 'valign', 'value', + 'vspace', 'width', 'itemprop' + ] + + if (updatedOptions.sanitize === 'ALLOW_STYLES') { + allowedTags.push('style') + allowedAttributes.push('style') + } + + // Sanitize use rinput before other plugins + this.md.use(sanitize, { + allowedTags, + allowedAttributes: { + '*': allowedAttributes, + 'a': ['href'], + 'div': ['itemscope', 'itemtype'], + 'blockquote': ['cite'], + 'del': ['cite'], + 'ins': ['cite'], + 'q': ['cite'], + 'img': ['src', 'width', 'height'], + 'iframe': ['src', 'width', 'height', 'frameborder', 'allowfullscreen'], + 'input': ['type', 'id', 'checked'] + }, + allowedIframeHostnames: ['www.youtube.com'] + }) + } this.md.use(emoji, { shortcuts: {} diff --git a/browser/main/lib/ConfigManager.js b/browser/main/lib/ConfigManager.js index 40b89198..ff220348 100644 --- a/browser/main/lib/ConfigManager.js +++ b/browser/main/lib/ConfigManager.js @@ -51,7 +51,8 @@ export const DEFAULT_CONFIG = { latexBlockOpen: '$$', latexBlockClose: '$$', scrollPastEnd: false, - smartQuotes: true + smartQuotes: true, + sanitize: 'STRICT' // 'STRICT', 'ALLOW_STYLES', 'NONE' }, blog: { type: 'wordpress', // Available value: wordpress, add more types in the future plz diff --git a/browser/main/modals/PreferencesModal/UiTab.js b/browser/main/modals/PreferencesModal/UiTab.js index 81e29746..708dd82a 100644 --- a/browser/main/modals/PreferencesModal/UiTab.js +++ b/browser/main/modals/PreferencesModal/UiTab.js @@ -91,7 +91,8 @@ class UiTab extends React.Component { latexBlockOpen: this.refs.previewLatexBlockOpen.value, latexBlockClose: this.refs.previewLatexBlockClose.value, scrollPastEnd: this.refs.previewScrollPastEnd.checked, - smartQuotes: this.refs.previewSmartQuotes.checked + smartQuotes: this.refs.previewSmartQuotes.checked, + sanitize: this.refs.previewSanitize.value } } @@ -441,6 +442,23 @@ class UiTab extends React.Component { Enable smart quotes
+ +
+
+ {i18n.__('Sanitization')} +
+
+ +
+
{i18n.__('LaTeX Inline Open Delimiter')} diff --git a/locales/da.json b/locales/da.json index e54245f9..be3c0491 100644 --- a/locales/da.json +++ b/locales/da.json @@ -141,5 +141,9 @@ "Portuguese": "Portuguese", "Spanish": "Spanish", "You have to save!": "You have to save!", - "Russian": "Russian" + "Russian": "Russian", + "Sanitization": "Sanitization", + "Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)", + "Allow styles": "Allow styles", + "Allow dangerous html tags": "Allow dangerous html tags" } \ No newline at end of file diff --git a/locales/de.json b/locales/de.json index 9c36871c..027310e1 100644 --- a/locales/de.json +++ b/locales/de.json @@ -143,5 +143,9 @@ "Successfully applied!": "Erfolgreich angewendet!", "UserName": "UserName", "Password": "Password", - "Russian": "Russian" + "Russian": "Russian", + "Sanitization": "Sanitization", + "Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)", + "Allow styles": "Allow styles", + "Allow dangerous html tags": "Allow dangerous html tags" } \ No newline at end of file diff --git a/locales/en.json b/locales/en.json index db13da16..182f5a47 100644 --- a/locales/en.json +++ b/locales/en.json @@ -144,5 +144,9 @@ "UserName": "UserName", "Password": "Password", "Russian": "Russian", - "Command(⌘)": "Command(⌘)" + "Command(⌘)": "Command(⌘)", + "Sanitization": "Sanitization", + "Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)", + "Allow styles": "Allow styles", + "Allow dangerous html tags": "Allow dangerous html tags" } \ No newline at end of file diff --git a/locales/es.json b/locales/es.json index e54245f9..be3c0491 100644 --- a/locales/es.json +++ b/locales/es.json @@ -141,5 +141,9 @@ "Portuguese": "Portuguese", "Spanish": "Spanish", "You have to save!": "You have to save!", - "Russian": "Russian" + "Russian": "Russian", + "Sanitization": "Sanitization", + "Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)", + "Allow styles": "Allow styles", + "Allow dangerous html tags": "Allow dangerous html tags" } \ No newline at end of file diff --git a/locales/fr.json b/locales/fr.json index 6f664280..fcc0fc6a 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -139,5 +139,11 @@ "Polish": "Polonais", "Portuguese": "Portugais", "Spanish": "Espagnol", - "You have to save!": "Il faut sauvegarder !" - } \ No newline at end of file + "You have to save!": "Il faut sauvegarder !", + "Russian": "Russian", + "Allow preview to scroll past the last line": "Allow preview to scroll past the last line", + "Sanitization": "Sanitization", + "Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)", + "Allow styles": "Allow styles", + "Allow dangerous html tags": "Allow dangerous html tags" +} \ No newline at end of file diff --git a/locales/ja.json b/locales/ja.json index e54245f9..be3c0491 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -141,5 +141,9 @@ "Portuguese": "Portuguese", "Spanish": "Spanish", "You have to save!": "You have to save!", - "Russian": "Russian" + "Russian": "Russian", + "Sanitization": "Sanitization", + "Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)", + "Allow styles": "Allow styles", + "Allow dangerous html tags": "Allow dangerous html tags" } \ No newline at end of file diff --git a/locales/ko.json b/locales/ko.json index 4b85c0e3..8a5c6f61 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -148,5 +148,9 @@ "UserName": "유저명", "Password": "패스워드", "Storage": "저장소", - "Hotkeys": "단축키" + "Hotkeys": "단축키", + "Sanitization": "허용 태그 범위", + "Only allow secure html tags (recommended)": "안전한 HTML 태그만 허용 (추천)", + "Allow styles": "style 태그, 속성까지 허용", + "Allow dangerous html tags": "모든 위험한 태그 허용" } \ No newline at end of file diff --git a/locales/no.json b/locales/no.json index e54245f9..be3c0491 100644 --- a/locales/no.json +++ b/locales/no.json @@ -141,5 +141,9 @@ "Portuguese": "Portuguese", "Spanish": "Spanish", "You have to save!": "You have to save!", - "Russian": "Russian" + "Russian": "Russian", + "Sanitization": "Sanitization", + "Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)", + "Allow styles": "Allow styles", + "Allow dangerous html tags": "Allow dangerous html tags" } \ No newline at end of file diff --git a/locales/pl.json b/locales/pl.json index e54245f9..be3c0491 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -141,5 +141,9 @@ "Portuguese": "Portuguese", "Spanish": "Spanish", "You have to save!": "You have to save!", - "Russian": "Russian" + "Russian": "Russian", + "Sanitization": "Sanitization", + "Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)", + "Allow styles": "Allow styles", + "Allow dangerous html tags": "Allow dangerous html tags" } \ No newline at end of file diff --git a/locales/pt.json b/locales/pt.json index e54245f9..be3c0491 100644 --- a/locales/pt.json +++ b/locales/pt.json @@ -141,5 +141,9 @@ "Portuguese": "Portuguese", "Spanish": "Spanish", "You have to save!": "You have to save!", - "Russian": "Russian" + "Russian": "Russian", + "Sanitization": "Sanitization", + "Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)", + "Allow styles": "Allow styles", + "Allow dangerous html tags": "Allow dangerous html tags" } \ No newline at end of file diff --git a/locales/sq.json b/locales/sq.json index e54245f9..be3c0491 100644 --- a/locales/sq.json +++ b/locales/sq.json @@ -141,5 +141,9 @@ "Portuguese": "Portuguese", "Spanish": "Spanish", "You have to save!": "You have to save!", - "Russian": "Russian" + "Russian": "Russian", + "Sanitization": "Sanitization", + "Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)", + "Allow styles": "Allow styles", + "Allow dangerous html tags": "Allow dangerous html tags" } \ No newline at end of file diff --git a/locales/zh-CN.json b/locales/zh-CN.json index e54245f9..be3c0491 100644 --- a/locales/zh-CN.json +++ b/locales/zh-CN.json @@ -141,5 +141,9 @@ "Portuguese": "Portuguese", "Spanish": "Spanish", "You have to save!": "You have to save!", - "Russian": "Russian" + "Russian": "Russian", + "Sanitization": "Sanitization", + "Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)", + "Allow styles": "Allow styles", + "Allow dangerous html tags": "Allow dangerous html tags" } \ No newline at end of file diff --git a/locales/zh-TW.json b/locales/zh-TW.json index e54245f9..be3c0491 100644 --- a/locales/zh-TW.json +++ b/locales/zh-TW.json @@ -141,5 +141,9 @@ "Portuguese": "Portuguese", "Spanish": "Spanish", "You have to save!": "You have to save!", - "Russian": "Russian" + "Russian": "Russian", + "Sanitization": "Sanitization", + "Only allow secure html tags (recommended)": "Only allow secure html tags (recommended)", + "Allow styles": "Allow styles", + "Allow dangerous html tags": "Allow dangerous html tags" } \ No newline at end of file From 36e63bb8a9021ad05933f215638215aebd4d9afb Mon Sep 17 00:00:00 2001 From: Yu-Hung Ou Date: Thu, 22 Mar 2018 21:33:32 +1100 Subject: [PATCH 4/7] wrap long LaTeX formula in Preview --- browser/components/markdown.styl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/components/markdown.styl b/browser/components/markdown.styl index b64af56c..cc6d7d92 100644 --- a/browser/components/markdown.styl +++ b/browser/components/markdown.styl @@ -58,7 +58,7 @@ body .katex font 400 1.2em 'KaTeX_Main' line-height 1.2em - white-space nowrap + white-space initial text-indent 0 .katex .mfrac>.vlist>span:nth-child(2) top 0 !important From 57ec5986726644cc5863642b6552f219f0728990 Mon Sep 17 00:00:00 2001 From: bimlas Date: Wed, 21 Mar 2018 23:23:10 +0100 Subject: [PATCH 5/7] i18n: Add Hungarian (HU) translations --- locales/hu.json | 159 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 159 insertions(+) create mode 100644 locales/hu.json diff --git a/locales/hu.json b/locales/hu.json new file mode 100644 index 00000000..37c19e48 --- /dev/null +++ b/locales/hu.json @@ -0,0 +1,159 @@ +{ + "Notes": "Jegyzetek", + "Tags": "Címkék", + "Preferences": "Beállítások", + "Make a note": "Új jegyzet", + "Ctrl": "Ctrl", + "Ctrl(^)": "Ctrl", + "to create a new note": "hogy létrehozz egy jegyzetet", + "Toggle Mode": "Mód Váltás", + "Trash": "Lomtár", + "MODIFICATION DATE": "MÓDOSÍTÁS DÁTUMA", + "Words": "Szó", + "Letters": "Betű", + "STORAGE": "TÁROLÓ", + "FOLDER": "KÖNYVTÁR", + "CREATION DATE": "LÉTREHOZÁS DÁTUMA", + "NOTE LINK": "JEGYZET LINKJE", + ".md": ".md", + ".txt": ".txt", + ".html": ".html", + "Print": "Nyomtatás", + "Your preferences for Boostnote": "Boostnote beállításaid", + "Storages": "Tárolók", + "Add Storage Location": "Tároló Hozzáadása", + "Add Folder": "Könyvtár Hozzáadása", + "Open Storage folder": "Tároló Megnyitása", + "Unlink": "Tároló Leválasztása", + "Edit": "Szerkesztés", + "Delete": "Törlés", + "Interface": "Felület", + "Interface Theme": "Felület Témája", + "Default": "Alapértelmezett", + "White": "Világos", + "Solarized Dark": "Solarized Dark", + "Dark": "Sötét", + "Show a confirmation dialog when deleting notes": "Kérjen megerősítést a jegyzetek törlése előtt", + "Editor Theme": "Szerkesztő Témája", + "Editor Font Size": "Szerkesztő Betűmérete", + "Editor Font Family": "Szerkesztő Betűtípusa", + "Editor Indent Style": "Szerkesztő Behúzása", + "Spaces": "Szóközök", + "Tabs": "Tabulátor karakterek", + "Switch to Preview": "Váltás Megtekintésre", + "When Editor Blurred": "Szerkesztő Elhagyásakor", + "When Editor Blurred, Edit On Double Click": "Szerkesztő Elhagyásakor, Szerkesztő Megnyitása Dupla Kattintással", + "On Right Click": "Jobb Egérgombbal", + "Editor Keymap": "Szerkesztő Billentyűzetkiosztása", + "default": "alapértelmezett", + "vim": "vim", + "emacs": "emacs", + "⚠️ Please restart boostnote after you change the keymap": "⚠️ Kérlek, indítsd újra a programot a kiosztás megváltoztatása után", + "Show line numbers in the editor": "Mutatassa a sorszámokat a szerkesztőben", + "Allow editor to scroll past the last line": "A szerkesztőben az utolsó sor alá is lehessen görgetni", + "Bring in web page title when pasting URL on editor": "Weboldal főcímének lekérdezése URL cím beillesztésekor", + "Preview": "Megtekintés", + "Preview Font Size": "Megtekintés Betűmérete", + "Preview Font Family": "Megtekintés Betűtípusa", + "Code block Theme": "Kódblokk Témája", + "Allow preview to scroll past the last line": "Megtekintésben az utolsó sor alá is lehessen görgetni", + "Show line numbers for preview code blocks": "Mutatassa a sorszámokat a megtekintett kódblokkokban", + "LaTeX Inline Open Delimiter": "LaTeX Inline Nyitó Határolója", + "LaTeX Inline Close Delimiter": "LaTeX Inline Záró Határolója", + "LaTeX Block Open Delimiter": "LaTeX Blokk Nyitó Határolója", + "LaTeX Block Close Delimiter": "LaTeX Blokk Záró Határolója", + "Community": "Közösség", + "Subscribe to Newsletter": "Feliratkozás a Hírlevélre", + "GitHub": "GitHub", + "Blog": "Blog", + "Facebook Group": "Facebook Csoport", + "Twitter": "Twitter", + "About": "Névjegy", + "Boostnote": "Boostnote", + "An open source note-taking app made for programmers just like you.": "Nyílt forráskódú jegyzetkészítő program a hozzád hasonló programozóknak.", + "Website": "Weboldal", + "Development": "Fejlesztés", + " : Development configurations for Boostnote.": " : Információk a Boostnote fejlesztéséről.", + "Copyright (C) 2017 - 2018 BoostIO": "Szerzői jog (C) 2017 - 2018 BoostIO", + "License: GPL v3": "Licensz: GPL v3", + "Analytics": "Adatok elemzése", + "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.": "A Boostnote névtelen adatokat gyűjt össze az alkalmazás tökéletesítése céljából, és szigorúan nem gyűjt semmilyen személyes adatot, például a jegyzetek tartalmát.", + "You can see how it works on ": "A működéséről további információkat itt találsz: ", + "You can choose to enable or disable this option.": "Kiválaszthatod, hogy engedélyezed, vagy tiltod ezt az opciót.", + "Enable analytics to help improve Boostnote": "Adatok elemzésének engedélyezése a Boostnote tökéletesítésének céljából", + "Crowdfunding": "Közösségi finanszírozás", + "Dear everyone,": "Kedves felhasználók!", + "Thank you for using Boostnote!": "Köszönjük, hogy a Boostnote-ot használjátok!", + "Boostnote is used in about 200 different countries and regions by an awesome community of developers.": "A Boostnote-ot több, mint 200 ország és régió fantasztikus fejlesztői használják.", + "To continue supporting this growth, and to satisfy community expectations,": "Hogy folytathassuk ezt a fejlődést és kielégíthessük a felhasználói elvárásokat,", + "we would like to invest more time and resources in this project.": "több időt és erőforrást szeretnénk a projektbe fektetni.", + "If you like this project and see its potential, you can help by supporting us on OpenCollective!": "Ha tetszik a projekt és hasznosnak találod, te is segíthetsz ebben az OpenCollective-en keresztül küldött támogatásoddal.", + "Thanks,": "Köszönjük!", + "Boostnote maintainers": "A Boostnote csapata", + "Support via OpenCollective": "Támogatás Küldése", + "Language": "Nyelv", + "English": "English", + "German": "German", + "French": "French", + "Show \"Saved to Clipboard\" notification when copying": "Mutassa a \"Vágólapra Másolva\" üzenetet másoláskor", + "All Notes": "Minden Jegyzet", + "Starred": "Kiemelt", + "Are you sure to ": "Biztos, hogy ", + " delete": " törölni", + "this folder?": "szeretnéd a könyvtárat?", + "Confirm": "Igen", + "Cancel": "Mégse", + "Markdown Note": "Markdown Jegyzet", + "This format is for creating text documents. Checklists, code blocks and Latex blocks are available.": "Ez a formátum szöveges dokumentumok készítésére használható. Jelölőnégyzeteket, kódblokkokat és Latex blokkokat is tartalmazhat.", + "Snippet Note": "Kód Jegyzet", + "This format is for creating code snippets. Multiple snippets can be grouped into a single note.": "Ez a formátum kódrészletek készítésére használható. Több kódrészlet tárolására is alkalmas (pl. HTML + CSS).", + "Tab to switch format": "Formátum váltásához nyomd le a Tabulátor billentyűt!", + "Updated": "Módosítás", + "Created": "Létrehozás", + "Alphabetically": "Ábécé sorrendben", + "Default View": "Alapértelmezett Nézet", + "Compressed View": "Tömörített Nézet", + "Search": "Keresés", + "Blog Type": "Blog Típusa", + "Blog Address": "Blog Címe", + "Save": "Mentés", + "Auth": "Hitelesítés", + "Authentication Method": "Hitelesítési Módszer", + "JWT": "JWT", + "USER": "USER", + "Token": "Token", + "Storage": "Tároló", + "Hotkeys": "Gyorsbillentyűk", + "Show/Hide Boostnote": "Boostnote Megjelenítése/Elrejtése", + "Restore": "Visszaállítás", + "Permanent Delete": "Végleges Törlés", + "Confirm note deletion": "Törlés megerősítése", + "This will permanently remove this note.": "A jegyzet véglegesen törölve lesz.", + "Successfully applied!": "Sikeresen alkalmazva.", + "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!": "Mentened kell!", + "UserName": "FelhasznaloNev", + "Password": "Jelszo", + "Russian": "Russian", + "Command(⌘)": "Command(⌘)", + "Hungarian": "Hungarian", + "Add Storage": "Tároló hozzáadása", + "Name": "Név", + "Type": "Típus", + "File System": "Fájlrendszer", + "Setting up 3rd-party cloud storage integration:": "Harmadik féltől származó felhőtárolási integráció beállítása:", + "Cloud-Syncing-and-Backup": "Cloud-Syncing-and-Backup", + "Location": "Hely", + "Add": "Hozzáadás", + "Unlink Storage": "Tároló Leválasztása", + "Unlinking removes this linked storage from Boostnote. No data is removed, please manually delete the folder from your hard drive if needed.": "A leválasztás eltávolítja ezt a tárolót a Boostnote-ból. Az adatok nem lesznek törölve, kérlek manuálisan töröld a könyvtárat a merevlemezről, ha szükséges." +} From be235e5204806b7bd648cc5bad68c757d46cb6aa Mon Sep 17 00:00:00 2001 From: bimlas Date: Thu, 22 Mar 2018 08:18:31 +0100 Subject: [PATCH 6/7] i18n: Add HU to locales --- browser/lib/i18n.js | 2 +- browser/main/Main.js | 2 ++ browser/main/lib/ConfigManager.js | 2 ++ browser/main/modals/PreferencesModal/UiTab.js | 1 + 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/browser/lib/i18n.js b/browser/lib/i18n.js index 1512940a..45ae057c 100644 --- a/browser/lib/i18n.js +++ b/browser/lib/i18n.js @@ -1,7 +1,7 @@ // load package for localization const i18n = new (require('i18n-2'))({ // setup some locales - other locales default to the first locale - locales: ['en', 'sq', 'zh-CN', 'zh-TW', 'da', 'fr', 'de', 'ja', 'ko', 'no', 'pl', 'pt', 'es'], + locales: ['en', 'sq', 'zh-CN', 'zh-TW', 'da', 'fr', 'de', 'hu', 'ja', 'ko', 'no', 'pl', 'pt', 'es'], extension: '.json', devMode: process.env.NODE_ENV !== 'production' }) diff --git a/browser/main/Main.js b/browser/main/Main.js index a2c8b658..35953aea 100644 --- a/browser/main/Main.js +++ b/browser/main/Main.js @@ -161,6 +161,8 @@ class Main extends React.Component { i18n.setLocale('fr') } else if (config.ui.language === 'de') { i18n.setLocale('de') + } else if (config.ui.language === 'hu') { + i18n.setLocale('hu') } else if (config.ui.language === 'ja') { i18n.setLocale('ja') } else if (config.ui.language === 'ko') { diff --git a/browser/main/lib/ConfigManager.js b/browser/main/lib/ConfigManager.js index 40b89198..e99d4fe7 100644 --- a/browser/main/lib/ConfigManager.js +++ b/browser/main/lib/ConfigManager.js @@ -147,6 +147,8 @@ function set (updates) { i18n.setLocale('fr') } else if (newConfig.ui.language === 'de') { i18n.setLocale('de') + } else if (newConfig.ui.language === 'hu') { + i18n.setLocale('hu') } else if (newConfig.ui.language === 'ja') { i18n.setLocale('ja') } else if (newConfig.ui.language === 'ko') { diff --git a/browser/main/modals/PreferencesModal/UiTab.js b/browser/main/modals/PreferencesModal/UiTab.js index 81e29746..486d75bd 100644 --- a/browser/main/modals/PreferencesModal/UiTab.js +++ b/browser/main/modals/PreferencesModal/UiTab.js @@ -185,6 +185,7 @@ class UiTab extends React.Component { + From a24a7e03beafce070ecccfd20dbc4b945fd4efc2 Mon Sep 17 00:00:00 2001 From: Junyoung Choi Date: Thu, 22 Mar 2018 20:59:19 +0900 Subject: [PATCH 7/7] Quit app when all window closed --- lib/main-app.js | 4 ++++ lib/main-window.js | 5 +---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/main-app.js b/lib/main-app.js index 6a6a4ce4..e7e52715 100644 --- a/lib/main-app.js +++ b/lib/main-app.js @@ -69,6 +69,10 @@ ipc.on('update-app-confirm', function (event, msg) { } }) +app.on('window-all-closed', function () { + app.quit() +}) + app.on('ready', function () { mainWindow = require('./main-window') diff --git a/lib/main-window.js b/lib/main-window.js index 573f41cf..4ac60797 100644 --- a/lib/main-window.js +++ b/lib/main-window.js @@ -56,11 +56,8 @@ if (process.platform === 'darwin' || process.env.DESKTOP_SESSION === 'cinnamon') app.on('before-quit', function (e) { mainWindow.removeAllListeners() }) -} else { - app.on('window-all-closed', function () { - app.quit() - }) } + mainWindow.on('resize', _.throttle(storeWindowSize, 500)) function storeWindowSize () {