Skip to content

Commit 01de0ea

Browse files
authored
Merge pull request #40 from editor-js/feature/tab-indents
feature: indentations by tab
2 parents d68d501 + 40f8b23 commit 01de0ea

File tree

4 files changed

+115
-12
lines changed

4 files changed

+115
-12
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@editorjs/code",
3-
"version": "2.6.0",
3+
"version": "2.7.0",
44
"keywords": [
55
"codex editor",
66
"code",

src/index.js

Lines changed: 71 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
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+
}

src/utils/string.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/**
2+
* Return the position of line starting from passed point
3+
*
4+
* ┌───────────────┐
5+
* │1234\n │
6+
* │2eda | dadd\n │ <-- returns 5
7+
* └───────────────┘
8+
*
9+
* @param {string} string - string to process
10+
* @param {number} position - search starting position
11+
* @returns {number}
12+
*/
13+
export function getLineStartPosition(string, position) {
14+
const charLength = 1;
15+
let char = '';
16+
17+
/**
18+
* Iterate through all the chars before the position till the
19+
* - end of line (\n)
20+
* - or start of string (position === 0)
21+
*/
22+
while (char !== '\n' && position > 0) {
23+
position = position - charLength;
24+
char = string.substr(position, charLength);
25+
}
26+
27+
/**
28+
* Do not count the linebreak symbol because it is related to the previous line
29+
*/
30+
if (char === '\n') {
31+
position += 1;
32+
}
33+
34+
return position;
35+
}

webpack.config.js

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,22 +12,23 @@ module.exports = {
1212
presets: [ '@babel/preset-env' ],
1313
},
1414
},
15-
]
15+
],
1616
},
1717
{
1818
test: /\.css$/,
1919
use: [
2020
'style-loader',
21-
'css-loader'
22-
]
23-
}
24-
]
21+
'css-loader',
22+
],
23+
},
24+
],
2525
},
2626
output: {
2727
path: __dirname + '/dist',
2828
publicPath: '/',
2929
filename: 'bundle.js',
3030
library: 'CodeTool',
31-
libraryTarget: 'umd'
32-
}
31+
libraryTarget: 'umd',
32+
libraryExport: 'default',
33+
},
3334
};

0 commit comments

Comments
 (0)