From 40f8b237267e559b79400d9c5064e50734ad0ef2 Mon Sep 17 00:00:00 2001 From: Peter Savchenko Date: Wed, 10 Mar 2021 12:42:01 +0300 Subject: [PATCH] feature: indentations by tab --- package.json | 2 +- src/index.js | 75 ++++++++++++++++++++++++++++++++++++++++++--- src/utils/string.js | 35 +++++++++++++++++++++ webpack.config.js | 15 ++++----- 4 files changed, 115 insertions(+), 12 deletions(-) create mode 100644 src/utils/string.js diff --git a/package.json b/package.json index 3fb5f1f..98fff55 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@editorjs/code", - "version": "2.6.0", + "version": "2.7.0", "keywords": [ "codex editor", "code", diff --git a/src/index.js b/src/index.js index 0f0dd71..d7506d9 100644 --- a/src/index.js +++ b/src/index.js @@ -1,7 +1,8 @@ /** * Build styles */ -require('./index.css').toString(); +import { getLineStartPosition } from './utils/string'; +import './index.css'; /** * CodeTool for Editor.js @@ -17,7 +18,7 @@ require('./index.css').toString(); /** * Code Tool for the Editor.js allows to include code examples in your articles. */ -class CodeTool { +export default class CodeTool { /** * Notify core that read-only mode is supported @@ -99,6 +100,17 @@ class CodeTool { wrapper.appendChild(textarea); + /** + * Enable keydown handlers + */ + textarea.addEventListener('keydown', (event) => { + switch (event.code) { + case 'Tab': + this.tabHandler(event); + break; + } + }); + this.nodes.textarea = textarea; return wrapper; @@ -209,6 +221,61 @@ class CodeTool { code: true, // Allow HTML tags }; } -} -module.exports = CodeTool; + /** + * Handles Tab key pressing (adds/removes indentations) + * + * @private + * @param {KeyboardEvent} event - keydown + * @returns {void} + */ + tabHandler(event) { + /** + * Prevent editor.js tab handler + */ + event.stopPropagation(); + + /** + * Prevent native tab behaviour + */ + event.preventDefault(); + + const textarea = event.target; + const isShiftPressed = event.shiftKey; + const caretPosition = textarea.selectionStart; + const value = textarea.value; + const indentation = ' '; + + let newCaretPosition; + + /** + * For Tab pressing, just add an indentation to the caret position + */ + if (!isShiftPressed) { + newCaretPosition = caretPosition + indentation.length; + + textarea.value = value.substring(0, caretPosition) + indentation + value.substring(caretPosition); + } else { + /** + * For Shift+Tab pressing, remove an indentation from the start of line + */ + const currentLineStart = getLineStartPosition(value, caretPosition); + const firstLineChars = value.substr(currentLineStart, indentation.length); + + if (firstLineChars !== indentation) { + return; + } + + /** + * Trim the first two chars from the start of line + */ + textarea.value = value.substring(0, currentLineStart) + value.substring(currentLineStart + indentation.length); + newCaretPosition = caretPosition - indentation.length; + } + + /** + * Restore the caret + */ + textarea.setSelectionRange(newCaretPosition, newCaretPosition); + } +} diff --git a/src/utils/string.js b/src/utils/string.js new file mode 100644 index 0000000..06d220f --- /dev/null +++ b/src/utils/string.js @@ -0,0 +1,35 @@ +/** + * Return the position of line starting from passed point + * + * ┌───────────────┐ + * │1234\n │ + * │2eda | dadd\n │ <-- returns 5 + * └───────────────┘ + * + * @param {string} string - string to process + * @param {number} position - search starting position + * @returns {number} + */ +export function getLineStartPosition(string, position) { + const charLength = 1; + let char = ''; + + /** + * Iterate through all the chars before the position till the + * - end of line (\n) + * - or start of string (position === 0) + */ + while (char !== '\n' && position > 0) { + position = position - charLength; + char = string.substr(position, charLength); + } + + /** + * Do not count the linebreak symbol because it is related to the previous line + */ + if (char === '\n') { + position += 1; + } + + return position; +} diff --git a/webpack.config.js b/webpack.config.js index 829fd5b..9e90446 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -12,22 +12,23 @@ module.exports = { presets: [ '@babel/preset-env' ], }, }, - ] + ], }, { test: /\.css$/, use: [ 'style-loader', - 'css-loader' - ] - } - ] + 'css-loader', + ], + }, + ], }, output: { path: __dirname + '/dist', publicPath: '/', filename: 'bundle.js', library: 'CodeTool', - libraryTarget: 'umd' - } + libraryTarget: 'umd', + libraryExport: 'default', + }, };