diff --git a/src/editor/contentState/index.js b/src/editor/contentState/index.js index fbd8d02c..02999020 100644 --- a/src/editor/contentState/index.js +++ b/src/editor/contentState/index.js @@ -46,6 +46,7 @@ class ContentState { constructor (options) { const { eventCenter, bulletListMarker } = options Object.assign(this, options) + // Use to cache the keys which you don't want to remove. this.exemption = new Set() this.blocks = [ this.createBlockP() ] diff --git a/src/editor/contentState/tabCtrl.js b/src/editor/contentState/tabCtrl.js index 42d5db1a..1ecfcb97 100644 --- a/src/editor/contentState/tabCtrl.js +++ b/src/editor/contentState/tabCtrl.js @@ -118,25 +118,27 @@ const tabCtrl = ContentState => { } this.appendChild(newList, listItem) - this.partialRender() + return this.partialRender() } - // ContentState.prototype.insertTab = function () { - // // TODO(fxha): Tabs and all spaces with length > 1 are converted to a single space - // in editor mode. Maybe write a HTML "tab" element - // // TODO(fxha): create setting entry "tabSize: " - // const tabCharacter = new Array(4).join(' ') - // const { start, end } = this.cursor - // const startBlock = this.getBlock(start.key) - // const endBlock = this.getBlock(end.key) - // if (this.cursor.start.key === this.cursor.end.key) { - // startBlock.text = startBlock.text.substring(0, start.offset) + tabCharacter + endBlock.text.substring(end.offset) - // // workaround: see todo 1 - // this.cursor.start.offset += 1 // tabCharacter.length - // this.cursor.end.offset += 1 // tabCharacter.length - // this.render() - // } - // } + ContentState.prototype.insertTab = function () { + const tabSize = this.tabSize + const tabCharacter = ' '.repeat(tabSize) + const { start, end } = this.cursor + const startBlock = this.getBlock(start.key) + const endBlock = this.getBlock(end.key) + if (start.key === end.key && start.offset === end.offset) { + startBlock.text = startBlock.text.substring(0, start.offset) + + tabCharacter + endBlock.text.substring(end.offset) + const key = start.key + const offset = start.offset + tabCharacter.length + this.cursor = { + start: { key, offset }, + end: { key, offset } + } + return this.partialRender() + } + } ContentState.prototype.tabHandler = function (event) { // disable tab focus @@ -173,9 +175,8 @@ const tabCtrl = ContentState => { if (this.isIndentableListItem()) { return this.indentListItem() - } // else { - // this.insertTab() - // } + } + return this.insertTab() } } diff --git a/src/editor/index.js b/src/editor/index.js index b9e93b34..4fb05512 100644 --- a/src/editor/index.js +++ b/src/editor/index.js @@ -21,7 +21,8 @@ class Aganippe { constructor (container, options) { const { focusMode = false, theme = 'light', markdown = '', preferLooseListItem = true, - autoPairBracket = true, autoPairMarkdownSyntax = true, autoPairQuote = true, bulletListMarker = '-' + autoPairBracket = true, autoPairMarkdownSyntax = true, autoPairQuote = true, + bulletListMarker = '-', tabSize = 4 } = options this.container = container const eventCenter = this.eventCenter = new EventCenter() @@ -35,7 +36,8 @@ class Aganippe { autoPairBracket, autoPairMarkdownSyntax, autoPairQuote, - bulletListMarker + bulletListMarker, + tabSize }) this.emoji = new Emoji() // emoji instance: has search(text) clear() methods. this.focusMode = focusMode @@ -539,6 +541,16 @@ class Aganippe { this.contentState.preferLooseListItem = preferLooseListItem } + setTabSize (tabSize) { + if (!tabSize || typeof tabSize !== 'number') { + tabSize = 4 + } else if (tabSize < 1) { + tabSize = 1 + } + this.tabSize = tabSize + this.contentState.tabSize = tabSize + } + updateParagraph (type) { this.contentState.updateParagraph(type) } diff --git a/src/renderer/components/editor.vue b/src/renderer/components/editor.vue index 2fca3ef2..a39754ab 100644 --- a/src/renderer/components/editor.vue +++ b/src/renderer/components/editor.vue @@ -100,7 +100,7 @@ }, computed: { ...mapState([ - 'preferLooseListItem', 'autoPairBracket', 'autoPairMarkdownSyntax', 'autoPairQuote', 'bulletListItemMarker' + 'preferLooseListItem', 'autoPairBracket', 'autoPairMarkdownSyntax', 'autoPairQuote', 'bulletListItemMarker', 'tabSize' ]) }, data () { @@ -150,6 +150,12 @@ if (value !== oldValue && editor) { editor.setListItemPreference(value) } + }, + tabSize: function (value, oldValue) { + const { editor } = this + if (value !== oldValue && editor) { + editor.setTabSize(value) + } } }, created () { @@ -164,7 +170,8 @@ autoPairBracket, autoPairMarkdownSyntax, autoPairQuote, - bulletListMarker + bulletListMarker, + tabSize } = this const { container } = this.editor = new Aganippe(ele, { @@ -175,7 +182,8 @@ autoPairBracket, autoPairMarkdownSyntax, autoPairQuote, - bulletListMarker + bulletListMarker, + tabSize }) if (typewriter) { diff --git a/src/renderer/store/editor.js b/src/renderer/store/editor.js index 2eee14ce..369a335d 100644 --- a/src/renderer/store/editor.js +++ b/src/renderer/store/editor.js @@ -23,6 +23,7 @@ const state = { autoPairBracket: true, autoPairMarkdownSyntax: true, autoPairQuote: true, + tabSize: 4, // edit mode typewriter: false, // typewriter mode focus: false, // focus mode diff --git a/static/preference.md b/static/preference.md index bc9f1adf..7fcf6d4b 100755 --- a/static/preference.md +++ b/static/preference.md @@ -25,7 +25,8 @@ Edit and save to update preferences. You can only change the JSON below! "autoPairBracket": true, "autoPairMarkdownSyntax": true, "autoPairQuote": true, - "endOfLine": "default" + "endOfLine": "default", + "tabSize": 4 } ```