11/**
22 * Build styles
33 */
4- require ( './index.css' ) . toString ( ) ;
4+ import { getLineStartPosition } from './utils/string' ;
5+ import './index.css' ;
56
67/**
78 * CodeTool for Editor.js
@@ -17,7 +18,7 @@ require('./index.css').toString();
1718/**
1819 * Code Tool for the Editor.js allows to include code examples in your articles.
1920 */
20- class CodeTool {
21+ export default class CodeTool {
2122
2223 /**
2324 * Notify core that read-only mode is supported
@@ -99,6 +100,17 @@ class CodeTool {
99100
100101 wrapper . appendChild ( textarea ) ;
101102
103+ /**
104+ * Enable keydown handlers
105+ */
106+ textarea . addEventListener ( 'keydown' , ( event ) => {
107+ switch ( event . code ) {
108+ case 'Tab' :
109+ this . tabHandler ( event ) ;
110+ break ;
111+ }
112+ } ) ;
113+
102114 this . nodes . textarea = textarea ;
103115
104116 return wrapper ;
@@ -209,6 +221,61 @@ class CodeTool {
209221 code : true , // Allow HTML tags
210222 } ;
211223 }
212- }
213224
214- module . exports = CodeTool ;
225+ /**
226+ * Handles Tab key pressing (adds/removes indentations)
227+ *
228+ * @private
229+ * @param {KeyboardEvent } event - keydown
230+ * @returns {void }
231+ */
232+ tabHandler ( event ) {
233+ /**
234+ * Prevent editor.js tab handler
235+ */
236+ event . stopPropagation ( ) ;
237+
238+ /**
239+ * Prevent native tab behaviour
240+ */
241+ event . preventDefault ( ) ;
242+
243+ const textarea = event . target ;
244+ const isShiftPressed = event . shiftKey ;
245+ const caretPosition = textarea . selectionStart ;
246+ const value = textarea . value ;
247+ const indentation = ' ' ;
248+
249+ let newCaretPosition ;
250+
251+ /**
252+ * For Tab pressing, just add an indentation to the caret position
253+ */
254+ if ( ! isShiftPressed ) {
255+ newCaretPosition = caretPosition + indentation . length ;
256+
257+ textarea . value = value . substring ( 0 , caretPosition ) + indentation + value . substring ( caretPosition ) ;
258+ } else {
259+ /**
260+ * For Shift+Tab pressing, remove an indentation from the start of line
261+ */
262+ const currentLineStart = getLineStartPosition ( value , caretPosition ) ;
263+ const firstLineChars = value . substr ( currentLineStart , indentation . length ) ;
264+
265+ if ( firstLineChars !== indentation ) {
266+ return ;
267+ }
268+
269+ /**
270+ * Trim the first two chars from the start of line
271+ */
272+ textarea . value = value . substring ( 0 , currentLineStart ) + value . substring ( currentLineStart + indentation . length ) ;
273+ newCaretPosition = caretPosition - indentation . length ;
274+ }
275+
276+ /**
277+ * Restore the caret
278+ */
279+ textarea . setSelectionRange ( newCaretPosition , newCaretPosition ) ;
280+ }
281+ }
0 commit comments