Skip to content

Commit ba555df

Browse files
committed
Allow space-character indentation; clean up; upgrade to v2.1.0
1 parent f0028e7 commit ba555df

File tree

5 files changed

+69
-24
lines changed

5 files changed

+69
-24
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ The next step is to set up a `template` to link `code-input` to your syntax-high
9999
hljs,
100100
[
101101
new codeInput.plugins.Autodetect(),
102-
new codeInput.plugins.Indent()
102+
new codeInput.plugins.Indent(true, 2) // 2 spaces indentation
103103
]
104104
)
105105
);
@@ -119,7 +119,7 @@ Now that you have registered a template, you can use the custom `<code-input>` e
119119
```
120120

121121
## Contributing
122-
If you have any features you would like to add to `code-input`, or have found any bugs, please [open an issue](https://github.com/WebCoder49/code-input/issues) or [fork and submit a pull request](https://github.com/WebCoder49/code-input/fork)! All contributions to this open-source project would be greatly appreciated.
122+
If you have any features you would like to add to `code-input` as plugins or core functionality, or have found any bugs, please [open an issue](https://github.com/WebCoder49/code-input/issues) or [fork and submit a pull request](https://github.com/WebCoder49/code-input/fork)! All contributions to this open-source project will be greatly appreciated. You can see [more info in our `CONTRIBUTING.md` file](CONTRIBUTING.md).
123123

124124

125125
|[![Contributors](https://contrib.rocks/image?repo=WebCoder49%2Fcode-input)](https://github.com/WebCoder49/code-input/graphs/contributors)|

code-input.d.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -116,7 +116,12 @@ export namespace plugins {
116116
* Files: indent.js
117117
*/
118118
class Indent extends Plugin {
119-
constructor();
119+
/**
120+
* Create an indentation plugin to pass into a template
121+
* @param {Boolean} defaultSpaces Should the Tab key enter spaces rather than tabs? Defaults to false.
122+
* @param {Number} numSpaces How many spaces is each tab character worth? Defaults to 4.
123+
*/
124+
constructor(defaultSpaces?: boolean, numSpaces?: Number);
120125
}
121126

122127
/**

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@webcoder49/code-input",
3-
"version": "2.0.3",
3+
"version": "2.1.0",
44
"description": "Fully customisable, editable syntax-highlighted textareas.",
55
"browser": "code-input.js",
66
"scripts": {

plugins/README.md

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,12 @@
11
# Code-input: Plugins
22
## List Of Plugins
33

4+
💡 Do you just want to get a quick editor working? We suggest the [Indent](#indent) and [Prism Line Numbers](#prism-line-numbers) plugins.
5+
6+
**Lots of plugins are very customisable - please see the JavaScript files for parameters and if you want more features let us know via GitHub Issues.**
7+
8+
---
9+
410
### Autocomplete
511
Display a popup under the caret using the text in the code-input element. This works well with autocomplete suggestions.
612

@@ -23,7 +29,7 @@ Files: [debounce-update.js](./debounce-update.js)
2329
[🚀 *CodePen Demo*](https://codepen.io/WebCoder49/pen/GRXyxzV)
2430

2531
### Indent
26-
Adds indentation using the `Tab` key, and auto-indents after a newline, as well as making it possible to indent/unindent multiple lines using Tab/Shift+Tab
32+
Adds indentation using the `Tab` key, and auto-indents after a newline, as well as making it possible to indent/unindent multiple lines using Tab/Shift+Tab. **Supports tab characters and custom numbers of spaces as indentation.**
2733

2834
Files: [indent.js](./indent.js)
2935

@@ -60,7 +66,7 @@ Plugins allow you to add extra features to a template, like [automatic indentati
6066
hljs,
6167
[
6268
new codeInput.plugins.Autodetect(),
63-
new codeInput.plugins.Indent()
69+
new codeInput.plugins.Indent(true, 2) // 2 spaces indentation
6470
]
6571
)
6672
);

plugins/indent.js

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,33 @@
44
* Files: indent.js
55
*/
66
codeInput.plugins.Indent = class extends codeInput.Plugin {
7-
constructor() {
7+
8+
numSpaces;
9+
indentation = "\t";
10+
indentationNumChars = 1;
11+
12+
/**
13+
* Create an indentation plugin to pass into a template
14+
* @param {Boolean} defaultSpaces Should the Tab key enter spaces rather than tabs? Defaults to false.
15+
* @param {Number} numSpaces How many spaces is each tab character worth? Defaults to 4.
16+
*/
17+
constructor(defaultSpaces=false, numSpaces=4) {
818
super([]); // No observed attributes
19+
20+
this.numSpaces = numSpaces;
21+
if(defaultSpaces) {
22+
this.indentation = "";
23+
for(let i = 0; i < numSpaces; i++) {
24+
this.indentation += " ";
25+
}
26+
this.indentationNumChars = numSpaces;
27+
}
928
}
1029

1130
/* Add keystroke events */
1231
afterElementsAdded(codeInput) {
1332
let textarea = codeInput.textareaElement;
14-
textarea.addEventListener('keydown', (event) => { this.checkTab(codeInput, event); this.checkEnter(codeInput, event); });
33+
textarea.addEventListener('keydown', (event) => { this.checkTab(codeInput, event); this.checkEnter(codeInput, event); this.checkBackspace(codeInput, event); });
1534
}
1635

1736
/* Event handlers */
@@ -23,8 +42,8 @@ codeInput.plugins.Indent = class extends codeInput.Plugin {
2342
event.preventDefault(); // stop normal
2443

2544
if(!event.shiftKey && inputElement.selectionStart == inputElement.selectionEnd) {
26-
// Just place a tab here.
27-
document.execCommand("insertText", false, "\t");
45+
// Just place a tab/spaces here.
46+
document.execCommand("insertText", false, this.indentation);
2847

2948
} else {
3049
let lines = inputElement.value.split("\n");
@@ -38,31 +57,31 @@ codeInput.plugins.Indent = class extends codeInput.Plugin {
3857
|| (selectionStartI == selectionEndI && selectionStartI <= letterI+lines[i].length+1 && selectionEndI >= letterI)) { // + 1 so newlines counted
3958
// Starts before or at last char and ends after or at first char
4059
if(event.shiftKey) {
41-
if(lines[i][0] == "\t") {
42-
// Remove first tab
60+
if(lines[i].substring(0, this.indentationNumChars) == this.indentation) {
61+
// Remove first indent
4362
inputElement.selectionStart = letterI;
44-
inputElement.selectionEnd = letterI+1;
63+
inputElement.selectionEnd = letterI+this.indentationNumChars;
4564
document.execCommand("delete", false, "");
4665

4766
// Change selection
4867
if(selectionStartI > letterI) { // Indented outside selection
49-
selectionStartI--;
68+
selectionStartI = Math.max(selectionStartI - this.indentationNumChars, letterI); // Don't move to before indent
5069
}
51-
selectionEndI--;
52-
letterI--;
70+
selectionEndI -= this.indentationNumChars;
71+
letterI -= this.indentationNumChars;
5372
}
5473
} else {
5574
// Add tab at start
5675
inputElement.selectionStart = letterI;
5776
inputElement.selectionEnd = letterI;
58-
document.execCommand("insertText", false, "\t");
77+
document.execCommand("insertText", false, this.indentation);
5978

6079
// Change selection
6180
if(selectionStartI > letterI) { // Indented outside selection
62-
selectionStartI++;
81+
selectionStartI += this.indentationNumChars;
6382
}
64-
selectionEndI++;
65-
letterI++;
83+
selectionEndI += this.indentationNumChars;
84+
letterI += this.indentationNumChars;
6685
}
6786
}
6887

@@ -101,8 +120,8 @@ codeInput.plugins.Indent = class extends codeInput.Plugin {
101120

102121
// count the number of indents the current line starts with (up to our cursor position in the line)
103122
let cursorPosInLine = lines[currentLineI].length - (letterI - inputElement.selectionEnd) + 1;
104-
for (let i = 0; i < cursorPosInLine; i++) {
105-
if (lines[currentLineI][i] == "\t") {
123+
for (let i = 0; i < cursorPosInLine; i += this.indentationNumChars) {
124+
if (lines[currentLineI].substring(i, i+this.indentationNumChars) == this.indentation) {
106125
numberIndents++;
107126
} else {
108127
break;
@@ -118,7 +137,7 @@ codeInput.plugins.Indent = class extends codeInput.Plugin {
118137

119138
// insert our indents and any text from the previous line that might have been after the line break
120139
for (let i = 0; i < numberIndents; i++) {
121-
newLine += "\t";
140+
newLine += this.indentation;
122141
}
123142

124143
// save the current cursor position
@@ -127,7 +146,7 @@ codeInput.plugins.Indent = class extends codeInput.Plugin {
127146
document.execCommand("insertText", false, "\n" + newLine); // Write new line, including auto-indentation
128147

129148
// move cursor to new position
130-
inputElement.selectionStart = selectionStartI + numberIndents + 1; // count the indent level and the newline character
149+
inputElement.selectionStart = selectionStartI + numberIndents*this.indentationNumChars + 1; // count the indent level and the newline character
131150
inputElement.selectionEnd = inputElement.selectionStart;
132151

133152

@@ -141,4 +160,19 @@ codeInput.plugins.Indent = class extends codeInput.Plugin {
141160

142161
codeInput.update(inputElement.value);
143162
}
163+
164+
checkBackspace(codeInput, event) {
165+
if(event.key != "Backspace" || this.indentationNumChars == 1) {
166+
return; // Normal backspace
167+
}
168+
169+
let inputElement = codeInput.textareaElement;
170+
171+
if(inputElement.selectionStart == inputElement.selectionEnd && codeInput.value.substring(inputElement.selectionStart - this.indentationNumChars, inputElement.selectionStart) == this.indentation) {
172+
// Indentation before cursor = delete it
173+
inputElement.selectionStart -= this.indentationNumChars;
174+
event.preventDefault();
175+
document.execCommand("delete", false, "");
176+
}
177+
}
144178
}

0 commit comments

Comments
 (0)