autopair 1.2.5 → 1.2.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -0
- package/package.json +1 -1
- package/src/autopair.js +28 -37
package/README.md
CHANGED
|
@@ -67,6 +67,10 @@ npm install autopair
|
|
|
67
67
|
|
|
68
68
|
Report issues on the [Veritula issue tracker](https://veritula.com/discussions/autopair-js). Do not submit issues on GitHub.
|
|
69
69
|
|
|
70
|
+
## Bug bounty program
|
|
71
|
+
|
|
72
|
+
There’s a [Veritula bug bounty program](https://veritula.com/bounties/10) for autopair.js. Report bugs there, not on GitHub.
|
|
73
|
+
|
|
70
74
|
## Development
|
|
71
75
|
|
|
72
76
|
Run a webserver and open `index.html`.
|
package/package.json
CHANGED
package/src/autopair.js
CHANGED
|
@@ -5,76 +5,67 @@ export default function autopair(textarea, pairs = {
|
|
|
5
5
|
"'": "'",
|
|
6
6
|
'"': '"'
|
|
7
7
|
}) {
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
const closingFor = new Map(Object.entries(pairs));
|
|
9
|
+
const openingFor = new Map(Object.entries(pairs).map(([k, v]) => [v, k]));
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
textarea.selectionStart =
|
|
11
|
+
const insertText = text => document.execCommand('insertText', false, text);
|
|
12
|
+
const setSelection = (start, end) => {
|
|
13
|
+
textarea.selectionStart = start;
|
|
14
|
+
textarea.selectionEnd = end;
|
|
14
15
|
};
|
|
15
16
|
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
const handler = evt => {
|
|
18
|
+
const { selectionStart: start, selectionEnd: end, value } = textarea;
|
|
18
19
|
|
|
19
|
-
// Typethrough
|
|
20
|
-
if (start === end &&
|
|
20
|
+
// Typethrough: move cursor past an existing closing char
|
|
21
|
+
if (start === end && openingFor.has(evt.key) && value[end] === evt.key) {
|
|
21
22
|
evt.preventDefault();
|
|
22
|
-
|
|
23
|
+
setSelection(end + 1, end + 1);
|
|
24
|
+
|
|
23
25
|
return;
|
|
24
26
|
}
|
|
25
27
|
|
|
26
|
-
//
|
|
28
|
+
// Backspace inside a direct pair
|
|
27
29
|
if (evt.key === 'Backspace' && start === end && start > 0) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
30
|
+
const left = value[start - 1];
|
|
31
|
+
const right = value[start];
|
|
32
|
+
const opening = openingFor.get(right);
|
|
31
33
|
|
|
32
34
|
if (left === opening) {
|
|
33
35
|
evt.preventDefault();
|
|
34
|
-
|
|
35
|
-
// Select the pair and delete in one go
|
|
36
|
-
textarea.selectionStart = start - 1;
|
|
37
|
-
textarea.selectionEnd = start + 1;
|
|
38
|
-
|
|
36
|
+
setSelection(start - 1, start + 1);
|
|
39
37
|
insertText('');
|
|
40
38
|
|
|
41
39
|
return;
|
|
42
40
|
}
|
|
43
|
-
|
|
44
|
-
return; // normal backspace
|
|
45
41
|
}
|
|
46
42
|
|
|
47
|
-
|
|
43
|
+
const closing = closingFor.get(evt.key);
|
|
48
44
|
if (!closing) return;
|
|
49
45
|
|
|
50
|
-
// Wrap selection
|
|
46
|
+
// Wrap selection
|
|
51
47
|
if (start !== end) {
|
|
52
48
|
evt.preventDefault();
|
|
53
|
-
|
|
54
49
|
insertText(evt.key + value.slice(start, end) + closing);
|
|
55
|
-
|
|
56
|
-
textarea.selectionStart = start + 1;
|
|
57
|
-
textarea.selectionEnd = end + 1;
|
|
50
|
+
setSelection(start + 1, end + 1);
|
|
58
51
|
|
|
59
52
|
return;
|
|
60
53
|
}
|
|
61
54
|
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
55
|
+
// Autoclose single characters when typing next to a safe context
|
|
56
|
+
const nextChar = value[end] || '';
|
|
57
|
+
const prevChar = value[start - 1] || '';
|
|
58
|
+
const insidePair = closing === nextChar;
|
|
59
|
+
const safeNext = nextChar === '' || /[\s;})\]]/.test(nextChar);
|
|
60
|
+
const isSymmetric = evt.key === closing;
|
|
68
61
|
|
|
69
|
-
|
|
70
|
-
if (!insidePair && (!safeNext || (isSymmetric && (start !== end || prevChar === evt.key || /\w/.test(prevChar))))) {
|
|
62
|
+
if (!insidePair && (!safeNext || (isSymmetric && (prevChar === evt.key || /\w/.test(prevChar))))) {
|
|
71
63
|
return;
|
|
72
64
|
}
|
|
73
65
|
|
|
74
66
|
evt.preventDefault();
|
|
75
|
-
|
|
76
67
|
insertText(evt.key + closing);
|
|
77
|
-
|
|
68
|
+
setSelection(start + 1, start + 1);
|
|
78
69
|
};
|
|
79
70
|
|
|
80
71
|
textarea.addEventListener('keydown', handler);
|