@webcoder49/code-input 2.0.3 → 2.2.1
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/CODE_OF_CONDUCT.md +130 -0
- package/CONTRIBUTING.md +35 -0
- package/README.md +19 -10
- package/code-input.css +51 -23
- package/code-input.d.ts +70 -4
- package/code-input.js +128 -180
- package/code-input.min.css +1 -1
- package/code-input.min.js +1 -1
- package/package.json +1 -1
- package/plugins/README.md +28 -7
- package/plugins/auto-close-brackets.js +61 -0
- package/plugins/auto-close-brackets.min.js +1 -0
- package/plugins/autocomplete.js +20 -13
- package/plugins/autocomplete.min.js +1 -1
- package/plugins/autodetect.js +8 -8
- package/plugins/autodetect.min.js +1 -1
- package/plugins/find-and-replace.css +145 -0
- package/plugins/find-and-replace.js +652 -0
- package/plugins/find-and-replace.min.css +1 -0
- package/plugins/find-and-replace.min.js +1 -0
- package/plugins/go-to-line.css +77 -0
- package/plugins/go-to-line.js +157 -0
- package/plugins/go-to-line.min.css +1 -0
- package/plugins/go-to-line.min.js +1 -0
- package/plugins/indent.js +162 -78
- package/plugins/indent.min.js +1 -1
- package/plugins/special-chars.css +0 -4
- package/plugins/special-chars.js +60 -88
- package/plugins/special-chars.min.css +1 -1
- package/plugins/special-chars.min.js +1 -1
- package/plugins/test.js +1 -2
- package/plugins/test.min.js +1 -1
- package/tests/hljs.html +54 -0
- package/tests/prism.html +55 -0
- package/tests/tester.js +529 -0
- package/tests/tester.min.js +18 -0
- package/plugins/debounce-update.js +0 -41
- package/plugins/debounce-update.min.js +0 -1
package/plugins/special-chars.js
CHANGED
|
@@ -7,7 +7,7 @@ codeInput.plugins.SpecialChars = class extends codeInput.Plugin {
|
|
|
7
7
|
specialCharRegExp;
|
|
8
8
|
|
|
9
9
|
cachedColors; // ascii number > [background color, text color]
|
|
10
|
-
cachedWidths; //
|
|
10
|
+
cachedWidths; // character > character width
|
|
11
11
|
canvasContext;
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -31,37 +31,31 @@ codeInput.plugins.SpecialChars = class extends codeInput.Plugin {
|
|
|
31
31
|
this.canvasContext = canvas.getContext("2d");
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
/*
|
|
35
|
-
beforeElementsAdded(codeInput) {
|
|
36
|
-
codeInput.classList.add("code-input_special-char_container");
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
/* Runs after elements are added into a `code-input` (useful for adding events to the textarea); Params: codeInput element) */
|
|
34
|
+
/* Initially render special characters as the highlighting algorithm may automatically highlight and remove them */
|
|
40
35
|
afterElementsAdded(codeInput) {
|
|
41
|
-
|
|
42
|
-
setTimeout(() => { codeInput.update(codeInput.value); }, 100);
|
|
36
|
+
setTimeout(() => { codeInput.value = codeInput.value; }, 100);
|
|
43
37
|
}
|
|
44
38
|
|
|
45
|
-
/*
|
|
39
|
+
/* After highlighting, render special characters as their stylised hexadecimal equivalents */
|
|
46
40
|
afterHighlight(codeInput) {
|
|
47
|
-
let
|
|
41
|
+
let resultElement = codeInput.codeElement;
|
|
48
42
|
|
|
49
43
|
// Reset data each highlight so can change if font size, etc. changes
|
|
50
44
|
codeInput.pluginData.specialChars = {};
|
|
51
|
-
codeInput.pluginData.specialChars.
|
|
52
|
-
codeInput.pluginData.specialChars.contrastColor = window.getComputedStyle(result_element).color;
|
|
45
|
+
codeInput.pluginData.specialChars.contrastColor = window.getComputedStyle(resultElement).color;
|
|
53
46
|
|
|
54
|
-
this.recursivelyReplaceText(codeInput,
|
|
47
|
+
this.recursivelyReplaceText(codeInput, resultElement);
|
|
55
48
|
|
|
56
|
-
this.lastFont = window.getComputedStyle(codeInput.
|
|
49
|
+
this.lastFont = window.getComputedStyle(codeInput.textareaElement).font;
|
|
57
50
|
}
|
|
58
51
|
|
|
52
|
+
/* Search for special characters in an element and replace them with their stylised hexadecimal equivalents */
|
|
59
53
|
recursivelyReplaceText(codeInput, element) {
|
|
60
54
|
for(let i = 0; i < element.childNodes.length; i++) {
|
|
61
55
|
|
|
62
56
|
let nextNode = element.childNodes[i];
|
|
63
|
-
if(nextNode.
|
|
64
|
-
// Replace in here
|
|
57
|
+
if(nextNode.nodeType == 3) {
|
|
58
|
+
// Text node - Replace in here
|
|
65
59
|
let oldValue = nextNode.nodeValue;
|
|
66
60
|
|
|
67
61
|
this.specialCharRegExp.lastIndex = 0;
|
|
@@ -72,11 +66,11 @@ codeInput.plugins.SpecialChars = class extends codeInput.Plugin {
|
|
|
72
66
|
nextNode = nextNode.splitText(charIndex+1).previousSibling;
|
|
73
67
|
|
|
74
68
|
if(charIndex > 0) {
|
|
75
|
-
nextNode = nextNode.splitText(charIndex); // Keep
|
|
69
|
+
nextNode = nextNode.splitText(charIndex); // Keep characters before the special character in a different span
|
|
76
70
|
}
|
|
77
71
|
|
|
78
72
|
if(nextNode.textContent != "") {
|
|
79
|
-
let replacementElement = this.
|
|
73
|
+
let replacementElement = this.getStylisedSpecialChar(codeInput, nextNode.textContent);
|
|
80
74
|
nextNode.parentNode.insertBefore(replacementElement, nextNode);
|
|
81
75
|
nextNode.textContent = "";
|
|
82
76
|
}
|
|
@@ -90,29 +84,30 @@ codeInput.plugins.SpecialChars = class extends codeInput.Plugin {
|
|
|
90
84
|
}
|
|
91
85
|
}
|
|
92
86
|
|
|
93
|
-
|
|
94
|
-
|
|
87
|
+
/* Get the stylised hexadecimal representation HTML element for a given special character */
|
|
88
|
+
getStylisedSpecialChar(codeInput, matchChar) {
|
|
89
|
+
let hexCode = matchChar.codePointAt(0);
|
|
95
90
|
|
|
96
91
|
let colors;
|
|
97
|
-
if(this.colorInSpecialChars) colors = this.
|
|
92
|
+
if(this.colorInSpecialChars) colors = this.getCharacterColors(hexCode);
|
|
98
93
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
94
|
+
hexCode = hexCode.toString(16);
|
|
95
|
+
hexCode = ("0000" + hexCode).substring(hexCode.length); // So 2 chars with leading 0
|
|
96
|
+
hexCode = hexCode.toUpperCase();
|
|
102
97
|
|
|
103
|
-
let
|
|
98
|
+
let charWidth = this.getCharacterWidthEm(codeInput, matchChar);
|
|
104
99
|
|
|
105
100
|
// Create element with hex code
|
|
106
101
|
let result = document.createElement("span");
|
|
107
102
|
result.classList.add("code-input_special-char");
|
|
108
|
-
result.style.setProperty("--hex-0", "var(--code-input_special-chars_" +
|
|
109
|
-
result.style.setProperty("--hex-1", "var(--code-input_special-chars_" +
|
|
110
|
-
result.style.setProperty("--hex-2", "var(--code-input_special-chars_" +
|
|
111
|
-
result.style.setProperty("--hex-3", "var(--code-input_special-chars_" +
|
|
103
|
+
result.style.setProperty("--hex-0", "var(--code-input_special-chars_" + hexCode[0] + ")");
|
|
104
|
+
result.style.setProperty("--hex-1", "var(--code-input_special-chars_" + hexCode[1] + ")");
|
|
105
|
+
result.style.setProperty("--hex-2", "var(--code-input_special-chars_" + hexCode[2] + ")");
|
|
106
|
+
result.style.setProperty("--hex-3", "var(--code-input_special-chars_" + hexCode[3] + ")");
|
|
112
107
|
|
|
113
108
|
// Handle zero-width chars
|
|
114
|
-
if(
|
|
115
|
-
else result.style.width =
|
|
109
|
+
if(charWidth == 0) result.classList.add("code-input_special-char_zero-width");
|
|
110
|
+
else result.style.width = charWidth + "em";
|
|
116
111
|
|
|
117
112
|
if(this.colorInSpecialChars) {
|
|
118
113
|
result.style.backgroundColor = "#" + colors[0];
|
|
@@ -123,96 +118,73 @@ codeInput.plugins.SpecialChars = class extends codeInput.Plugin {
|
|
|
123
118
|
return result;
|
|
124
119
|
}
|
|
125
120
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
let
|
|
129
|
-
let
|
|
130
|
-
if(!(
|
|
121
|
+
/* Get the colors a stylised representation of a given character must be shown in; lazy load and return [background color, text color] */
|
|
122
|
+
getCharacterColors(asciiCode) {
|
|
123
|
+
let backgroundColor;
|
|
124
|
+
let textColor;
|
|
125
|
+
if(!(asciiCode in this.cachedColors)) {
|
|
131
126
|
// Get background color - arbitrary bit manipulation to get a good range of colours
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
127
|
+
backgroundColor = asciiCode^(asciiCode << 3)^(asciiCode << 7)^(asciiCode << 14)^(asciiCode << 16); // Arbitrary
|
|
128
|
+
backgroundColor = backgroundColor^0x1fc627; // Arbitrary
|
|
129
|
+
backgroundColor = backgroundColor.toString(16);
|
|
130
|
+
backgroundColor = ("000000" + backgroundColor).substring(backgroundColor.length); // So 6 chars with leading 0
|
|
136
131
|
|
|
137
132
|
// Get most suitable text color - white or black depending on background brightness
|
|
138
|
-
let
|
|
139
|
-
|
|
133
|
+
let colorBrightness = 0;
|
|
134
|
+
const luminanceCoefficients = [0.299, 0.587, 0.114];
|
|
140
135
|
for(let i = 0; i < 6; i += 2) {
|
|
141
|
-
|
|
136
|
+
colorBrightness += parseInt(backgroundColor.substring(i, i+2), 16) * luminanceCoefficients[i/2];
|
|
142
137
|
}
|
|
143
138
|
// Calculate darkness
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
// console.log(background_color, color_brightness, text_color);
|
|
139
|
+
textColor = colorBrightness < 128 ? "white" : "black";
|
|
147
140
|
|
|
148
|
-
this.cachedColors[
|
|
149
|
-
return [
|
|
141
|
+
this.cachedColors[asciiCode] = [backgroundColor, textColor];
|
|
142
|
+
return [backgroundColor, textColor];
|
|
150
143
|
} else {
|
|
151
|
-
return this.cachedColors[
|
|
144
|
+
return this.cachedColors[asciiCode];
|
|
152
145
|
}
|
|
153
146
|
}
|
|
154
147
|
|
|
155
|
-
|
|
148
|
+
/* Get the width of a character in em (relative to font size), for use in creation of the stylised hexadecimal representation with the same width */
|
|
149
|
+
getCharacterWidthEm(codeInput, char) {
|
|
156
150
|
// Force zero-width characters
|
|
157
151
|
if(new RegExp("\u00AD|\u02de|[\u0300-\u036F]|[\u0483-\u0489]|\u200b").test(char) ) { return 0 }
|
|
158
152
|
// Non-renderable ASCII characters should all be rendered at same size
|
|
159
153
|
if(char != "\u0096" && new RegExp("[\u{0000}-\u{001F}]|[\u{007F}-\u{009F}]", "g").test(char)) {
|
|
160
|
-
let fallbackWidth = this.
|
|
154
|
+
let fallbackWidth = this.getCharacterWidthEm(codeInput, "\u0096");
|
|
161
155
|
return fallbackWidth;
|
|
162
156
|
}
|
|
163
157
|
|
|
164
|
-
let font =
|
|
158
|
+
let font = getComputedStyle(codeInput.textareaElement).fontFamily + " " + getComputedStyle(codeInput.textareaElement).fontStretch + " " + getComputedStyle(codeInput.textareaElement).fontStyle + " " + getComputedStyle(codeInput.textareaElement).fontVariant + " " + getComputedStyle(codeInput.textareaElement).fontWeight + " " + getComputedStyle(codeInput.textareaElement).lineHeight; // Font without size
|
|
165
159
|
|
|
166
|
-
// Lazy-load
|
|
160
|
+
// Lazy-load width of each character
|
|
167
161
|
if(this.cachedWidths[font] == undefined) {
|
|
168
|
-
this.cachedWidths[font] = {};
|
|
162
|
+
this.cachedWidths[font] = {};
|
|
169
163
|
}
|
|
170
164
|
if(this.cachedWidths[font][char] != undefined) { // Use cached width
|
|
171
165
|
return this.cachedWidths[font][char];
|
|
172
166
|
}
|
|
173
167
|
|
|
174
|
-
// Ensure font the same
|
|
175
|
-
|
|
176
|
-
this.canvasContext.font = font;
|
|
168
|
+
// Ensure font the same - 20px font size is where this algorithm works
|
|
169
|
+
this.canvasContext.font = getComputedStyle(codeInput.textareaElement).font.replace(getComputedStyle(codeInput.textareaElement).fontSize, "20px");
|
|
177
170
|
|
|
178
171
|
// Try to get width from canvas
|
|
179
|
-
let width = this.canvasContext.measureText(char).width;
|
|
180
|
-
if(width >
|
|
172
|
+
let width = this.canvasContext.measureText(char).width/20; // From px to em (=proportion of font-size)
|
|
173
|
+
if(width > 1) {
|
|
181
174
|
width /= 2; // Fix double-width-in-canvas Firefox bug
|
|
182
175
|
} else if(width == 0 && char != "\u0096") {
|
|
183
|
-
let fallbackWidth = this.
|
|
176
|
+
let fallbackWidth = this.getCharacterWidthEm(codeInput, "\u0096");
|
|
184
177
|
return fallbackWidth; // In Firefox some control chars don't render, but all control chars are the same width
|
|
185
178
|
}
|
|
186
179
|
|
|
180
|
+
// Firefox will never make smaller than size at 20px
|
|
181
|
+
if(navigator.userAgent.includes("Mozilla") && !navigator.userAgent.includes("Chrome") && !navigator.userAgent.includes("Safari")) {
|
|
182
|
+
let fontSize = Number(getComputedStyle(codeInput.textareaElement).fontSize.substring(0, getComputedStyle(codeInput.textareaElement).fontSize.length-2)); // Remove 20, make px
|
|
183
|
+
if(fontSize < 20) width *= 20 / fontSize;
|
|
184
|
+
}
|
|
185
|
+
|
|
187
186
|
this.cachedWidths[font][char] = width;
|
|
188
187
|
|
|
189
|
-
// console.log(this.cachedWidths);
|
|
190
188
|
return width;
|
|
191
189
|
}
|
|
192
|
-
|
|
193
|
-
// getCharacterWidth(char) { // Doesn't work for now - from StackOverflow suggestion https://stackoverflow.com/a/76146120/21785620
|
|
194
|
-
// let textarea = codeInput.pluginData.specialChars.textarea;
|
|
195
|
-
|
|
196
|
-
// // Create a temporary element to measure the width of the character
|
|
197
|
-
// const span = document.createElement('span');
|
|
198
|
-
// span.textContent = char;
|
|
199
|
-
|
|
200
|
-
// // Copy the textarea's font to the temporary element
|
|
201
|
-
// span.style.fontSize = window.getComputedStyle(textarea).fontSize;
|
|
202
|
-
// span.style.fontFamily = window.getComputedStyle(textarea).fontFamily;
|
|
203
|
-
// span.style.fontWeight = window.getComputedStyle(textarea).fontWeight;
|
|
204
|
-
// span.style.visibility = 'hidden';
|
|
205
|
-
// span.style.position = 'absolute';
|
|
206
|
-
|
|
207
|
-
// // Add the temporary element to the document so we can measure its width
|
|
208
|
-
// document.body.appendChild(span);
|
|
209
|
-
|
|
210
|
-
// // Get the width of the character in pixels
|
|
211
|
-
// const width = span.offsetWidth;
|
|
212
|
-
|
|
213
|
-
// // Remove the temporary element from the document
|
|
214
|
-
// document.body.removeChild(span);
|
|
215
|
-
|
|
216
|
-
// return width;
|
|
217
|
-
// }
|
|
218
190
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
:root,body{--code-input_special-chars_0:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABtJREFUGFdjZGBgYPj///9/RhCAMcA0bg6yHgAPmh/6BoxTcQAAAABJRU5ErkJgggAA');--code-input_special-chars_1:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABZJREFUGFdjZGBgYPj///9/RhAggwMAitIUBr9U6sYAAAAASUVORK5CYII=');--code-input_special-chars_2:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB9JREFUGFdj/P///38GKGCEMUCCjCgyYBFGRrAKFBkAuLYT9kYcIu0AAAAASUVORK5CYII=');--code-input_special-chars_3:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABhJREFUGFdj/P///38GKGCEMUCCjMTJAACYiBPyG8sfAgAAAABJRU5ErkJggg==');--code-input_special-chars_4:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB5JREFUGFdj/P///39GRkZGMI3BYYACRhgDrAKZAwAYxhvyz0DRIQAAAABJRU5ErkJggg==');--code-input_special-chars_5:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAACJJREFUGFdj/P///38GKGAEcRgZGRlBfDAHLgNjgFUgywAAuR4T9hxJl2YAAAAASUVORK5CYII=');--code-input_special-chars_6:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAACBJREFUGFdj/P///38GKGAEcRgZGRlBfDAHQwasAlkGABcdF/Y4yco2AAAAAElFTkSuQmCC');--code-input_special-chars_7:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABZJREFUGFdj/P///38GKGCEMUCCRHIAWMgT8kue3bQAAAAASUVORK5CYII=');--code-input_special-chars_8:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABlJREFUGFdj/P///38GKGAEcRgZGSE0cTIAvHcb8v+mIfAAAAAASUVORK5CYII=');--code-input_special-chars_9:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB9JREFUGFdj/P///38GKGAEcRgZGSE0igxMCVgGmQMAPqcX8hWL1K0AAAAASUVORK5CYII=');--code-input_special-chars_A:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAACBJREFUGFdjZGBgYPj///9/RhCAMcA0iADJggCmDEw5ALdxH/aGuYHqAAAAAElFTkSuQmCC');--code-input_special-chars_B:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABlJREFUGFdj/P///38GBgYGRhAAceA0cTIAvc0b/vRDnVoAAAAASUVORK5CYII=');--code-input_special-chars_C:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB5JREFUGFdjZGBgYPj///9/EM0IYjAyMjIS4CDrAQC57hP+uLwvFQAAAABJRU5ErkJggg==');--code-input_special-chars_D:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABtJREFUGFdj/P///38GBgYGRhAAceA0fg5MDwAveh/6ToN9VwAAAABJRU5ErkJggg==');--code-input_special-chars_E:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABxJREFUGFdj/P///38GKGAEcRgZGRlBfDCHsAwA2UwT+mVIH1MAAAAASUVORK5CYII=');--code-input_special-chars_F:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB5JREFUGFdj/P///38GKGAEcRgZGRlBfDAHtwxMGQDZZhP+BnB1kwAAAABJRU5ErkJggg==')}.code-input_special-
|
|
1
|
+
:root,body{--code-input_special-chars_0:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABtJREFUGFdjZGBgYPj///9/RhCAMcA0bg6yHgAPmh/6BoxTcQAAAABJRU5ErkJgggAA');--code-input_special-chars_1:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABZJREFUGFdjZGBgYPj///9/RhAggwMAitIUBr9U6sYAAAAASUVORK5CYII=');--code-input_special-chars_2:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB9JREFUGFdj/P///38GKGCEMUCCjCgyYBFGRrAKFBkAuLYT9kYcIu0AAAAASUVORK5CYII=');--code-input_special-chars_3:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABhJREFUGFdj/P///38GKGCEMUCCjMTJAACYiBPyG8sfAgAAAABJRU5ErkJggg==');--code-input_special-chars_4:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB5JREFUGFdj/P///39GRkZGMI3BYYACRhgDrAKZAwAYxhvyz0DRIQAAAABJRU5ErkJggg==');--code-input_special-chars_5:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAACJJREFUGFdj/P///38GKGAEcRgZGRlBfDAHLgNjgFUgywAAuR4T9hxJl2YAAAAASUVORK5CYII=');--code-input_special-chars_6:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAACBJREFUGFdj/P///38GKGAEcRgZGRlBfDAHQwasAlkGABcdF/Y4yco2AAAAAElFTkSuQmCC');--code-input_special-chars_7:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABZJREFUGFdj/P///38GKGCEMUCCRHIAWMgT8kue3bQAAAAASUVORK5CYII=');--code-input_special-chars_8:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABlJREFUGFdj/P///38GKGAEcRgZGSE0cTIAvHcb8v+mIfAAAAAASUVORK5CYII=');--code-input_special-chars_9:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB9JREFUGFdj/P///38GKGAEcRgZGSE0igxMCVgGmQMAPqcX8hWL1K0AAAAASUVORK5CYII=');--code-input_special-chars_A:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAACBJREFUGFdjZGBgYPj///9/RhCAMcA0iADJggCmDEw5ALdxH/aGuYHqAAAAAElFTkSuQmCC');--code-input_special-chars_B:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABlJREFUGFdj/P///38GBgYGRhAAceA0cTIAvc0b/vRDnVoAAAAASUVORK5CYII=');--code-input_special-chars_C:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB5JREFUGFdjZGBgYPj///9/EM0IYjAyMjIS4CDrAQC57hP+uLwvFQAAAABJRU5ErkJggg==');--code-input_special-chars_D:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABtJREFUGFdj/P///38GBgYGRhAAceA0fg5MDwAveh/6ToN9VwAAAABJRU5ErkJggg==');--code-input_special-chars_E:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAABxJREFUGFdj/P///38GKGAEcRgZGRlBfDCHsAwA2UwT+mVIH1MAAAAASUVORK5CYII=');--code-input_special-chars_F:url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAMAAAAFCAYAAACAcVaiAAAAAXNSR0IArs4c6QAAAB5JREFUGFdj/P///38GKGAEcRgZGRlBfDAHtwxMGQDZZhP+BnB1kwAAAABJRU5ErkJggg==')}.code-input_special-char{display:inline-block;position:relative;top:0;left:0;height:1em;overflow:hidden;text-decoration:none;text-shadow:none;vertical-align:middle;outline:.1px solid currentColor;--hex-0:var(
|
|
2
2
|
--code-input_special-chars_0);--hex-1:var(
|
|
3
3
|
--code-input_special-chars_0);--hex-2:var(
|
|
4
4
|
--code-input_special-chars_0);--hex-3:var(
|
|
@@ -1 +1 @@
|
|
|
1
|
-
codeInput.plugins.SpecialChars=class extends codeInput.Plugin{specialCharRegExp;cachedColors;cachedWidths;canvasContext;constructor(a=!1,b=!1,c=/(?!\n)(?!\t)[\u{0000}-\u{001F}]|[\u{007F}-\u{009F}]|[\u{0200}-\u{FFFF}]/ug){super([]),this.specialCharRegExp=c,this.colorInSpecialChars=a,this.inheritTextColor=b,this.cachedColors={},this.cachedWidths={};let d=document.createElement("canvas");this.canvasContext=d.getContext("2d")}
|
|
1
|
+
codeInput.plugins.SpecialChars=class extends codeInput.Plugin{specialCharRegExp;cachedColors;cachedWidths;canvasContext;constructor(a=!1,b=!1,c=/(?!\n)(?!\t)[\u{0000}-\u{001F}]|[\u{007F}-\u{009F}]|[\u{0200}-\u{FFFF}]/ug){super([]),this.specialCharRegExp=c,this.colorInSpecialChars=a,this.inheritTextColor=b,this.cachedColors={},this.cachedWidths={};let d=document.createElement("canvas");this.canvasContext=d.getContext("2d")}afterElementsAdded(a){setTimeout(()=>{a.value=a.value},100)}afterHighlight(a){let b=a.codeElement;a.pluginData.specialChars={},a.pluginData.specialChars.contrastColor=window.getComputedStyle(b).color,this.recursivelyReplaceText(a,b),this.lastFont=window.getComputedStyle(a.textareaElement).font}recursivelyReplaceText(a,b){for(let c,d=0;d<b.childNodes.length;d++)if(c=b.childNodes[d],3==c.nodeType){let b=c.nodeValue;this.specialCharRegExp.lastIndex=0;let d=this.specialCharRegExp.exec(b);if(null!=d){let b=d.index;if(c=c.splitText(b+1).previousSibling,0<b&&(c=c.splitText(b)),""!=c.textContent){let b=this.getStylisedSpecialChar(a,c.textContent);c.parentNode.insertBefore(b,c),c.textContent=""}}}else 1==c.nodeType&&"code-input_special-char"!=c.className&&""!=c.nodeValue&&this.recursivelyReplaceText(a,c)}getStylisedSpecialChar(a,b){let c,d=b.codePointAt(0);this.colorInSpecialChars&&(c=this.getCharacterColors(d)),d=d.toString(16),d=("0000"+d).substring(d.length),d=d.toUpperCase();let e=this.getCharacterWidthEm(a,b),f=document.createElement("span");return f.classList.add("code-input_special-char"),f.style.setProperty("--hex-0","var(--code-input_special-chars_"+d[0]+")"),f.style.setProperty("--hex-1","var(--code-input_special-chars_"+d[1]+")"),f.style.setProperty("--hex-2","var(--code-input_special-chars_"+d[2]+")"),f.style.setProperty("--hex-3","var(--code-input_special-chars_"+d[3]+")"),0==e?f.classList.add("code-input_special-char_zero-width"):f.style.width=e+"em",this.colorInSpecialChars?(f.style.backgroundColor="#"+c[0],f.style.setProperty("--code-input_special-char_color",c[1])):!this.inheritTextColor&&f.style.setProperty("--code-input_special-char_color",a.pluginData.specialChars.contrastColor),f}getCharacterColors(a){let b,c;if(!(a in this.cachedColors)){b=a^a<<3^a<<7^a<<14^a<<16,b^=2082343,b=b.toString(16),b=("000000"+b).substring(b.length);let d=0;const e=[.299,.587,.114];for(let a=0;6>a;a+=2)d+=parseInt(b.substring(a,a+2),16)*e[a/2];return c=128>d?"white":"black",this.cachedColors[a]=[b,c],[b,c]}return this.cachedColors[a]}getCharacterWidthEm(a,b){if(/|˞|[̀-ͯ]|[҃-҉]|/.test(b))return 0;if("\x96"!=b&&/[\0-]|[-]/g.test(b)){let b=this.getCharacterWidthEm(a,"\x96");return b}let c=getComputedStyle(a.textareaElement).fontFamily+" "+getComputedStyle(a.textareaElement).fontStretch+" "+getComputedStyle(a.textareaElement).fontStyle+" "+getComputedStyle(a.textareaElement).fontVariant+" "+getComputedStyle(a.textareaElement).fontWeight+" "+getComputedStyle(a.textareaElement).lineHeight;if(null==this.cachedWidths[c]&&(this.cachedWidths[c]={}),null!=this.cachedWidths[c][b])return this.cachedWidths[c][b];this.canvasContext.font=getComputedStyle(a.textareaElement).font.replace(getComputedStyle(a.textareaElement).fontSize,"20px");let d=this.canvasContext.measureText(b).width/20;if(1<d)d/=2;else if(0==d&&"\x96"!=b){let b=this.getCharacterWidthEm(a,"\x96");return b}if(navigator.userAgent.includes("Mozilla")&&!navigator.userAgent.includes("Chrome")&&!navigator.userAgent.includes("Safari")){let b=+getComputedStyle(a.textareaElement).fontSize.substring(0,getComputedStyle(a.textareaElement).fontSize.length-2);20>b&&(d*=20/b)}return this.cachedWidths[c][b]=d,d}};
|
package/plugins/test.js
CHANGED
|
@@ -10,9 +10,8 @@
|
|
|
10
10
|
*/
|
|
11
11
|
codeInput.plugins.Test = class extends codeInput.Plugin {
|
|
12
12
|
constructor() {
|
|
13
|
-
super(["testattr"
|
|
13
|
+
super(["testattr"]);
|
|
14
14
|
// Array of observed attributes as parameter
|
|
15
|
-
// Wildcard "*" matches any text
|
|
16
15
|
}
|
|
17
16
|
/* Runs before code is highlighted; Params: codeInput element) */
|
|
18
17
|
beforeHighlight(codeInput) {
|
package/plugins/test.min.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
codeInput.plugins.Test=class extends codeInput.Plugin{constructor(){super(["testattr"
|
|
1
|
+
codeInput.plugins.Test=class extends codeInput.Plugin{constructor(){super(["testattr"])}beforeHighlight(a){console.log(a,"before highlight")}afterHighlight(a){console.log(a,"after highlight")}beforeElementsAdded(a){console.log(a,"before elements added")}afterElementsAdded(a){console.log(a,"after elements added")}attributeChanged(a,b,c,d){console.log(a,b,":",c,">",d)}};
|
package/tests/hljs.html
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>code-input Tester</title>
|
|
7
|
+
|
|
8
|
+
<!--Import Highlight.JS-->
|
|
9
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/styles/default.min.css">
|
|
10
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/highlight.min.js"></script>
|
|
11
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/xml.min.js"></script>
|
|
12
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/css.min.js"></script>
|
|
13
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/javascript.min.js"></script>
|
|
14
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.9.0/languages/python.min.js"></script>
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
<!--Import code-input-->
|
|
18
|
+
<link rel="stylesheet" href="../code-input.css">
|
|
19
|
+
<script src="../code-input.js"></script>
|
|
20
|
+
|
|
21
|
+
<!--Import code-input plugins-->
|
|
22
|
+
<script src="../plugins/auto-close-brackets.js"></script>
|
|
23
|
+
<script src="../plugins/autocomplete.js"></script>
|
|
24
|
+
<link rel="stylesheet" href="../plugins/autocomplete.css">
|
|
25
|
+
<script src="../plugins/autodetect.js"></script>
|
|
26
|
+
<script src="../plugins/find-and-replace.js"></script>
|
|
27
|
+
<link rel="stylesheet" href="../plugins/find-and-replace.css">
|
|
28
|
+
<script src="../plugins/go-to-line.js"></script>
|
|
29
|
+
<link rel="stylesheet" href="../plugins/go-to-line.css">
|
|
30
|
+
<script src="../plugins/indent.js"></script>
|
|
31
|
+
<script src="../plugins/special-chars.js"></script>
|
|
32
|
+
<link rel="stylesheet" href="../plugins/special-chars.css">
|
|
33
|
+
|
|
34
|
+
<script src="tester.js"></script>
|
|
35
|
+
</head>
|
|
36
|
+
<body>
|
|
37
|
+
<h1>code-input Tester (highlight.js)</h1>
|
|
38
|
+
<h2>If the page doesn't load, please reload it, and answer the questions in alert boxes.</h2>
|
|
39
|
+
<h4><a href="prism.html">Test for Prism.js</a></h4>
|
|
40
|
+
<p>This page carries out automated tests for the code-input library to check that both the core components and the plugins work in some ways. It doesn't fully cover every scenario so you should test any code you change by hand, but it's good for quickly checking a wide range of functionality works.</p>
|
|
41
|
+
|
|
42
|
+
<details id="collapse-results"><summary>Test Results (Click to Open)</summary><pre id="test-results"></pre></details>
|
|
43
|
+
<form method="GET" action="https://google.com/search" target="_blank">
|
|
44
|
+
<code-input language="JavaScript" name="q">console.log("Hello, World!");
|
|
45
|
+
// A second line
|
|
46
|
+
// A third line with <html> tags</code-input>
|
|
47
|
+
<input type="submit" value="Search Google For Code"/>
|
|
48
|
+
</form>
|
|
49
|
+
|
|
50
|
+
<script>
|
|
51
|
+
beginTest(true);
|
|
52
|
+
</script>
|
|
53
|
+
</body>
|
|
54
|
+
</html>
|
package/tests/prism.html
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
<!DOCTYPE html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
|
+
<title>code-input Tester</title>
|
|
7
|
+
|
|
8
|
+
<!--Import Prism-->
|
|
9
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism.min.css">
|
|
10
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
|
|
11
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
|
|
12
|
+
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.js"></script>
|
|
13
|
+
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/line-numbers/prism-line-numbers.min.css">
|
|
14
|
+
|
|
15
|
+
<!--Import code-input-->
|
|
16
|
+
<link rel="stylesheet" href="../code-input.css">
|
|
17
|
+
<script src="../code-input.js"></script>
|
|
18
|
+
|
|
19
|
+
<!--Import code-input plugins-->
|
|
20
|
+
<script src="../plugins/auto-close-brackets.js"></script>
|
|
21
|
+
<script src="../plugins/autocomplete.js"></script>
|
|
22
|
+
<link rel="stylesheet" href="../plugins/autocomplete.css">
|
|
23
|
+
<script src="../plugins/find-and-replace.js"></script>
|
|
24
|
+
<link rel="stylesheet" href="../plugins/find-and-replace.css">
|
|
25
|
+
<script src="../plugins/go-to-line.js"></script>
|
|
26
|
+
<link rel="stylesheet" href="../plugins/go-to-line.css">
|
|
27
|
+
<script src="../plugins/indent.js"></script>
|
|
28
|
+
<link rel="stylesheet" href="../plugins/prism-line-numbers.css">
|
|
29
|
+
<script src="../plugins/special-chars.js"></script>
|
|
30
|
+
<link rel="stylesheet" href="../plugins/special-chars.css">
|
|
31
|
+
|
|
32
|
+
<script src="tester.js"></script>
|
|
33
|
+
</head>
|
|
34
|
+
<body>
|
|
35
|
+
<h1>code-input Tester (Prism.js)</h1>
|
|
36
|
+
<h2>If the page doesn't load, please reload it, and answer the questions in alert boxes.</h2>
|
|
37
|
+
<h4><a href="hljs.html">Test for highlight.js</a></h4>
|
|
38
|
+
<p>This page carries out automated tests for the code-input library to check that both the core components and the plugins work in some ways. It doesn't fully cover every scenario so you should test any code you change by hand, but it's good for quickly checking a wide range of functionality works.</p>
|
|
39
|
+
|
|
40
|
+
<!-- <pre class="line-numbers language-javascript"><code>// Hello
|
|
41
|
+
// World
|
|
42
|
+
// Yay!</code></pre> -->
|
|
43
|
+
|
|
44
|
+
<details id="collapse-results"><summary>Test Results (Click to Open)</summary><pre id="test-results"></pre></details>
|
|
45
|
+
<form method="GET" class="line-numbers" action="https://google.com/search" target="_blank">
|
|
46
|
+
<code-input language="JavaScript" name="q">console.log("Hello, World!");
|
|
47
|
+
// A second line
|
|
48
|
+
// A third line with <html> tags</code-input>
|
|
49
|
+
<input type="submit" value="Search Google For Code"/>
|
|
50
|
+
</form>
|
|
51
|
+
<script>
|
|
52
|
+
beginTest(false);
|
|
53
|
+
</script>
|
|
54
|
+
</body>
|
|
55
|
+
</html>
|