From 7804a229844c372f875ab498fb937744500bdbac Mon Sep 17 00:00:00 2001 From: Maciek Date: Fri, 10 Aug 2018 21:39:59 +0200 Subject: [PATCH 001/129] Automatic table of contents generation for Markdown Adds table of contents for any Markdown note or Markdown snippet. Consequent generations update existing TOC. Generated TOC is case sensitive to handle #2067 Shortcut : CommandOrControl+Alt+T Menu : Edit/Generate/Update Markdown TOC --- browser/lib/markdown-toc-generator.js | 52 +++++++++++++++++++++++ browser/main/Detail/MarkdownNoteDetail.js | 9 ++++ browser/main/Detail/SnippetNoteDetail.js | 15 ++++++- lib/main-menu.js | 10 +++++ package.json | 1 + webpack-skeleton.js | 1 + 6 files changed, 87 insertions(+), 1 deletion(-) create mode 100644 browser/lib/markdown-toc-generator.js diff --git a/browser/lib/markdown-toc-generator.js b/browser/lib/markdown-toc-generator.js new file mode 100644 index 00000000..363a58ce --- /dev/null +++ b/browser/lib/markdown-toc-generator.js @@ -0,0 +1,52 @@ +/** + * @fileoverview Markdown table of contents generator + */ + +import toc from 'markdown-toc' +import diacritics from 'diacritics-map' +import stripColor from 'strip-color' + +/** + * @caseSensitiveSlugify Custom slugify function + * Same implementation that the original used by markdown-toc (node_modules/markdown-toc/lib/utils.js), + * but keeps original case to properly handle https://github.com/BoostIO/Boostnote/issues/2067 + */ +function caseSensitiveSlugify (str) { + function replaceDiacritics (str) { + return str.replace(/[À-ž]/g, function (ch) { + return diacritics[ch] || ch + }) + } + function getTitle (str) { + if (/^\[[^\]]+\]\(/.test(str)) { + var m = /^\[([^\]]+)\]/.exec(str) + if (m) return m[1] + } + return str + } + str = getTitle(str) + str = stripColor(str) + // str = str.toLowerCase() //let's be case sensitive + + // `.split()` is often (but not always) faster than `.replace()` + str = str.split(' ').join('-') + str = str.split(/\t/).join('--') + str = str.split(/<\/?[^>]+>/).join('') + str = str.split(/[|$&`~=\\\/@+*!?({[\]})<>=.,;:'"^]/).join('') + str = str.split(/[。?!,、;:“”【】()〔〕[]﹃﹄“ ”‘’﹁﹂—…-~《》〈〉「」]/).join('') + str = replaceDiacritics(str) + return str +} + +export function generate (currentValue, updateCallback) { + const TOC_MARKER = '' + if (!currentValue.includes(TOC_MARKER)) { + currentValue = TOC_MARKER + currentValue + } + updateCallback(toc.insert(currentValue, {slugify: caseSensitiveSlugify})) +} + +export default { + generate +} + diff --git a/browser/main/Detail/MarkdownNoteDetail.js b/browser/main/Detail/MarkdownNoteDetail.js index 82073162..11197838 100755 --- a/browser/main/Detail/MarkdownNoteDetail.js +++ b/browser/main/Detail/MarkdownNoteDetail.js @@ -29,6 +29,7 @@ import { formatDate } from 'browser/lib/date-formatter' import { getTodoPercentageOfCompleted } from 'browser/lib/getTodoStatus' import striptags from 'striptags' import { confirmDeleteNote } from 'browser/lib/confirmDeleteNote' +import markdownToc from 'browser/lib/markdown-toc-generator' class MarkdownNoteDetail extends React.Component { constructor (props) { @@ -47,6 +48,7 @@ class MarkdownNoteDetail extends React.Component { this.dispatchTimer = null this.toggleLockButton = this.handleToggleLockButton.bind(this) + this.generateToc = () => this.handleGenerateToc() } focus () { @@ -59,6 +61,7 @@ class MarkdownNoteDetail extends React.Component { const reversedType = this.state.editorType === 'SPLIT' ? 'EDITOR_PREVIEW' : 'SPLIT' this.handleSwitchMode(reversedType) }) + ee.on('code:generate-toc', this.generateToc) } componentWillReceiveProps (nextProps) { @@ -75,6 +78,7 @@ class MarkdownNoteDetail extends React.Component { componentWillUnmount () { ee.off('topbar:togglelockbutton', this.toggleLockButton) + ee.off('code:generate-toc', this.generateToc) if (this.saveQueue != null) this.saveNow() } @@ -262,6 +266,11 @@ class MarkdownNoteDetail extends React.Component { } } + handleGenerateToc () { + markdownToc.generate(this.refs.content.value, + (modifiedValue) => { this.refs.content.refs.code.setValue(modifiedValue) }) + } + handleFocus (e) { this.focus() } diff --git a/browser/main/Detail/SnippetNoteDetail.js b/browser/main/Detail/SnippetNoteDetail.js index 652d1f53..f7a4dd3a 100644 --- a/browser/main/Detail/SnippetNoteDetail.js +++ b/browser/main/Detail/SnippetNoteDetail.js @@ -29,6 +29,7 @@ import InfoPanelTrashed from './InfoPanelTrashed' import { formatDate } from 'browser/lib/date-formatter' import i18n from 'browser/lib/i18n' import { confirmDeleteNote } from 'browser/lib/confirmDeleteNote' +import markdownToc from 'browser/lib/markdown-toc-generator' const electron = require('electron') const { remote } = electron @@ -52,6 +53,7 @@ class SnippetNoteDetail extends React.Component { } this.scrollToNextTabThreshold = 0.7 + this.generateToc = () => this.handleGenerateToc() } componentDidMount () { @@ -65,6 +67,7 @@ class SnippetNoteDetail extends React.Component { enableLeftArrow: allTabs.offsetLeft !== 0 }) } + ee.on('code:generate-toc', this.generateToc) } componentWillReceiveProps (nextProps) { @@ -91,6 +94,16 @@ class SnippetNoteDetail extends React.Component { componentWillUnmount () { if (this.saveQueue != null) this.saveNow() + ee.off('code:generate-toc', this.generateToc) + } + + handleGenerateToc () { + let currentMode = this.state.note.snippets[this.state.snippetIndex].mode + if (currentMode.includes('Markdown')) { + let currentValue = this.refs['code-' + this.state.snippetIndex].value + let currentEditor = this.refs['code-' + this.state.snippetIndex].refs.code.editor + markdownToc.generate(currentValue, (modifiedValue) => { currentEditor.setValue(modifiedValue) }) + } } handleChange (e) { @@ -441,7 +454,7 @@ class SnippetNoteDetail extends React.Component { const isSuper = global.process.platform === 'darwin' ? e.metaKey : e.ctrlKey - if (isSuper && !e.shiftKey) { + if (isSuper && !e.shiftKey && !e.altKey) { e.preventDefault() this.addSnippet() } diff --git a/lib/main-menu.js b/lib/main-menu.js index cda964c5..b86552ac 100644 --- a/lib/main-menu.js +++ b/lib/main-menu.js @@ -228,6 +228,16 @@ const edit = { click () { mainWindow.webContents.send('editor:add-tag') } + }, + { + type: 'separator' + }, + { + label: 'Generate/Update Markdown TOC', + accelerator: 'CommandOrControl+Alt+T', + click () { + mainWindow.webContents.send('code:generate-toc') + } } ] } diff --git a/package.json b/package.json index fbbb025f..062a9c6c 100644 --- a/package.json +++ b/package.json @@ -82,6 +82,7 @@ "markdown-it-named-headers": "^0.0.4", "markdown-it-plantuml": "^1.1.0", "markdown-it-smartarrows": "^1.0.1", + "markdown-toc": "^1.2.0", "mdurl": "^1.0.1", "mermaid": "^8.0.0-rc.8", "moment": "^2.10.3", diff --git a/webpack-skeleton.js b/webpack-skeleton.js index aca0791f..4d221f15 100644 --- a/webpack-skeleton.js +++ b/webpack-skeleton.js @@ -37,6 +37,7 @@ var config = { 'markdown-it-kbd', 'markdown-it-plantuml', 'markdown-it-admonition', + 'markdown-toc', 'devtron', '@rokt33r/season', { From 3c14cc219e0d69d390fffb5bafad9bc776783275 Mon Sep 17 00:00:00 2001 From: Maciek Date: Sat, 11 Aug 2018 10:09:22 +0200 Subject: [PATCH 002/129] ESLint: fix let -> const warnings --- browser/main/Detail/SnippetNoteDetail.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/browser/main/Detail/SnippetNoteDetail.js b/browser/main/Detail/SnippetNoteDetail.js index f7a4dd3a..ce3d03e2 100644 --- a/browser/main/Detail/SnippetNoteDetail.js +++ b/browser/main/Detail/SnippetNoteDetail.js @@ -98,10 +98,10 @@ class SnippetNoteDetail extends React.Component { } handleGenerateToc () { - let currentMode = this.state.note.snippets[this.state.snippetIndex].mode + const currentMode = this.state.note.snippets[this.state.snippetIndex].mode if (currentMode.includes('Markdown')) { - let currentValue = this.refs['code-' + this.state.snippetIndex].value - let currentEditor = this.refs['code-' + this.state.snippetIndex].refs.code.editor + const currentValue = this.refs['code-' + this.state.snippetIndex].value + const currentEditor = this.refs['code-' + this.state.snippetIndex].refs.code.editor markdownToc.generate(currentValue, (modifiedValue) => { currentEditor.setValue(modifiedValue) }) } } From b93d7a204fc1b3a0bb9e9d46c33961a706f549b3 Mon Sep 17 00:00:00 2001 From: zhoufeng1989 Date: Tue, 14 Aug 2018 12:38:31 +1200 Subject: [PATCH 003/129] Fix 2207 and 2273, add export for storage. --- browser/main/SideNav/StorageItem.js | 40 ++++++++++++++ browser/main/lib/dataApi/exportStorage.js | 63 +++++++++++++++++++++++ browser/main/lib/dataApi/index.js | 1 + browser/main/store.js | 15 +----- tests/dataApi/exportStorage-test.js | 51 ++++++++++++++++++ 5 files changed, 157 insertions(+), 13 deletions(-) create mode 100644 browser/main/lib/dataApi/exportStorage.js create mode 100644 tests/dataApi/exportStorage-test.js diff --git a/browser/main/SideNav/StorageItem.js b/browser/main/SideNav/StorageItem.js index d72f0a8f..d17314b3 100644 --- a/browser/main/SideNav/StorageItem.js +++ b/browser/main/SideNav/StorageItem.js @@ -38,6 +38,22 @@ class StorageItem extends React.Component { { type: 'separator' }, + { + label: i18n.__('Export Storage'), + submenu: [ + { + label: i18n.__('Export as txt'), + click: (e) => this.handleExportStorageClick(e, 'txt') + }, + { + label: i18n.__('Export as md'), + click: (e) => this.handleExportStorageClick(e, 'md') + } + ] + }, + { + type: 'separator' + }, { label: i18n.__('Unlink Storage'), click: (e) => this.handleUnlinkStorageClick(e) @@ -68,6 +84,30 @@ class StorageItem extends React.Component { } } + handleExportStorageClick (e, fileType) { + const options = { + properties: ['openDirectory', 'createDirectory'], + buttonLabel: i18n.__('Select directory'), + title: i18n.__('Select a folder to export the files to'), + multiSelections: false + } + dialog.showOpenDialog(remote.getCurrentWindow(), options, + (paths) => { + if (paths && paths.length === 1) { + const { storage, dispatch } = this.props + dataApi + .exportStorage(storage.key, fileType, paths[0]) + .then(data => { + dispatch({ + type: 'EXPORT_STORAGE', + storage: data.storage, + fileType: data.fileType + }) + }) + } + }) + } + handleToggleButtonClick (e) { const { storage, dispatch } = this.props const isOpen = !this.state.isOpen diff --git a/browser/main/lib/dataApi/exportStorage.js b/browser/main/lib/dataApi/exportStorage.js new file mode 100644 index 00000000..ce2c4573 --- /dev/null +++ b/browser/main/lib/dataApi/exportStorage.js @@ -0,0 +1,63 @@ +import { findStorage } from 'browser/lib/findStorage' +import resolveStorageData from './resolveStorageData' +import resolveStorageNotes from './resolveStorageNotes' +import filenamify from 'filenamify' +import * as path from 'path' +import * as fs from 'fs' + +/** + * @param {String} storageKey + * @param {String} fileType + * @param {String} exportDir + * + * @return {Object} + * ``` + * { + * storage: Object, + * fileType: String, + * exportDir: String + * } + * ``` + */ + +function exportStorage (storageKey, fileType, exportDir) { + let targetStorage + try { + targetStorage = findStorage(storageKey) + } catch (e) { + return Promise.reject(e) + } + + return resolveStorageData(targetStorage) + .then(storage => ( + resolveStorageNotes(storage).then(notes => ({storage, notes})) + )) + .then(function exportNotes (data) { + const { storage, notes } = data + const folderNamesMapping = {} + storage.folders.forEach(folder => { + const folderExportedDir = path.join(exportDir, filenamify(folder.name, {replacement: '_'})) + folderNamesMapping[folder.key] = folderExportedDir + // make sure directory exists + try { + fs.mkdirSync(folderExportedDir) + } catch (e) {} + }) + notes + .filter(note => !note.isTrashed && note.type === 'MARKDOWN_NOTE') + .forEach(markdownNote => { + const folderExportedDir = folderNamesMapping[markdownNote.folder] + const snippetName = `${filenamify(markdownNote.title, {replacement: '_'})}.${fileType}` + const notePath = path.join(folderExportedDir, snippetName) + fs.writeFileSync(notePath, markdownNote.content) + }) + + return { + storage, + fileType, + exportDir + } + }) +} + +module.exports = exportStorage diff --git a/browser/main/lib/dataApi/index.js b/browser/main/lib/dataApi/index.js index 4e2f0061..92be6b93 100644 --- a/browser/main/lib/dataApi/index.js +++ b/browser/main/lib/dataApi/index.js @@ -9,6 +9,7 @@ const dataApi = { deleteFolder: require('./deleteFolder'), reorderFolder: require('./reorderFolder'), exportFolder: require('./exportFolder'), + exportStorage: require('./exportStorage'), createNote: require('./createNote'), updateNote: require('./updateNote'), deleteNote: require('./deleteNote'), diff --git a/browser/main/store.js b/browser/main/store.js index a1b6b791..b8f13cc8 100644 --- a/browser/main/store.js +++ b/browser/main/store.js @@ -216,16 +216,10 @@ function data (state = defaultDataMap(), action) { return state } case 'UPDATE_FOLDER': - state = Object.assign({}, state) - state.storageMap = new Map(state.storageMap) - state.storageMap.set(action.storage.key, action.storage) - return state case 'REORDER_FOLDER': - state = Object.assign({}, state) - state.storageMap = new Map(state.storageMap) - state.storageMap.set(action.storage.key, action.storage) - return state case 'EXPORT_FOLDER': + case 'RENAME_STORAGE': + case 'EXPORT_STORAGE': state = Object.assign({}, state) state.storageMap = new Map(state.storageMap) state.storageMap.set(action.storage.key, action.storage) @@ -355,11 +349,6 @@ function data (state = defaultDataMap(), action) { }) } return state - case 'RENAME_STORAGE': - state = Object.assign({}, state) - state.storageMap = new Map(state.storageMap) - state.storageMap.set(action.storage.key, action.storage) - return state case 'EXPAND_STORAGE': state = Object.assign({}, state) state.storageMap = new Map(state.storageMap) diff --git a/tests/dataApi/exportStorage-test.js b/tests/dataApi/exportStorage-test.js new file mode 100644 index 00000000..1ee98328 --- /dev/null +++ b/tests/dataApi/exportStorage-test.js @@ -0,0 +1,51 @@ +const test = require('ava') +const exportStorage = require('browser/main/lib/dataApi/exportStorage') + +global.document = require('jsdom').jsdom('') +global.window = document.defaultView +global.navigator = window.navigator + +const Storage = require('dom-storage') +const localStorage = window.localStorage = global.localStorage = new Storage(null, { strict: true }) +const path = require('path') +const TestDummy = require('../fixtures/TestDummy') +const os = require('os') +const fs = require('fs') +const sander = require('sander') + +test.beforeEach(t => { + t.context.storageDir = path.join(os.tmpdir(), 'test/export-storage') + t.context.storage = TestDummy.dummyStorage(t.context.storageDir) + t.context.exportDir = path.join(os.tmpdir(), 'test/export-storage-output') + try { fs.mkdirSync(t.context.exportDir) } catch (e) {} + localStorage.setItem('storages', JSON.stringify([t.context.storage.cache])) +}) + +test.serial('Export a storage', t => { + const storageKey = t.context.storage.cache.key + const folders = t.context.storage.json.folders + const notes = t.context.storage.notes + const exportDir = t.context.exportDir + const folderKeyToName = folders.reduce( + (acc, folder) => { + acc[folder.key] = folder.name + return acc + }, {}) + return exportStorage(storageKey, 'md', exportDir) + .then(() => { + notes.forEach(note => { + const noteDir = path.join(exportDir, folderKeyToName[note.folder], `${note.title}.md`) + if (note.type === 'MARKDOWN_NOTE') { + t.true(fs.existsSync(noteDir)) + } else if (note.type === 'SNIPPET_NOTE') { + t.false(fs.existsSync(noteDir)) + } + }) + }) +}) + +test.afterEach.always(t => { + localStorage.clear() + sander.rimrafSync(t.context.storageDir) + sander.rimrafSync(t.context.exportDir) +}) From ce3b29085f080ae705b8615c6dcecd0a4c3dc529 Mon Sep 17 00:00:00 2001 From: Maciek Date: Tue, 14 Aug 2018 22:32:22 +0200 Subject: [PATCH 004/129] Change menu position and accelerator for TOC gen. Due to the fact, that submenu "Edit" is visible only in macOS, let's move TOC generator to "File" menu. Also, change accelerator to SHIFT+CTRL+T which is working without conflicts and problems on all platforms. --- lib/main-menu.js | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/main-menu.js b/lib/main-menu.js index b86552ac..fed5eb15 100644 --- a/lib/main-menu.js +++ b/lib/main-menu.js @@ -145,6 +145,16 @@ const file = { { type: 'separator' }, + { + label: 'Generate/Update Markdown TOC', + accelerator: 'Shift+Ctrl+T', + click () { + mainWindow.webContents.send('code:generate-toc') + } + }, + { + type: 'separator' + }, { label: 'Print', accelerator: 'CommandOrControl+P', @@ -228,16 +238,6 @@ const edit = { click () { mainWindow.webContents.send('editor:add-tag') } - }, - { - type: 'separator' - }, - { - label: 'Generate/Update Markdown TOC', - accelerator: 'CommandOrControl+Alt+T', - click () { - mainWindow.webContents.send('code:generate-toc') - } } ] } From ab35c3557fd86e54bede2bbbe52d1e7472cbd5b6 Mon Sep 17 00:00:00 2001 From: amedora Date: Thu, 16 Aug 2018 16:36:00 +0900 Subject: [PATCH 005/129] add Monokai style for SnippetTab --- browser/components/SnippetTab.styl | 46 +++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/browser/components/SnippetTab.styl b/browser/components/SnippetTab.styl index 0cf4ce49..02f88f8c 100644 --- a/browser/components/SnippetTab.styl +++ b/browser/components/SnippetTab.styl @@ -136,4 +136,48 @@ body[data-theme="solarized-dark"] color $ui-solarized-dark-text-color .deleteButton - color alpha($ui-solarized-dark-text-color, 30%) \ No newline at end of file + color alpha($ui-solarized-dark-text-color, 30%) + +body[data-theme="monokai"] + .root + color $ui-monokai-text-color + border-color $ui-dark-borderColor + &:hover + background-color $ui-monokai-noteDetail-backgroundColor + .deleteButton + color $ui-monokai-text-color + &:hover + background-color darken($ui-monokai-noteDetail-backgroundColor, 15%) + &:active + color $ui-monokai-text-color + background-color $ui-dark-button--active-backgroundColor + + .root--active + color $ui-monokai-text-color + border-color $ui-monokai-borderColor + &:hover + background-color $ui-monokai-noteDetail-backgroundColor + .deleteButton + color $ui-monokai-text-color + &:hover + background-color darken($ui-monokai-noteDetail-backgroundColor, 15%) + &:active + color $ui-monokai-text-color + background-color $ui-dark-button--active-backgroundColor + + .button + border none + color $ui-monokai-text-color + background-color transparent + transition color background-color 0.15s + border-left 4px solid transparent + &:hover + color $ui-monokai-text-color + background-color $ui-monokai-noteDetail-backgroundColor + + .input + background-color $ui-monokai-noteDetail-backgroundColor + color $ui-monokai-text-color + + .deleteButton + color alpha($ui-monokai-text-color, 30%) \ No newline at end of file From 657806c8cf278720e4806c26840bb05fb97c0626 Mon Sep 17 00:00:00 2001 From: Baptiste Augrain Date: Mon, 20 Aug 2018 20:14:45 +0200 Subject: [PATCH 006/129] add smart table editor --- browser/components/CodeEditor.js | 183 ++++++++++++------ browser/components/MarkdownEditor.js | 3 +- browser/components/MarkdownSplitEditor.js | 1 + browser/lib/TextEditorInterface.js | 170 +++++++++++----- browser/main/Detail/SnippetNoteDetail.js | 1 + browser/main/lib/ConfigManager.js | 3 +- browser/main/modals/PreferencesModal/UiTab.js | 14 +- locales/en.json | 3 +- locales/fr.json | 3 +- 9 files changed, 269 insertions(+), 112 deletions(-) diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index f16cc53c..36779e4f 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -141,61 +141,9 @@ export default class CodeEditor extends React.Component { triples: '```"""\'\'\'', explode: '[]{}``$$', override: true - }, - extraKeys: { - Tab: function (cm) { - const cursor = cm.getCursor() - const line = cm.getLine(cursor.line) - const cursorPosition = cursor.ch - const charBeforeCursor = line.substr(cursorPosition - 1, 1) - if (cm.somethingSelected()) cm.indentSelection('add') - else { - const tabs = cm.getOption('indentWithTabs') - if (line.trimLeft().match(/^(-|\*|\+) (\[( |x)] )?$/)) { - cm.execCommand('goLineStart') - if (tabs) { - cm.execCommand('insertTab') - } else { - cm.execCommand('insertSoftTab') - } - cm.execCommand('goLineEnd') - } else if ( - !charBeforeCursor.match(/\t|\s|\r|\n/) && - cursor.ch > 1 - ) { - // text expansion on tab key if the char before is alphabet - const snippets = JSON.parse( - fs.readFileSync(consts.SNIPPET_FILE, 'utf8') - ) - if (expandSnippet(line, cursor, cm, snippets) === false) { - if (tabs) { - cm.execCommand('insertTab') - } else { - cm.execCommand('insertSoftTab') - } - } - } else { - if (tabs) { - cm.execCommand('insertTab') - } else { - cm.execCommand('insertSoftTab') - } - } - } - }, - 'Cmd-T': function (cm) { - // Do nothing - }, - Enter: 'boostNewLineAndIndentContinueMarkdownList', - 'Ctrl-C': cm => { - if (cm.getOption('keyMap').substr(0, 3) === 'vim') { - document.execCommand('copy') - } - return CodeMirror.Pass - } } }) - + this.setMode(this.props.mode) this.editor.on('focus', this.focusHandler) @@ -216,8 +164,135 @@ export default class CodeEditor extends React.Component { CodeMirror.Vim.defineEx('qw', 'qw', this.quitEditor) CodeMirror.Vim.map('ZZ', ':q', 'normal') this.setState({ isReady: true }) - this.tableEditor = new TableEditor(new TextEditorInterface(this.editor)) + + const editorIntf = new TextEditorInterface(this.editor) + this.tableEditor = new TableEditor(editorIntf) eventEmitter.on('code:format-table', this.formatTable) + + const defaultKeyMap = CodeMirror.normalizeKeyMap({ + Tab: function (cm) { + const cursor = cm.getCursor() + const line = cm.getLine(cursor.line) + const cursorPosition = cursor.ch + const charBeforeCursor = line.substr(cursorPosition - 1, 1) + if (cm.somethingSelected()) cm.indentSelection('add') + else { + const tabs = cm.getOption('indentWithTabs') + if (line.trimLeft().match(/^(-|\*|\+) (\[( |x)] )?$/)) { + cm.execCommand('goLineStart') + if (tabs) { + cm.execCommand('insertTab') + } else { + cm.execCommand('insertSoftTab') + } + cm.execCommand('goLineEnd') + } else if ( + !charBeforeCursor.match(/\t|\s|\r|\n/) && + cursor.ch > 1 + ) { + // text expansion on tab key if the char before is alphabet + const snippets = JSON.parse( + fs.readFileSync(consts.SNIPPET_FILE, 'utf8') + ) + if (expandSnippet(line, cursor, cm, snippets) === false) { + if (tabs) { + cm.execCommand('insertTab') + } else { + cm.execCommand('insertSoftTab') + } + } + } else { + if (tabs) { + cm.execCommand('insertTab') + } else { + cm.execCommand('insertSoftTab') + } + } + } + }, + 'Cmd-T': function (cm) { + // Do nothing + }, + Enter: 'boostNewLineAndIndentContinueMarkdownList', + 'Ctrl-C': cm => { + if (cm.getOption('keyMap').substr(0, 3) === 'vim') { + document.execCommand('copy') + } + return CodeMirror.Pass + } + }) + + if(this.props.enableTableEditor) { + const opts = options({ + smartCursor: true + }) + + const editorKeyMap = CodeMirror.normalizeKeyMap({ + 'Tab' : () => { this.tableEditor.nextCell(opts) }, + 'Shift-Tab' : () => { this.tableEditor.previousCell(opts) }, + 'Enter' : () => { this.tableEditor.nextRow(opts) }, + 'Ctrl-Enter' : () => { this.tableEditor.escape(opts) }, + 'Cmd-Enter' : () => { this.tableEditor.escape(opts) }, + 'Shift-Ctrl-Left' : () => { this.tableEditor.alignColumn(Alignment.LEFT, opts) }, + 'Shift-Cmd-Left' : () => { this.tableEditor.alignColumn(Alignment.LEFT, opts) }, + 'Shift-Ctrl-Right' : () => { this.tableEditor.alignColumn(Alignment.RIGHT, opts) }, + 'Shift-Cmd-Right' : () => { this.tableEditor.alignColumn(Alignment.RIGHT, opts) }, + 'Shift-Ctrl-Up' : () => { this.tableEditor.alignColumn(Alignment.CENTER, opts) }, + 'Shift-Cmd-Up' : () => { this.tableEditor.alignColumn(Alignment.CENTER, opts) }, + 'Shift-Ctrl-Down' : () => { this.tableEditor.alignColumn(Alignment.NONE, opts) }, + 'Shift-Cmd-Down' : () => { this.tableEditor.alignColumn(Alignment.NONE, opts) }, + 'Ctrl-Left' : () => { this.tableEditor.moveFocus(0, -1, opts) }, + 'Cmd-Left' : () => { this.tableEditor.moveFocus(0, -1, opts) }, + 'Ctrl-Right' : () => { this.tableEditor.moveFocus(0, 1, opts) }, + 'Cmd-Right' : () => { this.tableEditor.moveFocus(0, 1, opts) }, + 'Ctrl-Up' : () => { this.tableEditor.moveFocus(-1, 0, opts) }, + 'Cmd-Up' : () => { this.tableEditor.moveFocus(-1, 0, opts) }, + 'Ctrl-Down' : () => { this.tableEditor.moveFocus(1, 0, opts) }, + 'Cmd-Down' : () => { this.tableEditor.moveFocus(1, 0, opts) }, + 'Ctrl-K Ctrl-I' : () => { this.tableEditor.insertRow(opts) }, + 'Cmd-K Cmd-I' : () => { this.tableEditor.insertRow(opts) }, + 'Ctrl-L Ctrl-I' : () => { this.tableEditor.deleteRow(opts) }, + 'Cmd-L Cmd-I' : () => { this.tableEditor.deleteRow(opts) }, + 'Ctrl-K Ctrl-J' : () => { this.tableEditor.insertColumn(opts) }, + 'Cmd-K Cmd-J' : () => { this.tableEditor.insertColumn(opts) }, + 'Ctrl-L Ctrl-J' : () => { this.tableEditor.deleteColumn(opts) }, + 'Cmd-L Cmd-J' : () => { this.tableEditor.deleteColumn(opts) }, + 'Alt-Shift-Ctrl-Left' : () => { this.tableEditor.moveColumn(-1, opts) }, + 'Alt-Shift-Cmd-Left' : () => { this.tableEditor.moveColumn(-1, opts) }, + 'Alt-Shift-Ctrl-Right': () => { this.tableEditor.moveColumn(1, opts) }, + 'Alt-Shift-Cmd-Right' : () => { this.tableEditor.moveColumn(1, opts) }, + 'Alt-Shift-Ctrl-Up' : () => { this.tableEditor.moveRow(-1, opts) }, + 'Alt-Shift-Cmd-Up' : () => { this.tableEditor.moveRow(-1, opts) }, + 'Alt-Shift-Ctrl-Down' : () => { this.tableEditor.moveRow(1, opts) }, + 'Alt-Shift-Cmd-Down' : () => { this.tableEditor.moveRow(1, opts) } + }) + + const updateActiveState = () => { + const active = this.tableEditor.cursorIsInTable(opts) + if (active) { + this.editor.setOption('extraKeys', editorKeyMap) + } else { + this.editor.setOption('extraKeys', defaultKeyMap) + this.tableEditor.resetSmartCursor() + } + } + + this.editor.on('cursorActivity', () => { + if (!editorIntf.transaction) { + updateActiveState() + } + }) + this.editor.on('changes', () => { + if (!editorIntf.transaction) { + updateActiveState() + } + }) + editorIntf.onDidFinishTransaction = () => { + updateActiveState() + } + } else { + this.editor.setOption('extraKeys', defaultKeyMap) + } } expandSnippet (line, cursor, cm, snippets) { diff --git a/browser/components/MarkdownEditor.js b/browser/components/MarkdownEditor.js index 2b388f90..a9a041df 100644 --- a/browser/components/MarkdownEditor.js +++ b/browser/components/MarkdownEditor.js @@ -235,7 +235,7 @@ class MarkdownEditor extends React.Component { if (this.props.ignorePreviewPointerEvents) previewStyle.pointerEvents = 'none' const storage = findStorage(storageKey) - + return (
this.handleChange(e)} onBlur={(e) => this.handleBlur(e)} /> diff --git a/browser/components/MarkdownSplitEditor.js b/browser/components/MarkdownSplitEditor.js index 8fa3cc07..ddc9d7e0 100644 --- a/browser/components/MarkdownSplitEditor.js +++ b/browser/components/MarkdownSplitEditor.js @@ -158,6 +158,7 @@ class MarkdownSplitEditor extends React.Component { rulers={config.editor.rulers} scrollPastEnd={config.editor.scrollPastEnd} fetchUrlTitle={config.editor.fetchUrlTitle} + enableTableEditor={config.editor.enableTableEditor} storageKey={storageKey} noteKey={noteKey} onChange={this.handleOnChange.bind(this)} diff --git a/browser/lib/TextEditorInterface.js b/browser/lib/TextEditorInterface.js index 53ae2337..8e80c313 100644 --- a/browser/lib/TextEditorInterface.js +++ b/browser/lib/TextEditorInterface.js @@ -1,53 +1,117 @@ -import { Point } from '@susisu/mte-kernel' - -export default class TextEditorInterface { - constructor (editor) { - this.editor = editor - } - - getCursorPosition () { - const pos = this.editor.getCursor() - return new Point(pos.line, pos.ch) - } - - setCursorPosition (pos) { - this.editor.setCursor({line: pos.row, ch: pos.column}) - } - - setSelectionRange (range) { - this.editor.setSelection({ - anchor: {line: range.start.row, ch: range.start.column}, - head: {line: range.end.row, ch: range.end.column} - }) - } - - getLastRow () { - return this.editor.lastLine() - } - - acceptsTableEdit (row) { - return true - } - - getLine (row) { - return this.editor.getLine(row) - } - - insertLine (row, line) { - this.editor.replaceRange(line, {line: row, ch: 0}) - } - - deleteLine (row) { - this.editor.replaceRange('', {line: row, ch: 0}, {line: row, ch: this.editor.getLine(row).length}) - } - - replaceLines (startRow, endRow, lines) { - endRow-- // because endRow is a first line after a table. - const endRowCh = this.editor.getLine(endRow).length - this.editor.replaceRange(lines, {line: startRow, ch: 0}, {line: endRow, ch: endRowCh}) - } - - transact (func) { - func() - } -} +import { Point } from '@susisu/mte-kernel' + +export default class TextEditorInterface { + constructor (editor) { + this.editor = editor + this.doc = editor.getDoc() + this.transaction = false + } + + getCursorPosition() { + const { line, ch } = this.doc.getCursor() + return new Point(line, ch) + } + + setCursorPosition(pos) { + this.doc.setCursor({ + line: pos.row, + ch: pos.column + }) + } + + setSelectionRange(range) { + this.doc.setSelection( + { line: range.start.row, ch: range.start.column }, + { line: range.end.row, ch: range.end.column } + ) + } + + getLastRow() { + return this.doc.lineCount() - 1 + } + + acceptsTableEdit() { + return true + } + + getLine(row) { + return this.doc.getLine(row) + } + + insertLine(row, line) { + const lastRow = this.getLastRow() + if (row > lastRow) { + const lastLine = this.getLine(lastRow) + this.doc.replaceRange( + '\n' + line, + { line: lastRow, ch: lastLine.length }, + { line: lastRow, ch: lastLine.length } + ) + } + else { + this.doc.replaceRange( + line + '\n', + { line: row, ch: 0 }, + { line: row, ch: 0 } + ) + } + } + + deleteLine(row) { + const lastRow = this.getLastRow() + if (row >= lastRow) { + if (lastRow > 0) { + const preLastLine = this.getLine(lastRow - 1) + const lastLine = this.getLine(lastRow) + this.doc.replaceRange( + '', + { line: lastRow - 1, ch: preLastLine.length }, + { line: lastRow, ch: lastLine.length } + ) + } + else { + const lastLine = this.getLine(lastRow) + this.doc.replaceRange( + '', + { line: lastRow, ch: 0 }, + { line: lastRow, ch: lastLine.length } + ) + } + } + else { + this.doc.replaceRange( + '', + { line: row, ch: 0 }, + { line: row + 1, ch: 0 } + ) + } + } + + replaceLines(startRow, endRow, lines) { + const lastRow = this.getLastRow() + if (endRow > lastRow) { + const lastLine = this.getLine(lastRow) + this.doc.replaceRange( + lines.join('\n'), + { line: startRow, ch: 0 }, + { line: lastRow, ch: lastLine.length } + ) + } + else { + this.doc.replaceRange( + lines.join('\n') + '\n', + { line: startRow, ch: 0 }, + { line: endRow, ch: 0 } + ) + } + } + + transact(func) { + this.transaction = true + func() + this.transaction = false + if (this.onDidFinishTransaction) { + this.onDidFinishTransaction.call(undefined) + } + } +} diff --git a/browser/main/Detail/SnippetNoteDetail.js b/browser/main/Detail/SnippetNoteDetail.js index 652d1f53..2fe96420 100644 --- a/browser/main/Detail/SnippetNoteDetail.js +++ b/browser/main/Detail/SnippetNoteDetail.js @@ -691,6 +691,7 @@ class SnippetNoteDetail extends React.Component { keyMap={config.editor.keyMap} scrollPastEnd={config.editor.scrollPastEnd} fetchUrlTitle={config.editor.fetchUrlTitle} + enableTableEditor={config.editor.enableTableEditor} onChange={(e) => this.handleCodeChange(index)(e)} ref={'code-' + index} /> diff --git a/browser/main/lib/ConfigManager.js b/browser/main/lib/ConfigManager.js index 434b0d22..2c601b57 100644 --- a/browser/main/lib/ConfigManager.js +++ b/browser/main/lib/ConfigManager.js @@ -46,7 +46,8 @@ export const DEFAULT_CONFIG = { switchPreview: 'BLUR', // Available value: RIGHTCLICK, BLUR scrollPastEnd: false, type: 'SPLIT', - fetchUrlTitle: true + fetchUrlTitle: true, + enableTableEditor: false }, preview: { fontSize: '14', diff --git a/browser/main/modals/PreferencesModal/UiTab.js b/browser/main/modals/PreferencesModal/UiTab.js index aa3568e7..f8a9ab11 100644 --- a/browser/main/modals/PreferencesModal/UiTab.js +++ b/browser/main/modals/PreferencesModal/UiTab.js @@ -86,7 +86,8 @@ class UiTab extends React.Component { switchPreview: this.refs.editorSwitchPreview.value, keyMap: this.refs.editorKeyMap.value, scrollPastEnd: this.refs.scrollPastEnd.checked, - fetchUrlTitle: this.refs.editorFetchUrlTitle.checked + fetchUrlTitle: this.refs.editorFetchUrlTitle.checked, + enableTableEditor: this.refs.enableTableEditor.checked }, preview: { fontSize: this.refs.previewFontSize.value, @@ -419,6 +420,17 @@ class UiTab extends React.Component { {i18n.__('Bring in web page title when pasting URL on editor')}
+ +
+ +
{i18n.__('Preview')}
diff --git a/locales/en.json b/locales/en.json index a9767492..6b12c1e7 100644 --- a/locales/en.json +++ b/locales/en.json @@ -175,5 +175,6 @@ "Allow styles": "Allow styles", "Allow dangerous html tags": "Allow dangerous html tags", "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.", - "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠" + "⚠ 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! ⚠", + "Enable smart table editor": "Enable smart table editor" } diff --git a/locales/fr.json b/locales/fr.json index 8b880aa6..e9b2c168 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -152,5 +152,6 @@ "Allow styles": "Accepter les styles", "Allow dangerous html tags": "Accepter les tags html dangereux", "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "Convertir des flèches textuelles en jolis signes. ⚠ Cela va interferérer avec les éventuels commentaires HTML dans votre Markdown.", - "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ Vous avez collé un lien qui référence une pièce-jointe qui n'a pas pu être récupéré dans le dossier de stockage de la note. Coller des liens qui font référence à des pièces-jointes ne fonctionne que si la source et la destination et la même. Veuillez plutôt utiliser du Drag & Drop ! ⚠" + "⚠ 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 ! ⚠", + "Enable smart table editor": "Activer l'intelligent éditeur de tableaux" } From 7cf9dda82108b69b34e3ebe7e1494712701f2e04 Mon Sep 17 00:00:00 2001 From: Baptiste Augrain Date: Mon, 20 Aug 2018 20:29:10 +0200 Subject: [PATCH 007/129] fix lint errors --- browser/components/CodeEditor.js | 90 +++++++++---------- browser/components/MarkdownEditor.js | 2 +- browser/lib/TextEditorInterface.js | 32 +++---- browser/main/modals/PreferencesModal/UiTab.js | 2 +- 4 files changed, 61 insertions(+), 65 deletions(-) diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index 36779e4f..b2301c08 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -5,7 +5,7 @@ import CodeMirror from 'codemirror' import 'codemirror-mode-elixir' import attachmentManagement from 'browser/main/lib/dataApi/attachmentManagement' import convertModeName from 'browser/lib/convertModeName' -import { options, TableEditor } from '@susisu/mte-kernel' +import { options, TableEditor, Alignment } from '@susisu/mte-kernel' import TextEditorInterface from 'browser/lib/TextEditorInterface' import eventEmitter from 'browser/main/lib/eventEmitter' import iconv from 'iconv-lite' @@ -143,7 +143,7 @@ export default class CodeEditor extends React.Component { override: true } }) - + this.setMode(this.props.mode) this.editor.on('focus', this.focusHandler) @@ -164,11 +164,11 @@ export default class CodeEditor extends React.Component { CodeMirror.Vim.defineEx('qw', 'qw', this.quitEditor) CodeMirror.Vim.map('ZZ', ':q', 'normal') this.setState({ isReady: true }) - + const editorIntf = new TextEditorInterface(this.editor) this.tableEditor = new TableEditor(editorIntf) eventEmitter.on('code:format-table', this.formatTable) - + const defaultKeyMap = CodeMirror.normalizeKeyMap({ Tab: function (cm) { const cursor = cm.getCursor() @@ -221,52 +221,52 @@ export default class CodeEditor extends React.Component { return CodeMirror.Pass } }) - - if(this.props.enableTableEditor) { + + if (this.props.enableTableEditor) { const opts = options({ smartCursor: true }) - + const editorKeyMap = CodeMirror.normalizeKeyMap({ - 'Tab' : () => { this.tableEditor.nextCell(opts) }, - 'Shift-Tab' : () => { this.tableEditor.previousCell(opts) }, - 'Enter' : () => { this.tableEditor.nextRow(opts) }, - 'Ctrl-Enter' : () => { this.tableEditor.escape(opts) }, - 'Cmd-Enter' : () => { this.tableEditor.escape(opts) }, - 'Shift-Ctrl-Left' : () => { this.tableEditor.alignColumn(Alignment.LEFT, opts) }, - 'Shift-Cmd-Left' : () => { this.tableEditor.alignColumn(Alignment.LEFT, opts) }, - 'Shift-Ctrl-Right' : () => { this.tableEditor.alignColumn(Alignment.RIGHT, opts) }, - 'Shift-Cmd-Right' : () => { this.tableEditor.alignColumn(Alignment.RIGHT, opts) }, - 'Shift-Ctrl-Up' : () => { this.tableEditor.alignColumn(Alignment.CENTER, opts) }, - 'Shift-Cmd-Up' : () => { this.tableEditor.alignColumn(Alignment.CENTER, opts) }, - 'Shift-Ctrl-Down' : () => { this.tableEditor.alignColumn(Alignment.NONE, opts) }, - 'Shift-Cmd-Down' : () => { this.tableEditor.alignColumn(Alignment.NONE, opts) }, - 'Ctrl-Left' : () => { this.tableEditor.moveFocus(0, -1, opts) }, - 'Cmd-Left' : () => { this.tableEditor.moveFocus(0, -1, opts) }, - 'Ctrl-Right' : () => { this.tableEditor.moveFocus(0, 1, opts) }, - 'Cmd-Right' : () => { this.tableEditor.moveFocus(0, 1, opts) }, - 'Ctrl-Up' : () => { this.tableEditor.moveFocus(-1, 0, opts) }, - 'Cmd-Up' : () => { this.tableEditor.moveFocus(-1, 0, opts) }, - 'Ctrl-Down' : () => { this.tableEditor.moveFocus(1, 0, opts) }, - 'Cmd-Down' : () => { this.tableEditor.moveFocus(1, 0, opts) }, - 'Ctrl-K Ctrl-I' : () => { this.tableEditor.insertRow(opts) }, - 'Cmd-K Cmd-I' : () => { this.tableEditor.insertRow(opts) }, - 'Ctrl-L Ctrl-I' : () => { this.tableEditor.deleteRow(opts) }, - 'Cmd-L Cmd-I' : () => { this.tableEditor.deleteRow(opts) }, - 'Ctrl-K Ctrl-J' : () => { this.tableEditor.insertColumn(opts) }, - 'Cmd-K Cmd-J' : () => { this.tableEditor.insertColumn(opts) }, - 'Ctrl-L Ctrl-J' : () => { this.tableEditor.deleteColumn(opts) }, - 'Cmd-L Cmd-J' : () => { this.tableEditor.deleteColumn(opts) }, - 'Alt-Shift-Ctrl-Left' : () => { this.tableEditor.moveColumn(-1, opts) }, - 'Alt-Shift-Cmd-Left' : () => { this.tableEditor.moveColumn(-1, opts) }, + 'Tab': () => { this.tableEditor.nextCell(opts) }, + 'Shift-Tab': () => { this.tableEditor.previousCell(opts) }, + 'Enter': () => { this.tableEditor.nextRow(opts) }, + 'Ctrl-Enter': () => { this.tableEditor.escape(opts) }, + 'Cmd-Enter': () => { this.tableEditor.escape(opts) }, + 'Shift-Ctrl-Left': () => { this.tableEditor.alignColumn(Alignment.LEFT, opts) }, + 'Shift-Cmd-Left': () => { this.tableEditor.alignColumn(Alignment.LEFT, opts) }, + 'Shift-Ctrl-Right': () => { this.tableEditor.alignColumn(Alignment.RIGHT, opts) }, + 'Shift-Cmd-Right': () => { this.tableEditor.alignColumn(Alignment.RIGHT, opts) }, + 'Shift-Ctrl-Up': () => { this.tableEditor.alignColumn(Alignment.CENTER, opts) }, + 'Shift-Cmd-Up': () => { this.tableEditor.alignColumn(Alignment.CENTER, opts) }, + 'Shift-Ctrl-Down': () => { this.tableEditor.alignColumn(Alignment.NONE, opts) }, + 'Shift-Cmd-Down': () => { this.tableEditor.alignColumn(Alignment.NONE, opts) }, + 'Ctrl-Left': () => { this.tableEditor.moveFocus(0, -1, opts) }, + 'Cmd-Left': () => { this.tableEditor.moveFocus(0, -1, opts) }, + 'Ctrl-Right': () => { this.tableEditor.moveFocus(0, 1, opts) }, + 'Cmd-Right': () => { this.tableEditor.moveFocus(0, 1, opts) }, + 'Ctrl-Up': () => { this.tableEditor.moveFocus(-1, 0, opts) }, + 'Cmd-Up': () => { this.tableEditor.moveFocus(-1, 0, opts) }, + 'Ctrl-Down': () => { this.tableEditor.moveFocus(1, 0, opts) }, + 'Cmd-Down': () => { this.tableEditor.moveFocus(1, 0, opts) }, + 'Ctrl-K Ctrl-I': () => { this.tableEditor.insertRow(opts) }, + 'Cmd-K Cmd-I': () => { this.tableEditor.insertRow(opts) }, + 'Ctrl-L Ctrl-I': () => { this.tableEditor.deleteRow(opts) }, + 'Cmd-L Cmd-I': () => { this.tableEditor.deleteRow(opts) }, + 'Ctrl-K Ctrl-J': () => { this.tableEditor.insertColumn(opts) }, + 'Cmd-K Cmd-J': () => { this.tableEditor.insertColumn(opts) }, + 'Ctrl-L Ctrl-J': () => { this.tableEditor.deleteColumn(opts) }, + 'Cmd-L Cmd-J': () => { this.tableEditor.deleteColumn(opts) }, + 'Alt-Shift-Ctrl-Left': () => { this.tableEditor.moveColumn(-1, opts) }, + 'Alt-Shift-Cmd-Left': () => { this.tableEditor.moveColumn(-1, opts) }, 'Alt-Shift-Ctrl-Right': () => { this.tableEditor.moveColumn(1, opts) }, - 'Alt-Shift-Cmd-Right' : () => { this.tableEditor.moveColumn(1, opts) }, - 'Alt-Shift-Ctrl-Up' : () => { this.tableEditor.moveRow(-1, opts) }, - 'Alt-Shift-Cmd-Up' : () => { this.tableEditor.moveRow(-1, opts) }, - 'Alt-Shift-Ctrl-Down' : () => { this.tableEditor.moveRow(1, opts) }, - 'Alt-Shift-Cmd-Down' : () => { this.tableEditor.moveRow(1, opts) } + 'Alt-Shift-Cmd-Right': () => { this.tableEditor.moveColumn(1, opts) }, + 'Alt-Shift-Ctrl-Up': () => { this.tableEditor.moveRow(-1, opts) }, + 'Alt-Shift-Cmd-Up': () => { this.tableEditor.moveRow(-1, opts) }, + 'Alt-Shift-Ctrl-Down': () => { this.tableEditor.moveRow(1, opts) }, + 'Alt-Shift-Cmd-Down': () => { this.tableEditor.moveRow(1, opts) } }) - + const updateActiveState = () => { const active = this.tableEditor.cursorIsInTable(opts) if (active) { @@ -276,7 +276,7 @@ export default class CodeEditor extends React.Component { this.tableEditor.resetSmartCursor() } } - + this.editor.on('cursorActivity', () => { if (!editorIntf.transaction) { updateActiveState() diff --git a/browser/components/MarkdownEditor.js b/browser/components/MarkdownEditor.js index a9a041df..c9db7eff 100644 --- a/browser/components/MarkdownEditor.js +++ b/browser/components/MarkdownEditor.js @@ -235,7 +235,7 @@ class MarkdownEditor extends React.Component { if (this.props.ignorePreviewPointerEvents) previewStyle.pointerEvents = 'none' const storage = findStorage(storageKey) - + return (
lastRow) { const lastLine = this.getLine(lastRow) @@ -47,8 +47,7 @@ export default class TextEditorInterface { { line: lastRow, ch: lastLine.length }, { line: lastRow, ch: lastLine.length } ) - } - else { + } else { this.doc.replaceRange( line + '\n', { line: row, ch: 0 }, @@ -57,7 +56,7 @@ export default class TextEditorInterface { } } - deleteLine(row) { + deleteLine (row) { const lastRow = this.getLastRow() if (row >= lastRow) { if (lastRow > 0) { @@ -68,8 +67,7 @@ export default class TextEditorInterface { { line: lastRow - 1, ch: preLastLine.length }, { line: lastRow, ch: lastLine.length } ) - } - else { + } else { const lastLine = this.getLine(lastRow) this.doc.replaceRange( '', @@ -77,8 +75,7 @@ export default class TextEditorInterface { { line: lastRow, ch: lastLine.length } ) } - } - else { + } else { this.doc.replaceRange( '', { line: row, ch: 0 }, @@ -87,7 +84,7 @@ export default class TextEditorInterface { } } - replaceLines(startRow, endRow, lines) { + replaceLines (startRow, endRow, lines) { const lastRow = this.getLastRow() if (endRow > lastRow) { const lastLine = this.getLine(lastRow) @@ -96,8 +93,7 @@ export default class TextEditorInterface { { line: startRow, ch: 0 }, { line: lastRow, ch: lastLine.length } ) - } - else { + } else { this.doc.replaceRange( lines.join('\n') + '\n', { line: startRow, ch: 0 }, @@ -106,7 +102,7 @@ export default class TextEditorInterface { } } - transact(func) { + transact (func) { this.transaction = true func() this.transaction = false diff --git a/browser/main/modals/PreferencesModal/UiTab.js b/browser/main/modals/PreferencesModal/UiTab.js index f8a9ab11..6fda7c3a 100644 --- a/browser/main/modals/PreferencesModal/UiTab.js +++ b/browser/main/modals/PreferencesModal/UiTab.js @@ -420,7 +420,7 @@ class UiTab extends React.Component { {i18n.__('Bring in web page title when pasting URL on editor')}
- +
+ +
+
+ {i18n.__('Snippet Default Language')} +
+
+ +
+
- +
{i18n.__('Snippet Default Language')} @@ -398,7 +398,7 @@ class UiTab extends React.Component { onChange={(e) => this.handleUIChange(e)} > { - _.sortBy(CodeMirror.modeInfo.map(mode => mode.name)).map(name => ()) + _.sortBy(CodeMirror.modeInfo.map(mode => mode.name)).map(name => ()) }
diff --git a/locales/en.json b/locales/en.json index a9767492..ab7b33f6 100644 --- a/locales/en.json +++ b/locales/en.json @@ -175,5 +175,6 @@ "Allow styles": "Allow styles", "Allow dangerous html tags": "Allow dangerous html tags", "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.", - "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠" + "⚠ 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! ⚠", + "Snippet Default Language": "Snippet Default Language" } diff --git a/locales/fr.json b/locales/fr.json index 8b880aa6..e5ce7314 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -152,5 +152,6 @@ "Allow styles": "Accepter les styles", "Allow dangerous html tags": "Accepter les tags html dangereux", "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "Convertir des flèches textuelles en jolis signes. ⚠ Cela va interferérer avec les éventuels commentaires HTML dans votre Markdown.", - "⚠ You have pasted a link referring an attachment that could not be found in the storage location of this note. Pasting links referring attachments is only supported if the source and destination location is the same storage. Please Drag&Drop the attachment instead! ⚠": "⚠ Vous avez collé un lien qui référence une pièce-jointe qui n'a pas pu être récupéré dans le dossier de stockage de la note. Coller des liens qui font référence à des pièces-jointes ne fonctionne que si la source et la destination et la même. Veuillez plutôt utiliser du Drag & Drop ! ⚠" + "⚠ 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 ! ⚠", + "Snippet Default Language": "Langage par défaut d'un snippet" } From 7c0c81207bf0b93d16bd47bf4eb0f326f093a522 Mon Sep 17 00:00:00 2001 From: Baptiste Augrain Date: Fri, 31 Aug 2018 10:27:02 +0200 Subject: [PATCH 031/129] add test --- tests/lib/find-title-test.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/lib/find-title-test.js b/tests/lib/find-title-test.js index 2c91a3dc..f587804c 100644 --- a/tests/lib/find-title-test.js +++ b/tests/lib/find-title-test.js @@ -14,7 +14,8 @@ test('findNoteTitle#find should return a correct title (string)', t => { ['hoge\n====\nfuga', 'hoge'], ['====', '===='], ['```\n# hoge\n```', '```'], - ['hoge', 'hoge'] + ['hoge', 'hoge'], + ['---\nlayout: test\n---\n # hoge', '# hoge'] ] testCases.forEach(testCase => { From 01641b5af4c873a8f4f1b9e277b752c0335e791b Mon Sep 17 00:00:00 2001 From: William Grant Date: Sat, 1 Sep 2018 12:54:48 +1000 Subject: [PATCH 032/129] fixed --- browser/styles/index.styl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/browser/styles/index.styl b/browser/styles/index.styl index 7d32e77a..a52a8f61 100644 --- a/browser/styles/index.styl +++ b/browser/styles/index.styl @@ -5,7 +5,7 @@ $danger-color = #c9302c $danger-lighten-color = lighten(#c9302c, 5%) // Layouts -$statusBar-height = 22px +$statusBar-height = 28px $sideNav-width = 200px $sideNav--folded-width = 44px $topBar-height = 60px From d015b18c66cb76dd83b9dfec2b28eaf61d96c42e Mon Sep 17 00:00:00 2001 From: Junyoung Choi Date: Sat, 1 Sep 2018 16:50:52 +0900 Subject: [PATCH 033/129] Revert flickering fix --- browser/components/CodeEditor.js | 6 ++---- browser/components/MarkdownEditor.js | 3 +-- browser/components/MarkdownPreview.js | 11 ++--------- 3 files changed, 5 insertions(+), 15 deletions(-) diff --git a/browser/components/CodeEditor.js b/browser/components/CodeEditor.js index f16cc53c..d81ce39d 100644 --- a/browser/components/CodeEditor.js +++ b/browser/components/CodeEditor.js @@ -24,7 +24,6 @@ export default class CodeEditor extends React.Component { constructor (props) { super(props) - this.state = { isReady: false } this.scrollHandler = _.debounce(this.handleScroll.bind(this), 100, { leading: false, trailing: true @@ -215,7 +214,7 @@ export default class CodeEditor extends React.Component { CodeMirror.Vim.defineEx('wq', 'wq', this.quitEditor) CodeMirror.Vim.defineEx('qw', 'qw', this.quitEditor) CodeMirror.Vim.map('ZZ', ':q', 'normal') - this.setState({ isReady: true }) + this.tableEditor = new TableEditor(new TextEditorInterface(this.editor)) eventEmitter.on('code:format-table', this.formatTable) } @@ -582,8 +581,7 @@ export default class CodeEditor extends React.Component { style={{ fontFamily, fontSize: fontSize, - width: width, - opacity: this.state.isReady ? '1' : '0' + width: width }} onDrop={e => this.handleDropImage(e)} /> diff --git a/browser/components/MarkdownEditor.js b/browser/components/MarkdownEditor.js index 2b388f90..ee80c887 100644 --- a/browser/components/MarkdownEditor.js +++ b/browser/components/MarkdownEditor.js @@ -6,7 +6,6 @@ import CodeEditor from 'browser/components/CodeEditor' import MarkdownPreview from 'browser/components/MarkdownPreview' import eventEmitter from 'browser/main/lib/eventEmitter' import { findStorage } from 'browser/lib/findStorage' -import debounceRender from 'react-debounce-render' class MarkdownEditor extends React.Component { constructor (props) { @@ -313,4 +312,4 @@ MarkdownEditor.propTypes = { ignorePreviewPointerEvents: PropTypes.bool } -export default debounceRender(CSSModules(MarkdownEditor, styles)) +export default CSSModules(MarkdownEditor, styles) diff --git a/browser/components/MarkdownPreview.js b/browser/components/MarkdownPreview.js index 610585ba..5376a773 100755 --- a/browser/components/MarkdownPreview.js +++ b/browser/components/MarkdownPreview.js @@ -180,9 +180,7 @@ const defaultCodeBlockFontFamily = [ export default class MarkdownPreview extends React.Component { constructor (props) { super(props) - this.state = { - isReady: false - } + this.contextMenuHandler = e => this.handleContextMenu(e) this.mouseDownHandler = e => this.handleMouseDown(e) this.mouseUpHandler = e => this.handleMouseUp(e) @@ -457,7 +455,6 @@ export default class MarkdownPreview extends React.Component { eventEmitter.on('export:save-md', this.saveAsMdHandler) eventEmitter.on('export:save-html', this.saveAsHtmlHandler) eventEmitter.on('print', this.printHandler) - setTimeout(() => this.setState({ isReady: true })) } componentWillUnmount () { @@ -850,11 +847,7 @@ export default class MarkdownPreview extends React.Component { className={ className != null ? 'MarkdownPreview ' + className : 'MarkdownPreview' } - style={ - this.state.isReady - ? Object.assign(style, { opacity: '1' }) - : Object.assign(style, { opacity: '0' }) - } + style={style} tabIndex={tabIndex} ref='root' /> From e9070fadab349fb74b62d74fa4a9fb623833cf6c Mon Sep 17 00:00:00 2001 From: Maciek Date: Sun, 2 Sep 2018 19:38:15 +0200 Subject: [PATCH 034/129] Refactoring : use object destructuring to retain file code style --- browser/main/Detail/SnippetNoteDetail.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/browser/main/Detail/SnippetNoteDetail.js b/browser/main/Detail/SnippetNoteDetail.js index cf4df18c..9a394683 100644 --- a/browser/main/Detail/SnippetNoteDetail.js +++ b/browser/main/Detail/SnippetNoteDetail.js @@ -98,9 +98,10 @@ class SnippetNoteDetail extends React.Component { } handleGenerateToc () { - const currentMode = this.state.note.snippets[this.state.snippetIndex].mode + const { note, snippetIndex } = this.state + const currentMode = note.snippets[snippetIndex].mode if (currentMode.includes('Markdown')) { - const currentEditor = this.refs['code-' + this.state.snippetIndex].refs.code.editor + const currentEditor = this.refs[`code-${snippetIndex}`].refs.code.editor markdownToc.generateInEditor(currentEditor) } } From 6a2242725d4b8397fff3147d018a1af042b9b33a Mon Sep 17 00:00:00 2001 From: Junyoung Choi Date: Tue, 4 Sep 2018 16:11:27 +0900 Subject: [PATCH 035/129] v0.11.9 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index e9949adf..c9e22164 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "boost", "productName": "Boostnote", - "version": "0.11.8", + "version": "0.11.9", "main": "index.js", "description": "Boostnote", "license": "GPL-3.0", From da81f10e04c3c861dfa7b00317bdde0b7e1b97cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Har=C4=99=C5=BClak?= Date: Tue, 4 Sep 2018 21:39:14 +0200 Subject: [PATCH 036/129] Add Polish translations --- locales/pl.json | 230 ++++++++++++++++++++++++------------------------ 1 file changed, 115 insertions(+), 115 deletions(-) diff --git a/locales/pl.json b/locales/pl.json index 33b1b763..626129ff 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -1,155 +1,155 @@ { - "Notes": "Notes", - "Tags": "Tags", - "Preferences": "Preferences", - "Make a note": "Make a note", + "Notes": "Notatki", + "Tags": "Tagi", + "Preferences": "Ustawienia", + "Make a note": "Stwórz notatkę", "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", + "to create a new note": "Aby stworzyć nową notatkę", + "Toggle Mode": "Przełącz tryb", + "Trash": "Kosz", + "MODIFICATION DATE": "DATA MODYFIKACJI", + "Words": "Słowa", + "Letters": "Litery", "STORAGE": "STORAGE", "FOLDER": "FOLDER", - "CREATION DATE": "CREATION DATE", - "NOTE LINK": "NOTE LINK", + "CREATION DATE": "DATA UTWORZENIA", + "NOTE LINK": "LINK NOTATKI", ".md": ".md", ".txt": ".txt", ".html": ".html", "Print": "Print", - "Your preferences for Boostnote": "Your preferences for Boostnote", + "Your preferences for Boostnote": "Twoje ustawienia dla Boostnote", "Storages": "Storages", "Add Storage Location": "Add Storage Location", - "Add Folder": "Add Folder", + "Add Folder": "Dodaj Folder", "Open Storage folder": "Open Storage folder", - "Unlink": "Unlink", - "Edit": "Edit", - "Delete": "Delete", - "Interface": "Interface", - "Interface Theme": "Interface Theme", - "Default": "Default", - "White": "White", + "Unlink": "Odlinkuj", + "Edit": "Edytuj", + "Delete": "Usuń", + "Interface": "Interfejs", + "Interface Theme": "Wygląd interfejsu", + "Default": "Domyślny", + "White": "Biały", "Solarized Dark": "Solarized 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", - "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 Keymap", - "default": "default", + "Dark": "Ciemny", + "Show a confirmation dialog when deleting notes": "Wymagaj potwierdzenia usunięcia notatek", + "Editor Theme": "Wygląd edytota", + "Editor Font Size": "Rozmiar czcionki edytora", + "Editor Font Family": "Czcionka edytora", + "Editor Indent Style": "Rodzaj wcięć edytora", + "Spaces": "Spacje", + "Tabs": "Tabulatory", + "Switch to Preview": "Przełącz na podgląd", + "When Editor Blurred": "Gdy edytor w pracuje w tle", + "When Editor Blurred, Edit On Double Click": "Gdy edytor w pracuje w tle, edytuj za pomocą podwójnego kliknięcia", + "On Right Click": "Kliknięcie prawego przycisku myszy", + "Editor Keymap": "Układ klawiszy edytora", + "default": "domyślny", "vim": "vim", "emacs": "emacs", - "⚠️ Please restart boostnote after you change the keymap": "⚠️ Please restart boostnote after you change the keymap", - "Show line numbers in the editor": "Show line numbers in the editor", + "⚠️ Please restart boostnote after you change the keymap": "⚠️ Wymagane zresetowania Boostnote po zmianie ustawień klawiszy", + "Show line numbers in the editor": "Pokazuj numery lini w edytorze", "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", + "Preview": "Podgląd", + "Preview Font Size": "Podgląd rozmiaru czcionki", + "Preview Font Family": "Podgląd czcionki", + "Code block Theme": "Wygląd bloku kodu", "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 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 Server", - "Community": "Community", - "Subscribe to Newsletter": "Subscribe to Newsletter", + "PlantUML Server": "Serwer PlantUML", + "Community": "Społecznośc", + "Subscribe to Newsletter": "Zapisz do Newsletter", "GitHub": "GitHub", "Blog": "Blog", - "Facebook Group": "Facebook Group", + "Facebook Group": "Grupa Facebook", "Twitter": "Twitter", - "About": "About", + "About": "O nas", "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", + "An open source note-taking app made for programmers just like you.": "Społecznościowa aplikacja do przechowywania notatek, stworzona dla programistów takich jak Ty.", + "Website": "Strona WWW", "Development": "Development", " : Development configurations for Boostnote.": " : Development configurations for Boostnote.", "Copyright (C) 2017 - 2018 BoostIO": "Copyright (C) 2017 - 2018 BoostIO", - "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 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.", - "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": "Enable analytics to help improve Boostnote", + "License: GPL v3": "Licencja: GPL v3", + "Analytics": "Statystyki", + "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 zbiera anonimowe informacje na temat aplikacji by pomóc w jej ulepszaniu, nie pobiera informacji z Twoich notatek.", + "You can see how it works on ": "Możesz zobaczyć jak to działa ", + "You can choose to enable or disable this option.": "Możesz włączyć lub wyłączyć tę opcje.", + "Enable analytics to help improve Boostnote": "Włącz zbierania statystyk by pomóc polepszać Boostnote", "Crowdfunding": "Crowdfunding", - "Dear everyone,": "Dear everyone,", - "Thank you for using Boostnote!": "Thank you for using 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.", - "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!": "If you like this project and see its potential, you can help by supporting us on OpenCollective!", - "Thanks,": "Thanks,", + "Dear everyone,": "Droga społeczności,", + "Thank you for using Boostnote!": "Dziękujemy za używanie Boostnote!", + "Boostnote is used in about 200 different countries and regions by an awesome community of developers.": "Boostnote jest używany w około 200 krajach i regionach przez wspaniałą społeczność programistów.", + "To continue supporting this growth, and to satisfy community expectations,": "Do kontynuowania wzrostu popularności i satysfakcji naszej społeczności,", + "we would like to invest more time and resources in this project.": "chcielibyśmy poświęcić więcej czasu na rozwój naszego projektu.", + "If you like this project and see its potential, you can help by supporting us on OpenCollective!": "Jeśli podoba Ci się naszy projekt i lubisz go używać, możesz wspomóc nasz przez OpenCollective!", + "Thanks,": "Dzięki,", "Boostnote maintainers": "Boostnote maintainers", - "Support via OpenCollective": "Support via OpenCollective", - "Language": "Language", - "English": "English", - "German": "German", - "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 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.", - "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 to switch format", - "Updated": "Updated", - "Created": "Created", - "Alphabetically": "Alphabetically", - "Default View": "Default View", - "Compressed View": "Compressed View", - "Search": "Search", - "Blog Type": "Blog Type", - "Blog Address": "Blog Address", - "Save": "Save", - "Auth": "Auth", - "Authentication Method": "Authentication Method", + "Support via OpenCollective": "Wspomóż przez OpenCollective", + "Language": "Język", + "English": "Angielski", + "German": "Niemiecki", + "French": "Francuski", + "Show \"Saved to Clipboard\" notification when copying": "Pokazuj \"Skopiowano do schowka\" podczas kopiowania", + "All Notes": "Notatki", + "Starred": "Oznaczone", + "Are you sure to ": "Czy na pewno chcesz ", + " delete": " usunąc", + "this folder?": "ten folder?", + "Confirm": "Potwierdź", + "Cancel": "Anuluj", + "Markdown Note": "Notatka Markdown", + "This format is for creating text documents. Checklists, code blocks and Latex blocks are available.": "Ten format pozwala na tworzenie dokumentów tekstowych. List zadań, bloków kodu czy bloków Latex.", + "Snippet Note": "Snippet Kodu", + "This format is for creating code snippets. Multiple snippets can be grouped into a single note.": "Ten format zezwala na tworzenia snippetów kodu. Kilka snippetów można zgrupować w jedną notatkę.", + "Tab to switch format": "Tabulator by zmienić format", + "Updated": "Zaaktualizowano", + "Created": "Stworzono", + "Alphabetically": "Alfabetycznie", + "Default View": "Widok domyślny", + "Compressed View": "Widok skompresowany", + "Search": "Szukaj", + "Blog Type": "Typ bloga", + "Blog Address": "Adres bloga", + "Save": "Zapisz", + "Auth": "Autoryzacja", + "Authentication Method": "Metoda Autoryzacji", "JWT": "JWT", - "USER": "USER", + "USER": "Użutkownik", "Token": "Token", "Storage": "Storage", - "Hotkeys": "Hotkeys", - "Show/Hide Boostnote": "Show/Hide 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", - "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!": "You have to save!", - "Russian": "Russian", + "Hotkeys": "Skróty klawiszowe", + "Show/Hide Boostnote": "Pokaż/Ukryj Boostnote", + "Restore": "Przywróć", + "Permanent Delete": "Usuń trwale", + "Confirm note deletion": "Potwierdź usunięcie notatki", + "This will permanently remove this note.": "Spodowoduje to trwałe usunięcie notatki", + "Successfully applied!": "Sukces!", + "Albanian": "Albański", + "Chinese (zh-CN)": "Chiński (zh-CN)", + "Chinese (zh-TW)": "Chiński (zh-TW)", + "Danish": "Duński", + "Japanese": "Japoński", + "Korean": "Koreański", + "Norwegian": "Norweski", + "Polish": "Polski", + "Portuguese": "Portugalski", + "Spanish": "Hiszpański", + "You have to save!": "Musisz zapisać!", + "Russian": "Rosyjski", "Editor Rulers": "Editor Rulers", - "Enable": "Enable", - "Disable": "Disable", + "Enable": "Włącz", + "Disable": "Wyłącz", "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", + "Only allow secure html tags (recommended)": "Zezwól tylko na bezpieczne tagi HTML (zalecane)", + "Allow styles": "Zezwól na style", + "Allow dangerous html tags": "Zezwól na niebezpieczne tagi HTML", "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! ⚠" } From bb32c3a8d32376debfa7af153a65932a6a39dd98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20J=2E=20P=C3=A9rez=20Nieto?= Date: Wed, 5 Sep 2018 08:41:06 +0200 Subject: [PATCH 037/129] Improved es-ES translation. --- locales/es-ES.json | 46 +++++++++++++++++++++++----------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/locales/es-ES.json b/locales/es-ES.json index 2ee7da71..a301dc9e 100644 --- a/locales/es-ES.json +++ b/locales/es-ES.json @@ -1,8 +1,8 @@ -{ + { "Notes": "Notas", "Tags": "Etiquetas", "Preferences": "Preferencias", - "Make a note": "Tomar una nota", + "Make a note": "Crear nota", "Ctrl": "Ctrl", "Ctrl(^)": "Ctrl", "to create a new note": "para crear una nueva nota", @@ -14,7 +14,7 @@ "STORAGE": "ALMACENAMIENTO", "FOLDER": "CARPETA", "CREATION DATE": "FECHA DE CREACIÓN", - "NOTE LINK": "ENLACE A LA NOTA", + "NOTE LINK": "ENLACE DE LA NOTA", ".md": ".md", ".txt": ".txt", ".html": ".html", @@ -23,7 +23,7 @@ "Storages": "Almacenamientos", "Add Storage Location": "Añadir ubicación de almacenamiento", "Add Folder": "Añadir carpeta", - "Open Storage folder": "Añadir carpeta de almacenamiento", + "Open Storage folder": "Abrir carpeta de almacenamiento", "Unlink": "Desvincular", "Edit": "Editar", "Delete": "Eliminar", @@ -39,8 +39,8 @@ "Editor Font Family": "Fuente del editor", "Editor Indent Style": "Estilo de indentado del editor", "Spaces": "Espacios", - "Tabs": "Tabulación", - "Switch to Preview": "Cambiar a Previsualización", + "Tabs": "Tabulaciónes", + "Switch to Preview": "Cambiar a previsualización", "When Editor Blurred": "Cuando el editor pierde el foco", "When Editor Blurred, Edit On Double Click": "Cuando el editor pierde el foco, editar con doble clic", "On Right Click": "Al hacer clic derecho", @@ -48,19 +48,19 @@ "default": "por defecto", "vim": "vim", "emacs": "emacs", - "⚠️ Please restart boostnote after you change the keymap": "⚠️ Reinicie boostnote después de cambiar el mapeo de teclas", + "⚠️ Please restart boostnote after you change the keymap": "⚠️ Por favor reinicie boostnote después de cambiar el mapeo de teclas", "Show line numbers in the editor": "Mostrar números de línea en el editor", "Allow editor to scroll past the last line": "Permitir al editor desplazarse más allá de la última línea", - "Bring in web page title when pasting URL on editor": "Al pegar una URL en el editor, insertar el título de la web automáticamente", - "Preview": "Previsualización", + "Bring in web page title when pasting URL on editor": "Al pegar una URL en el editor, insertar el título de la web", + "Preview": "Previsualizar", "Preview Font Size": "Previsualizar tamaño de la fuente", "Preview Font Family": "Previsualizar fuente", "Code block Theme": "Tema de los bloques de código", "Allow preview to scroll past the last line": "Permitir a la previsualización desplazarse más allá de la última línea", - "Show line numbers for preview code blocks": "Mostar números de línea al previsualizar bloques de código", + "Show line numbers for preview code blocks": "Mostrar números de línea al previsualizar bloques de código", "LaTeX Inline Open Delimiter": "Delimitador de apertura LaTeX en línea", "LaTeX Inline Close Delimiter": "Delimitador de cierre LaTeX en línea", - "LaTeX Block Open Delimiter": "Delimitado de apertura bloque LaTeX", + "LaTeX Block Open Delimiter": "Delimitador de apertura bloque LaTeX", "LaTeX Block Close Delimiter": "Delimitador de cierre bloque LaTeX", "PlantUML Server": "PlantUML Server", "Community": "Comunidad", @@ -71,20 +71,20 @@ "Twitter": "Twitter", "About": "Sobre", "Boostnote": "Boostnote", - "An open source note-taking app made for programmers just like you.": "Una aplicación para tomar notas de código abieto para programadores como tú.", + "An open source note-taking app made for programmers just like you.": "Una aplicación de código abierto para tomar notas hecho para programadores como tú.", "Website": "Página web", "Development": "Desarrollo", " : Development configurations for Boostnote.": " : Configuraciones de desarrollo para Boostnote.", "Copyright (C) 2017 - 2018 BoostIO": "Copyright (C) 2017 - 2018 BoostIO", "License: GPL v3": "Licencia: GPL v3", "Analytics": "Analítica", - "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 recopila datos anónimos con el único propósito de mejorar la aplicación. No recopila ninguna información personal, como puede ser el contenido de sus notas.", + "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 recopila datos anónimos con el único propósito de mejorar la aplicación, y de ninguna manera recopila información personal como el contenido de sus notas.", "You can see how it works on ": "Puedes ver cómo funciona en ", "You can choose to enable or disable this option.": "Puedes elegir activar o desactivar esta opción.", - "Enable analytics to help improve Boostnote": "Activa analítica para ayudar a mejorar Boostnote", + "Enable analytics to help improve Boostnote": "Activar analítica para ayudar a mejorar Boostnote", "Crowdfunding": "Crowdfunding", "Dear everyone,": "Hola a todos,", - "Thank you for using Boostnote!": "Gracias por usar Boostnote!", + "Thank you for using Boostnote!": "¡Gracias por usar Boostnote!", "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,", "we would like to invest more time and resources in this project.": "nos gustaría invertir más tiempo y recursos en este proyecto.", @@ -99,7 +99,7 @@ "Show \"Saved to Clipboard\" notification when copying": "Mostrar la notificaión \"Guardado en Portapapeles\" al copiar", "All Notes": "Todas las notas", "Starred": "Destacado", - "Are you sure to ": "Estás seguro de ", + "Are you sure to ": "¿Estás seguro de ", " delete": " eliminar", "this folder?": "esta carpeta?", "Confirm": "Confirmar", @@ -129,8 +129,8 @@ "Restore": "Restaurar", "Permanent Delete": "Eliminar permanentemente", "Confirm note deletion": "Confirmar eliminación de nota", - "This will permanently remove this note.": "La nota se eliminará permanentemente.", - "Successfully applied!": "Aplicado con éxito!", + "This will permanently remove this note.": "Esto eliminará la nota permanentemente.", + "Successfully applied!": "¡Aplicado con éxito!", "Albanian": "Albanés", "Chinese (zh-CN)": "Chino - China", "Chinese (zh-TW)": "Chino - Taiwan", @@ -139,11 +139,11 @@ "Korean": "Coreano", "Norwegian": "Noruego", "Polish": "Polaco", - "Portuguese": "Portugues", + "Portuguese": "Portugués", "Spanish": "Español", - "You have to save!": "Tienes que guardar!", + "You have to save!": "¡Tienes que guardar!", "Russian": "Ruso", - "Command(⌘)": "Command(⌘)", + "Command(⌘)": "Comando(⌘)", "Editor Rulers": "Reglas del editor", "Enable": "Activar", "Disable": "Desactivar", @@ -151,6 +151,6 @@ "Only allow secure html tags (recommended)": "Solo permitir etiquetas html seguras (recomendado)", "Allow styles": "Permitir estilos", "Allow dangerous html tags": "Permitir etiquetas html peligrosas", - "⚠ 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! ⚠", - "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 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! ⚠": "⚠ Ha pegado un enlace a un archivo adjunto que no se puede encontrar en el almacenamiento de esta nota. Pegar enlaces a archivos adjuntos solo está soportado si el origen y el destino son el mismo almacenamiento. ¡Por favor arrastre el archivo en su lugar! ⚠", + "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "Convertir flechas textuales a símbolos bonitos. ⚠ Esto interferirá cuando use comentarios HTML en Markdown." } From d9783490ecdb2aff3ce7904415d8d44e672940b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20J=2E=20P=C3=A9rez=20Nieto?= Date: Wed, 5 Sep 2018 08:48:43 +0200 Subject: [PATCH 038/129] New phrase from last commit Added the new phrase from last commit. --- locales/es-ES.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/locales/es-ES.json b/locales/es-ES.json index a301dc9e..d78f8153 100644 --- a/locales/es-ES.json +++ b/locales/es-ES.json @@ -152,5 +152,6 @@ "Allow styles": "Permitir estilos", "Allow dangerous html tags": "Permitir etiquetas html peligrosas", "⚠ You have pasted a link referring an attachment that could not be found in the 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! ⚠": "⚠ Ha pegado un enlace a un archivo adjunto que no se puede encontrar en el almacenamiento de esta nota. Pegar enlaces a archivos adjuntos solo está soportado si el origen y el destino son el mismo almacenamiento. ¡Por favor arrastre el archivo en su lugar! ⚠", - "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "Convertir flechas textuales a símbolos bonitos. ⚠ Esto interferirá cuando use comentarios HTML en Markdown." + "Convert textual arrows to beautiful signs. ⚠ This will interfere with using HTML comments in your Markdown.": "Convertir flechas textuales a símbolos bonitos. ⚠ Esto interferirá cuando use comentarios HTML en Markdown.", + "Snippet Default Language": "Lenguaje por defecto de los fragmentos de código" } From 1c8e379fdddab1f431bfbb55764d674d01e7fcfe Mon Sep 17 00:00:00 2001 From: Baptiste Augrain Date: Wed, 5 Sep 2018 17:08:39 +0200 Subject: [PATCH 039/129] add option for default new note --- browser/lib/newNote.js | 62 +++++++++++++++++ browser/main/NewNoteButton/index.js | 23 +++++-- browser/main/modals/NewNoteModal.js | 66 ++----------------- browser/main/modals/PreferencesModal/UiTab.js | 17 +++++ 4 files changed, 102 insertions(+), 66 deletions(-) create mode 100644 browser/lib/newNote.js diff --git a/browser/lib/newNote.js b/browser/lib/newNote.js new file mode 100644 index 00000000..d9834dec --- /dev/null +++ b/browser/lib/newNote.js @@ -0,0 +1,62 @@ +import { hashHistory } from 'react-router' +import dataApi from 'browser/main/lib/dataApi' +import ee from 'browser/main/lib/eventEmitter' +import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig' + +export function createMarkdownNote (storage, folder, dispatch, location) { + AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_MARKDOWN') + AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE') + return dataApi + .createNote(storage, { + type: 'MARKDOWN_NOTE', + folder: folder, + title: '', + content: '' + }) + .then(note => { + const noteHash = note.key + dispatch({ + type: 'UPDATE_NOTE', + note: note + }) + + hashHistory.push({ + pathname: location.pathname, + query: { key: noteHash } + }) + ee.emit('list:jump', noteHash) + ee.emit('detail:focus') + }) +} + +export function createSnippetNote (storage, folder, dispatch, location, config) { + AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_SNIPPET') + AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE') + return dataApi + .createNote(storage, { + type: 'SNIPPET_NOTE', + folder: folder, + title: '', + description: '', + snippets: [ + { + name: '', + mode: config.editor.snippetDefaultLanguage || 'text', + content: '' + } + ] + }) + .then(note => { + const noteHash = note.key + dispatch({ + type: 'UPDATE_NOTE', + note: note + }) + hashHistory.push({ + pathname: location.pathname, + query: { key: noteHash } + }) + ee.emit('list:jump', noteHash) + ee.emit('detail:focus') + }) +} \ No newline at end of file diff --git a/browser/main/NewNoteButton/index.js b/browser/main/NewNoteButton/index.js index 85dc7f40..85fbbfbf 100644 --- a/browser/main/NewNoteButton/index.js +++ b/browser/main/NewNoteButton/index.js @@ -7,6 +7,7 @@ import modal from 'browser/main/lib/modal' import NewNoteModal from 'browser/main/modals/NewNoteModal' import eventEmitter from 'browser/main/lib/eventEmitter' import i18n from 'browser/lib/i18n' +import { createMarkdownNote, createSnippetNote } from 'browser/lib/newNote' const { remote } = require('electron') const { dialog } = remote @@ -37,13 +38,21 @@ class NewNoteButton extends React.Component { const { location, dispatch, config } = this.props const { storage, folder } = this.resolveTargetFolder() - modal.open(NewNoteModal, { - storage: storage.key, - folder: folder.key, - dispatch, - location, - config - }) + console.log(config) + + if (config.ui.defaultNote === 'MARKDOWN_NOTE') { + createMarkdownNote(storage.key, folder.key, dispatch, location) + } else if (config.ui.defaultNote === 'SNIPPET_NOTE') { + createSnippetNote(storage.key, folder.key, dispatch, location, config) + } else { + modal.open(NewNoteModal, { + storage: storage.key, + folder: folder.key, + dispatch, + location, + config + }) + } } resolveTargetFolder () { diff --git a/browser/main/modals/NewNoteModal.js b/browser/main/modals/NewNoteModal.js index f6aa2c67..8b16f2a2 100644 --- a/browser/main/modals/NewNoteModal.js +++ b/browser/main/modals/NewNoteModal.js @@ -1,12 +1,9 @@ import React from 'react' import CSSModules from 'browser/lib/CSSModules' import styles from './NewNoteModal.styl' -import dataApi from 'browser/main/lib/dataApi' -import { hashHistory } from 'react-router' -import ee from 'browser/main/lib/eventEmitter' import ModalEscButton from 'browser/components/ModalEscButton' -import AwsMobileAnalyticsConfig from 'browser/main/lib/AwsMobileAnalyticsConfig' import i18n from 'browser/lib/i18n' +import { createMarkdownNote, createSnippetNote } from 'browser/lib/newNote' class NewNoteModal extends React.Component { constructor (props) { @@ -24,31 +21,10 @@ class NewNoteModal extends React.Component { } handleMarkdownNoteButtonClick (e) { - AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_MARKDOWN') - AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE') const { storage, folder, dispatch, location } = this.props - dataApi - .createNote(storage, { - type: 'MARKDOWN_NOTE', - folder: folder, - title: '', - content: '' - }) - .then(note => { - const noteHash = note.key - dispatch({ - type: 'UPDATE_NOTE', - note: note - }) - - hashHistory.push({ - pathname: location.pathname, - query: { key: noteHash } - }) - ee.emit('list:jump', noteHash) - ee.emit('detail:focus') - setTimeout(this.props.close, 200) - }) + createMarkdownNote(storage, folder, dispatch, location).then(() => { + setTimeout(this.props.close, 200) + }) } handleMarkdownNoteButtonKeyDown (e) { @@ -59,38 +35,10 @@ class NewNoteModal extends React.Component { } handleSnippetNoteButtonClick (e) { - AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_SNIPPET') - AwsMobileAnalyticsConfig.recordDynamicCustomEvent('ADD_ALLNOTE') const { storage, folder, dispatch, location, config } = this.props - - dataApi - .createNote(storage, { - type: 'SNIPPET_NOTE', - folder: folder, - title: '', - description: '', - snippets: [ - { - name: '', - mode: config.editor.snippetDefaultLanguage || 'text', - content: '' - } - ] - }) - .then(note => { - const noteHash = note.key - dispatch({ - type: 'UPDATE_NOTE', - note: note - }) - hashHistory.push({ - pathname: location.pathname, - query: { key: noteHash } - }) - ee.emit('list:jump', noteHash) - ee.emit('detail:focus') - setTimeout(this.props.close, 200) - }) + createSnippetNote(storage, folder, dispatch, location, config).then(() => { + setTimeout(this.props.close, 200) + }) } handleSnippetNoteButtonKeyDown (e) { diff --git a/browser/main/modals/PreferencesModal/UiTab.js b/browser/main/modals/PreferencesModal/UiTab.js index 74047d44..6661d95d 100644 --- a/browser/main/modals/PreferencesModal/UiTab.js +++ b/browser/main/modals/PreferencesModal/UiTab.js @@ -67,6 +67,7 @@ class UiTab extends React.Component { ui: { theme: this.refs.uiTheme.value, language: this.refs.uiLanguage.value, + defaultNote: this.refs.defaultNote.value, showCopyNotification: this.refs.showCopyNotification.checked, confirmDeletion: this.refs.confirmDeletion.checked, showOnlyRelatedTags: this.refs.showOnlyRelatedTags.checked, @@ -202,6 +203,22 @@ class UiTab extends React.Component {
+
+
+ {i18n.__('Default New Note')} +
+
+ +
+
+