@webcoder49/code-input 2.1.0 → 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/CONTRIBUTING.md +11 -1
- package/README.md +17 -8
- package/code-input.css +47 -22
- package/code-input.d.ts +65 -4
- package/code-input.js +127 -176
- package/code-input.min.css +1 -1
- package/code-input.min.js +1 -1
- package/package.json +1 -1
- package/plugins/README.md +21 -6
- package/plugins/auto-close-brackets.js +61 -0
- package/plugins/auto-close-brackets.min.js +1 -0
- package/plugins/autocomplete.js +18 -11
- package/plugins/autocomplete.min.js +1 -1
- package/plugins/autodetect.js +4 -4
- 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 +71 -11
- package/plugins/indent.min.js +1 -1
- package/plugins/special-chars.css +0 -4
- package/plugins/special-chars.js +60 -58
- 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 -40
- 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,64 +118,71 @@ 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
|
-
|
|
139
|
+
textColor = colorBrightness < 128 ? "white" : "black";
|
|
145
140
|
|
|
146
|
-
this.cachedColors[
|
|
147
|
-
return [
|
|
141
|
+
this.cachedColors[asciiCode] = [backgroundColor, textColor];
|
|
142
|
+
return [backgroundColor, textColor];
|
|
148
143
|
} else {
|
|
149
|
-
return this.cachedColors[
|
|
144
|
+
return this.cachedColors[asciiCode];
|
|
150
145
|
}
|
|
151
146
|
}
|
|
152
147
|
|
|
153
|
-
|
|
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) {
|
|
154
150
|
// Force zero-width characters
|
|
155
151
|
if(new RegExp("\u00AD|\u02de|[\u0300-\u036F]|[\u0483-\u0489]|\u200b").test(char) ) { return 0 }
|
|
156
152
|
// Non-renderable ASCII characters should all be rendered at same size
|
|
157
153
|
if(char != "\u0096" && new RegExp("[\u{0000}-\u{001F}]|[\u{007F}-\u{009F}]", "g").test(char)) {
|
|
158
|
-
let fallbackWidth = this.
|
|
154
|
+
let fallbackWidth = this.getCharacterWidthEm(codeInput, "\u0096");
|
|
159
155
|
return fallbackWidth;
|
|
160
156
|
}
|
|
161
157
|
|
|
162
|
-
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
|
|
163
159
|
|
|
164
|
-
// Lazy-load
|
|
160
|
+
// Lazy-load width of each character
|
|
165
161
|
if(this.cachedWidths[font] == undefined) {
|
|
166
|
-
this.cachedWidths[font] = {};
|
|
162
|
+
this.cachedWidths[font] = {};
|
|
167
163
|
}
|
|
168
164
|
if(this.cachedWidths[font][char] != undefined) { // Use cached width
|
|
169
165
|
return this.cachedWidths[font][char];
|
|
170
166
|
}
|
|
171
167
|
|
|
172
|
-
// Ensure font the same
|
|
173
|
-
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");
|
|
174
170
|
|
|
175
171
|
// Try to get width from canvas
|
|
176
|
-
let width = this.canvasContext.measureText(char).width;
|
|
177
|
-
if(width >
|
|
172
|
+
let width = this.canvasContext.measureText(char).width/20; // From px to em (=proportion of font-size)
|
|
173
|
+
if(width > 1) {
|
|
178
174
|
width /= 2; // Fix double-width-in-canvas Firefox bug
|
|
179
175
|
} else if(width == 0 && char != "\u0096") {
|
|
180
|
-
let fallbackWidth = this.
|
|
176
|
+
let fallbackWidth = this.getCharacterWidthEm(codeInput, "\u0096");
|
|
181
177
|
return fallbackWidth; // In Firefox some control chars don't render, but all control chars are the same width
|
|
182
178
|
}
|
|
183
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
|
+
|
|
184
186
|
this.cachedWidths[font][char] = width;
|
|
185
187
|
|
|
186
188
|
return width;
|
|
@@ -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>
|