@gravitee/ui-components 3.24.3-migrate-codemirror-bed237b → 3.24.4-migrate-codemirror-6bf640d
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/CHANGELOG.md +7 -0
- package/assets/i18n/en.json +0 -3
- package/assets/i18n/fr.json +0 -3
- package/package.json +2 -6
- package/src/atoms/gv-button.js +0 -8
- package/src/atoms/gv-input.js +31 -25
- package/src/lib/asciidoc-lang.js +642 -0
- package/src/mixins/input-element.js +7 -3
- package/src/molecules/gv-code.js +117 -100
- package/src/molecules/gv-expression-language.js +10 -13
- package/src/styles/input.js +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
## [3.24.4](https://github.com/gravitee-io/gravitee-ui-components/compare/v3.24.3...v3.24.4) (2021-12-16)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* remove unnecessary perform update ([1b8fee6](https://github.com/gravitee-io/gravitee-ui-components/commit/1b8fee6711bf1af63bf40ca9aca2fac570590076))
|
|
7
|
+
|
|
1
8
|
## [3.24.3](https://github.com/gravitee-io/gravitee-ui-components/compare/v3.24.2...v3.24.3) (2021-12-15)
|
|
2
9
|
|
|
3
10
|
|
package/assets/i18n/en.json
CHANGED
package/assets/i18n/fr.json
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gravitee/ui-components",
|
|
3
|
-
"version": "3.24.
|
|
3
|
+
"version": "3.24.4-migrate-codemirror-6bf640d",
|
|
4
4
|
"description": "Gravitee.io UI Components library, based on Web Components",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -64,6 +64,7 @@
|
|
|
64
64
|
"@codemirror/language-data": "^0.19.1",
|
|
65
65
|
"@codemirror/matchbrackets": "^0.19.3",
|
|
66
66
|
"@codemirror/state": "^0.19.6",
|
|
67
|
+
"@codemirror/stream-parser": "^0.19.3",
|
|
67
68
|
"@codemirror/view": "^0.19.32",
|
|
68
69
|
"@formatjs/intl-locale": "^2.4.40",
|
|
69
70
|
"@formatjs/intl-relativetimeformat": "^9.3.2",
|
|
@@ -99,7 +100,6 @@
|
|
|
99
100
|
"babel-plugin-template-html-minifier": "4.1.0",
|
|
100
101
|
"bundle-phobia-cli": "0.14.13",
|
|
101
102
|
"chromatic": "6.1.0",
|
|
102
|
-
"codemirror-asciidoc": "1.0.4",
|
|
103
103
|
"danger": "10.7.1",
|
|
104
104
|
"del": "6.0.0",
|
|
105
105
|
"eslint": "8.4.0",
|
|
@@ -146,7 +146,6 @@
|
|
|
146
146
|
"@highcharts/map-collection": "^1.0.0",
|
|
147
147
|
"asciidoctor": "^2.2.4",
|
|
148
148
|
"asciidoctor-highlight.js": "^0.3.0 || ^0.4.0",
|
|
149
|
-
"codemirror-asciidoc": "^1.0.4",
|
|
150
149
|
"highcharts": "^8.0.0 || ^9.0.0",
|
|
151
150
|
"highlight.js": "^10.7.0 || ^11.1.0"
|
|
152
151
|
},
|
|
@@ -163,9 +162,6 @@
|
|
|
163
162
|
"asciidoctor-highlight.js": {
|
|
164
163
|
"optional": true
|
|
165
164
|
},
|
|
166
|
-
"codemirror-asciidoc": {
|
|
167
|
-
"optional": true
|
|
168
|
-
},
|
|
169
165
|
"highcharts": {
|
|
170
166
|
"optional": true
|
|
171
167
|
},
|
package/src/atoms/gv-button.js
CHANGED
|
@@ -322,14 +322,6 @@ export class GvButton extends LitElement {
|
|
|
322
322
|
}
|
|
323
323
|
}
|
|
324
324
|
|
|
325
|
-
async performUpdate() {
|
|
326
|
-
super.performUpdate();
|
|
327
|
-
const icon = this.shadowRoot.querySelector('gv-icon');
|
|
328
|
-
if (icon) {
|
|
329
|
-
icon.performUpdate();
|
|
330
|
-
}
|
|
331
|
-
}
|
|
332
|
-
|
|
333
325
|
render() {
|
|
334
326
|
const classes = {
|
|
335
327
|
button: true,
|
package/src/atoms/gv-input.js
CHANGED
|
@@ -111,8 +111,12 @@ export class GvInput extends InputElement(LitElement) {
|
|
|
111
111
|
--gv-icon--s: 22px;
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
.
|
|
115
|
-
--gv-
|
|
114
|
+
.copied {
|
|
115
|
+
--gv-input--bdc: var(--gv-theme-color-success-light, #81c784);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
.copied .box-icon gv-icon {
|
|
119
|
+
--gv-icon--c: var(--gv-theme-color-success-dark, #388e3c);
|
|
116
120
|
}
|
|
117
121
|
|
|
118
122
|
div.box-icon gv-icon.loading,
|
|
@@ -272,19 +276,7 @@ export class GvInput extends InputElement(LitElement) {
|
|
|
272
276
|
firstUpdated(changedProperties) {
|
|
273
277
|
super.firstUpdated(changedProperties);
|
|
274
278
|
|
|
275
|
-
|
|
276
|
-
for (const node of this.childNodes) {
|
|
277
|
-
if (node.nodeType === 1) {
|
|
278
|
-
const child = node.nodeName.toLowerCase() === 'input' ? node : node.querySelector('input');
|
|
279
|
-
if (child) {
|
|
280
|
-
this._input = child;
|
|
281
|
-
break;
|
|
282
|
-
}
|
|
283
|
-
}
|
|
284
|
-
}
|
|
285
|
-
if (this._input) {
|
|
286
|
-
defaultInputElement.remove();
|
|
287
|
-
}
|
|
279
|
+
this.catchSlot();
|
|
288
280
|
|
|
289
281
|
if (this.clipboard) {
|
|
290
282
|
import('clipboard-copy').then(
|
|
@@ -304,13 +296,6 @@ export class GvInput extends InputElement(LitElement) {
|
|
|
304
296
|
|
|
305
297
|
setTimeout(() => {
|
|
306
298
|
const clipboardPopover = this.shadowRoot.querySelector('.clipboard__popover');
|
|
307
|
-
if (this.readonly) {
|
|
308
|
-
this.getInputElement().addEventListener('click', (e) => {
|
|
309
|
-
e.preventDefault();
|
|
310
|
-
e.stopPropagation();
|
|
311
|
-
clipboardPopover.click();
|
|
312
|
-
});
|
|
313
|
-
}
|
|
314
299
|
clipboardPopover.addEventListener('click', (e) => {
|
|
315
300
|
e.preventDefault();
|
|
316
301
|
e.stopPropagation();
|
|
@@ -325,11 +310,32 @@ export class GvInput extends InputElement(LitElement) {
|
|
|
325
310
|
}
|
|
326
311
|
|
|
327
312
|
this.getInputElement().id = this._id;
|
|
313
|
+
|
|
314
|
+
this.bindInputEvents();
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
bindInputEvents() {
|
|
328
318
|
this.getInputElement().addEventListener('input', this._onInput.bind(this));
|
|
329
319
|
this.getInputElement().addEventListener('keyup', this._onKeyUp.bind(this));
|
|
330
320
|
this.getInputElement().addEventListener('keypress', this._onKeyPress.bind(this));
|
|
331
321
|
}
|
|
332
322
|
|
|
323
|
+
catchSlot() {
|
|
324
|
+
const defaultInputElement = this.getInputElement();
|
|
325
|
+
for (const node of this.childNodes) {
|
|
326
|
+
if (node.nodeType === 1) {
|
|
327
|
+
const child = node.nodeName.toLowerCase() === 'input' ? node : node.querySelector('input');
|
|
328
|
+
if (child) {
|
|
329
|
+
this._input = child;
|
|
330
|
+
break;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
if (this._input) {
|
|
335
|
+
defaultInputElement.remove();
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
|
|
333
339
|
updateState(value) {
|
|
334
340
|
super.updateState(value);
|
|
335
341
|
if (this.valid === true && !this.readonly) {
|
|
@@ -481,7 +487,7 @@ export class GvInput extends InputElement(LitElement) {
|
|
|
481
487
|
return !this.loading;
|
|
482
488
|
}
|
|
483
489
|
|
|
484
|
-
|
|
490
|
+
renderIcon() {
|
|
485
491
|
let shape = null;
|
|
486
492
|
if ((!this.isPassword && this.icon) || this.iconLeft) {
|
|
487
493
|
shape = (!this.isPassword && this.icon) || this.iconLeft;
|
|
@@ -495,7 +501,6 @@ export class GvInput extends InputElement(LitElement) {
|
|
|
495
501
|
'box-icon': true,
|
|
496
502
|
'box-icon-left': this.iconLeft != null || this.clearable,
|
|
497
503
|
'box-icon-bgc': this.hasBackground,
|
|
498
|
-
copied: this.hasClipboard && this._copied,
|
|
499
504
|
};
|
|
500
505
|
|
|
501
506
|
const iconClasses = {
|
|
@@ -538,6 +543,7 @@ export class GvInput extends InputElement(LitElement) {
|
|
|
538
543
|
'icon-left': !!this.iconLeft || (!!this.icon && this.clearable),
|
|
539
544
|
clipboard: this.hasClipboard,
|
|
540
545
|
required: this.required,
|
|
546
|
+
copied: this.hasClipboard && this._copied,
|
|
541
547
|
};
|
|
542
548
|
|
|
543
549
|
return html`
|
|
@@ -545,7 +551,7 @@ export class GvInput extends InputElement(LitElement) {
|
|
|
545
551
|
${this.renderLabel()}
|
|
546
552
|
<input />
|
|
547
553
|
<slot></slot>
|
|
548
|
-
${this._renderClearIcon()} ${this.
|
|
554
|
+
${this._renderClearIcon()} ${this.renderIcon()} ${this._renderPasswordIcon()}
|
|
549
555
|
</div>
|
|
550
556
|
${this.description != null ? html`<div class="description" .innerHTML="${this.description}"></div>` : ''}
|
|
551
557
|
`;
|
|
@@ -0,0 +1,642 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Copyright (C) 2021 The Gravitee team (http://gravitee.io)
|
|
3
|
+
*
|
|
4
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
* you may not use this file except in compliance with the License.
|
|
6
|
+
* You may obtain a copy of the License at
|
|
7
|
+
*
|
|
8
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
*
|
|
10
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
* See the License for the specific language governing permissions and
|
|
14
|
+
* limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
// Ace highlight rules function imported below.
|
|
17
|
+
const HighlightRules = function () {
|
|
18
|
+
const identifierRe = '[a-zA-Z\u00a1-\uffff]+\\b';
|
|
19
|
+
/* eslint no-useless-escape: "off" */
|
|
20
|
+
this.$rules = {
|
|
21
|
+
start: [
|
|
22
|
+
{ token: 'empty', regex: /$/ },
|
|
23
|
+
{ token: 'literal', regex: /^\.{4,}\s*$/, next: 'listingBlock' },
|
|
24
|
+
{ token: 'literal', regex: /^-{4,}\s*$/, next: 'literalBlock' },
|
|
25
|
+
{ token: 'literal', regex: /^\+{4,}\s*$/, next: 'passthroughBlock' },
|
|
26
|
+
{ token: 'keyword', regex: /^={4,}\s*$/ },
|
|
27
|
+
{ token: 'text', regex: /^\s*$/ },
|
|
28
|
+
// immediately return to the start mode without matching anything
|
|
29
|
+
{ token: 'empty', regex: '', next: 'dissallowDelimitedBlock' },
|
|
30
|
+
],
|
|
31
|
+
|
|
32
|
+
dissallowDelimitedBlock: [
|
|
33
|
+
{ include: 'paragraphEnd' },
|
|
34
|
+
{ token: 'comment', regex: '^//.+$' },
|
|
35
|
+
{ token: 'keyword', regex: '^(?:NOTE|TIP|IMPORTANT|WARNING|CAUTION):\\s' },
|
|
36
|
+
|
|
37
|
+
{ include: 'listStart' },
|
|
38
|
+
{ token: 'literal', regex: /^\s+.+$/, next: 'indentedBlock' },
|
|
39
|
+
{ token: 'empty', regex: '', next: 'text' },
|
|
40
|
+
],
|
|
41
|
+
|
|
42
|
+
paragraphEnd: [
|
|
43
|
+
{ token: 'doc.comment', regex: /^\/{4,}\s*$/, next: 'commentBlock' },
|
|
44
|
+
{ token: 'tableBlock', regex: /^\s*[|!]=+\s*$/, next: 'tableBlock' },
|
|
45
|
+
// open block, ruler
|
|
46
|
+
{ token: 'keyword', regex: /^(?:--|''')\s*$/, next: 'start' },
|
|
47
|
+
{ token: 'option', regex: /^\[.*\]\s*$/, next: 'start' },
|
|
48
|
+
{ token: 'pageBreak', regex: /^>{3,}$/, next: 'start' },
|
|
49
|
+
{ token: 'literal', regex: /^\.{4,}\s*$/, next: 'listingBlock' },
|
|
50
|
+
{ token: 'titleUnderline', regex: /^(?:={2,}|-{2,}|~{2,}|\^{2,}|\+{2,})\s*$/, next: 'start' },
|
|
51
|
+
{ token: 'singleLineTitle', regex: /^={1,6}\s+\S.*$/, next: 'start' },
|
|
52
|
+
|
|
53
|
+
{ token: 'otherBlock', regex: /^(?:\*{2,}|_{2,})\s*$/, next: 'start' },
|
|
54
|
+
// .optional title
|
|
55
|
+
{ token: 'optionalTitle', regex: /^\.[^.\s].+$/, next: 'start' },
|
|
56
|
+
],
|
|
57
|
+
|
|
58
|
+
listStart: [
|
|
59
|
+
{
|
|
60
|
+
token: 'keyword',
|
|
61
|
+
regex: /^\s*(?:\d+\.|[a-zA-Z]\.|[ixvmIXVM]+\)|\*{1,5}|-|\.{1,5})\s/,
|
|
62
|
+
next: 'listText',
|
|
63
|
+
},
|
|
64
|
+
{ token: 'meta.tag', regex: /^.+(?::{2,4}|;;)(?: |$)/, next: 'listText' },
|
|
65
|
+
// continuation
|
|
66
|
+
{ token: 'keyword', regex: /^\+\s*$/, next: 'start' },
|
|
67
|
+
],
|
|
68
|
+
|
|
69
|
+
text: [
|
|
70
|
+
{
|
|
71
|
+
token: ['link', 'link'],
|
|
72
|
+
regex: /((?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+)(\[.*?\])/,
|
|
73
|
+
},
|
|
74
|
+
{ token: ['link', 'link'], regex: /(?:https?:\/\/|ftp:\/\/|file:\/\/|mailto:|callto:)[^\s\[]+/ },
|
|
75
|
+
{ token: 'link', regex: /\b[\w\.\/\-]+@[\w\.\/\-]+\b/ },
|
|
76
|
+
{ include: 'macros' },
|
|
77
|
+
{ include: 'paragraphEnd' },
|
|
78
|
+
{ token: 'literal', regex: /\+{3,}/, next: 'smallPassthrough' },
|
|
79
|
+
{
|
|
80
|
+
token: 'escape',
|
|
81
|
+
regex: /\((?:C|TM|R)\)|\.{3}|->|<-|=>|<=|&#(?:\d+|x[a-fA-F\d]+);|(?: |^)--(?=\s+\S)/,
|
|
82
|
+
},
|
|
83
|
+
{ token: 'escape', regex: /\\[_*'`+#]|\\{2}[_*'`+#]{2}/ },
|
|
84
|
+
{ token: 'keyword', regex: /\s\+$/ },
|
|
85
|
+
// any word
|
|
86
|
+
{ token: 'text', regex: identifierRe },
|
|
87
|
+
{
|
|
88
|
+
token: ['keyword', 'string', 'keyword'],
|
|
89
|
+
regex: /(<<[\w\d\-$]+,)(.*?)(>>|$)/,
|
|
90
|
+
},
|
|
91
|
+
{ token: 'keyword', regex: /<<[\w\d\-$]+,?|>>/ },
|
|
92
|
+
{ token: 'constant.character', regex: /\({2,3}.*?\){2,3}/ },
|
|
93
|
+
// List of callouts
|
|
94
|
+
{ token: 'support.function.list.callout', regex: /^(?:<\d+>|\d+>|>) /, next: 'text' },
|
|
95
|
+
// Anchor
|
|
96
|
+
{ token: 'keyword', regex: /\[\[.+?\]\]/ },
|
|
97
|
+
// bibliography
|
|
98
|
+
{ token: 'support', regex: /^\[{3}[\w\d =\-]+\]{3}/ },
|
|
99
|
+
|
|
100
|
+
{ include: 'quotes' },
|
|
101
|
+
// text block end
|
|
102
|
+
{ token: 'empty', regex: /^\s*$/, next: 'start' },
|
|
103
|
+
],
|
|
104
|
+
|
|
105
|
+
listText: [{ include: 'listStart' }, { include: 'text' }],
|
|
106
|
+
|
|
107
|
+
indentedBlock: [
|
|
108
|
+
{ token: 'literal', regex: /^[\s\w].+$/, next: 'indentedBlock' },
|
|
109
|
+
{ token: 'literal', regex: '', next: 'start' },
|
|
110
|
+
],
|
|
111
|
+
|
|
112
|
+
listingBlock: [
|
|
113
|
+
{ token: 'literal', regex: /^\.{4,}\s*$/, next: 'dissallowDelimitedBlock' },
|
|
114
|
+
{ token: 'constant.numeric', regex: '<\\d+>' },
|
|
115
|
+
{ token: 'literal', regex: '[^<]+' },
|
|
116
|
+
{ token: 'literal', regex: '<' },
|
|
117
|
+
],
|
|
118
|
+
literalBlock: [
|
|
119
|
+
{ token: 'literal', regex: /^-{4,}\s*$/, next: 'dissallowDelimitedBlock' },
|
|
120
|
+
{ token: 'constant.numeric', regex: '<\\d+>' },
|
|
121
|
+
{ token: 'literal', regex: '[^<]+' },
|
|
122
|
+
{ token: 'literal', regex: '<' },
|
|
123
|
+
],
|
|
124
|
+
passthroughBlock: [
|
|
125
|
+
{ token: 'literal', regex: /^\+{4,}\s*$/, next: 'dissallowDelimitedBlock' },
|
|
126
|
+
{ token: 'literal', regex: identifierRe + '|\\d+' },
|
|
127
|
+
{ include: 'macros' },
|
|
128
|
+
{ token: 'literal', regex: '.' },
|
|
129
|
+
],
|
|
130
|
+
|
|
131
|
+
smallPassthrough: [
|
|
132
|
+
{ token: 'literal', regex: /[+]{3,}/, next: 'dissallowDelimitedBlock' },
|
|
133
|
+
{ token: 'literal', regex: /^\s*$/, next: 'dissallowDelimitedBlock' },
|
|
134
|
+
{ token: 'literal', regex: identifierRe + '|\\d+' },
|
|
135
|
+
{ include: 'macros' },
|
|
136
|
+
],
|
|
137
|
+
|
|
138
|
+
commentBlock: [
|
|
139
|
+
{ token: 'doc.comment', regex: /^\/{4,}\s*$/, next: 'dissallowDelimitedBlock' },
|
|
140
|
+
{ token: 'doc.comment', regex: '^.*$' },
|
|
141
|
+
],
|
|
142
|
+
tableBlock: [
|
|
143
|
+
{ token: 'tableBlock', regex: /^\s*\|={3,}\s*$/, next: 'dissallowDelimitedBlock' },
|
|
144
|
+
{ token: 'tableBlock', regex: /^\s*!={3,}\s*$/, next: 'innerTableBlock' },
|
|
145
|
+
{ token: 'tableBlock', regex: /\|/ },
|
|
146
|
+
{ include: 'text', noEscape: true },
|
|
147
|
+
],
|
|
148
|
+
innerTableBlock: [
|
|
149
|
+
{ token: 'tableBlock', regex: /^\s*!={3,}\s*$/, next: 'tableBlock' },
|
|
150
|
+
{ token: 'tableBlock', regex: /^\s*|={3,}\s*$/, next: 'dissallowDelimitedBlock' },
|
|
151
|
+
{ token: 'tableBlock', regex: /\!/ },
|
|
152
|
+
],
|
|
153
|
+
macros: [
|
|
154
|
+
{ token: 'macro', regex: /{[\w\-$]+}/ },
|
|
155
|
+
{
|
|
156
|
+
token: ['text', 'string', 'text', 'constant.character', 'text'],
|
|
157
|
+
regex: /({)([\w\-$]+)(:)?(.+)?(})/,
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
token: ['text', 'markup.list.macro', 'keyword', 'string'],
|
|
161
|
+
regex: /(\w+)(footnote(?:ref)?::?)([^\s\[]+)?(\[.*?\])?/,
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
token: ['markup.list.macro', 'keyword', 'string'],
|
|
165
|
+
regex: /([a-zA-Z\-][\w\.\/\-]*::?)([^\s\[]+)(\[.*?\])?/,
|
|
166
|
+
},
|
|
167
|
+
{ token: ['markup.list.macro', 'keyword'], regex: /([a-zA-Z\-][\w\.\/\-]+::?)(\[.*?\])/ },
|
|
168
|
+
{ token: 'keyword', regex: /^:.+?:(?= |$)/ },
|
|
169
|
+
],
|
|
170
|
+
|
|
171
|
+
quotes: [
|
|
172
|
+
{ token: 'string.italic', regex: /__[^_\s].*?__/ },
|
|
173
|
+
{ token: 'string.italic', regex: quoteRule('_') },
|
|
174
|
+
|
|
175
|
+
{ token: 'keyword.bold', regex: /\*\*[^*\s].*?\*\*/ },
|
|
176
|
+
{ token: 'keyword.bold', regex: quoteRule('\\*') },
|
|
177
|
+
|
|
178
|
+
{ token: 'literal', regex: /\+\+[^+\s].*?\+\+/ },
|
|
179
|
+
{ token: 'literal', regex: quoteRule('\\+') },
|
|
180
|
+
|
|
181
|
+
{ token: 'literal', regex: /\$\$.+?\$\$/ },
|
|
182
|
+
{ token: 'literal', regex: quoteRule('\\$') },
|
|
183
|
+
|
|
184
|
+
{ token: 'literal', regex: /``[^`\s].*?``/ },
|
|
185
|
+
{ token: 'literal', regex: quoteRule('`') },
|
|
186
|
+
|
|
187
|
+
{ token: 'keyword', regex: /\^[^\^].*?\^/ },
|
|
188
|
+
{ token: 'keyword', regex: quoteRule('\\^') },
|
|
189
|
+
{ token: 'keyword', regex: /~[^~].*?~/ },
|
|
190
|
+
{ token: 'keyword', regex: quoteRule('~') },
|
|
191
|
+
|
|
192
|
+
{ token: 'keyword', regex: /##?/ },
|
|
193
|
+
{ token: 'keyword', regex: /(?:\B|^)``|\b''/ },
|
|
194
|
+
],
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
function quoteRule(ch) {
|
|
198
|
+
const prefix = /\w/.test(ch) ? '\\b' : '(?:\\B|^)';
|
|
199
|
+
return prefix + ch + '[^' + ch + '].*?' + ch + '(?![\\w*])';
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// addQuoteBlock("text")
|
|
203
|
+
|
|
204
|
+
const tokenMap = {
|
|
205
|
+
macro: 'constant.character',
|
|
206
|
+
tableBlock: 'doc.comment',
|
|
207
|
+
titleUnderline: 'markup.heading',
|
|
208
|
+
singleLineTitle: 'markup.heading',
|
|
209
|
+
pageBreak: 'string',
|
|
210
|
+
option: 'string.regexp',
|
|
211
|
+
otherBlock: 'markup.list',
|
|
212
|
+
literal: 'support.function',
|
|
213
|
+
optionalTitle: 'constant.numeric',
|
|
214
|
+
escape: 'constant.language.escape',
|
|
215
|
+
link: 'markup.underline.list',
|
|
216
|
+
};
|
|
217
|
+
|
|
218
|
+
for (const state in this.$rules) {
|
|
219
|
+
const stateRules = this.$rules[state];
|
|
220
|
+
for (let i = stateRules.length; i--; ) {
|
|
221
|
+
const rule = stateRules[i];
|
|
222
|
+
if (rule.include || typeof rule === 'string') {
|
|
223
|
+
let args = [i, 1].concat(this.$rules[rule.include || rule]);
|
|
224
|
+
if (rule.noEscape) {
|
|
225
|
+
args = args.filter(function (x) {
|
|
226
|
+
return !x.next;
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
stateRules.splice.apply(stateRules, args);
|
|
230
|
+
} else if (rule.token in tokenMap) {
|
|
231
|
+
rule.token = tokenMap[rule.token];
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
};
|
|
236
|
+
|
|
237
|
+
// Ace's Syntax Tokenizer.
|
|
238
|
+
|
|
239
|
+
// tokenizing lines longer than this makes editor very slow
|
|
240
|
+
let MAX_TOKEN_COUNT = 1000;
|
|
241
|
+
const Tokenizer = function (rules) {
|
|
242
|
+
this.states = rules;
|
|
243
|
+
|
|
244
|
+
this.regExps = {};
|
|
245
|
+
this.matchMappings = {};
|
|
246
|
+
for (const key in this.states) {
|
|
247
|
+
const state = this.states[key];
|
|
248
|
+
const ruleRegExps = [];
|
|
249
|
+
let matchTotal = 0;
|
|
250
|
+
const mapping = (this.matchMappings[key] = { defaultToken: 'text' });
|
|
251
|
+
let flag = 'g';
|
|
252
|
+
|
|
253
|
+
const splitterRurles = [];
|
|
254
|
+
for (let i = 0; i < state.length; i++) {
|
|
255
|
+
const rule = state[i];
|
|
256
|
+
if (rule.defaultToken) mapping.defaultToken = rule.defaultToken;
|
|
257
|
+
if (rule.caseInsensitive) flag = 'gi';
|
|
258
|
+
if (rule.regex == null) continue;
|
|
259
|
+
|
|
260
|
+
if (rule.regex instanceof RegExp) rule.regex = rule.regex.toString().slice(1, -1);
|
|
261
|
+
|
|
262
|
+
// Count number of matching groups. 2 extra groups from the full match
|
|
263
|
+
// And the catch-all on the end (used to force a match);
|
|
264
|
+
let adjustedregex = rule.regex;
|
|
265
|
+
let matchcount = new RegExp('(?:(' + adjustedregex + ')|(.))').exec('a').length - 2;
|
|
266
|
+
if (Array.isArray(rule.token)) {
|
|
267
|
+
if (rule.token.length === 1 || matchcount === 1) {
|
|
268
|
+
rule.token = rule.token[0];
|
|
269
|
+
} else if (matchcount - 1 !== rule.token.length) {
|
|
270
|
+
throw new Error(
|
|
271
|
+
"number of classes and regexp groups in '" +
|
|
272
|
+
rule.token +
|
|
273
|
+
"'\n'" +
|
|
274
|
+
rule.regex +
|
|
275
|
+
"' doesn't match\n" +
|
|
276
|
+
(matchcount - 1) +
|
|
277
|
+
'!=' +
|
|
278
|
+
rule.token.length,
|
|
279
|
+
);
|
|
280
|
+
} else {
|
|
281
|
+
rule.tokenArray = rule.token;
|
|
282
|
+
rule.token = null;
|
|
283
|
+
rule.onMatch = this.$arrayTokens;
|
|
284
|
+
}
|
|
285
|
+
} else if (typeof rule.token === 'function' && !rule.onMatch) {
|
|
286
|
+
if (matchcount > 1) rule.onMatch = this.$applyToken;
|
|
287
|
+
else rule.onMatch = rule.token;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
if (matchcount > 1) {
|
|
291
|
+
if (/\\\d/.test(rule.regex)) {
|
|
292
|
+
// Replace any backreferences and offset appropriately.
|
|
293
|
+
adjustedregex = rule.regex.replace(/\\([0-9]+)/g, function (match, digit) {
|
|
294
|
+
return '\\' + (parseInt(digit, 10) + matchTotal + 1);
|
|
295
|
+
});
|
|
296
|
+
} else {
|
|
297
|
+
matchcount = 1;
|
|
298
|
+
adjustedregex = this.removeCapturingGroups(rule.regex);
|
|
299
|
+
}
|
|
300
|
+
if (!rule.splitRegex && typeof rule.token !== 'string')
|
|
301
|
+
// flag will be known only at the very end
|
|
302
|
+
splitterRurles.push(rule);
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
mapping[matchTotal] = i;
|
|
306
|
+
matchTotal += matchcount;
|
|
307
|
+
|
|
308
|
+
ruleRegExps.push(adjustedregex);
|
|
309
|
+
|
|
310
|
+
// makes property access faster
|
|
311
|
+
if (!rule.onMatch) rule.onMatch = null;
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
splitterRurles.forEach(function (rule) {
|
|
315
|
+
rule.splitRegex = this.createSplitterRegexp(rule.regex, flag);
|
|
316
|
+
}, this);
|
|
317
|
+
|
|
318
|
+
this.regExps[key] = new RegExp('(' + ruleRegExps.join(')|(') + ')|($)', flag);
|
|
319
|
+
}
|
|
320
|
+
};
|
|
321
|
+
|
|
322
|
+
(function () {
|
|
323
|
+
this.$setMaxTokenCount = function (m) {
|
|
324
|
+
MAX_TOKEN_COUNT = m | 0;
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
this.$applyToken = function (str) {
|
|
328
|
+
const values = this.splitRegex.exec(str).slice(1);
|
|
329
|
+
const types = this.token.apply(this, values);
|
|
330
|
+
|
|
331
|
+
// required for compatibility with old modes
|
|
332
|
+
if (typeof types === 'string') return [{ type: types, value: str }];
|
|
333
|
+
|
|
334
|
+
const tokens = [];
|
|
335
|
+
for (let i = 0, l = types.length; i < l; i++) {
|
|
336
|
+
if (values[i])
|
|
337
|
+
tokens[tokens.length] = {
|
|
338
|
+
type: types[i],
|
|
339
|
+
value: values[i],
|
|
340
|
+
};
|
|
341
|
+
}
|
|
342
|
+
return tokens;
|
|
343
|
+
};
|
|
344
|
+
|
|
345
|
+
this.$arrayTokens = function (str) {
|
|
346
|
+
if (!str) return [];
|
|
347
|
+
const values = this.splitRegex.exec(str);
|
|
348
|
+
if (!values) return 'text';
|
|
349
|
+
const tokens = [];
|
|
350
|
+
const types = this.tokenArray;
|
|
351
|
+
for (let i = 0, l = types.length; i < l; i++) {
|
|
352
|
+
if (values[i + 1])
|
|
353
|
+
tokens[tokens.length] = {
|
|
354
|
+
type: types[i],
|
|
355
|
+
value: values[i + 1],
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
return tokens;
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
this.removeCapturingGroups = function (src) {
|
|
362
|
+
const r = src.replace(/\[(?:\\.|[^\]])*?\]|\\.|\(\?[:=!]|(\()/g, function (x, y) {
|
|
363
|
+
return y ? '(?:' : x;
|
|
364
|
+
});
|
|
365
|
+
return r;
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
this.createSplitterRegexp = function (src, flag) {
|
|
369
|
+
if (src.indexOf('(?=') !== -1) {
|
|
370
|
+
let stack = 0;
|
|
371
|
+
let inChClass = false;
|
|
372
|
+
const lastCapture = {};
|
|
373
|
+
src.replace(/(\\.)|(\((?:\?[=!])?)|(\))|([\[\]])/g, function (m, esc, parenOpen, parenClose, square, index) {
|
|
374
|
+
if (inChClass) {
|
|
375
|
+
inChClass = square !== ']';
|
|
376
|
+
} else if (square) {
|
|
377
|
+
inChClass = true;
|
|
378
|
+
} else if (parenClose) {
|
|
379
|
+
if (stack === lastCapture.stack) {
|
|
380
|
+
lastCapture.end = index + 1;
|
|
381
|
+
lastCapture.stack = -1;
|
|
382
|
+
}
|
|
383
|
+
stack--;
|
|
384
|
+
} else if (parenOpen) {
|
|
385
|
+
stack++;
|
|
386
|
+
if (parenOpen.length !== 1) {
|
|
387
|
+
lastCapture.stack = stack;
|
|
388
|
+
lastCapture.start = index;
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
return m;
|
|
392
|
+
});
|
|
393
|
+
|
|
394
|
+
if (lastCapture.end != null && /^\)*$/.test(src.substr(lastCapture.end)))
|
|
395
|
+
src = src.substring(0, lastCapture.start) + src.substr(lastCapture.end);
|
|
396
|
+
}
|
|
397
|
+
return new RegExp(src, (flag || '').replace('g', ''));
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Returns an object containing two properties: `tokens`, which contains all the tokens; and `state`, the current state.
|
|
402
|
+
* @returns {Object}
|
|
403
|
+
**/
|
|
404
|
+
this.getLineTokens = function (line, startState) {
|
|
405
|
+
let stack = [];
|
|
406
|
+
if (startState && typeof startState !== 'string') {
|
|
407
|
+
stack = startState.slice(0);
|
|
408
|
+
startState = stack[0];
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
let currentState = startState || 'start';
|
|
412
|
+
let state = this.states[currentState];
|
|
413
|
+
if (!state) {
|
|
414
|
+
currentState = 'start';
|
|
415
|
+
state = this.states[currentState];
|
|
416
|
+
}
|
|
417
|
+
let mapping = this.matchMappings[currentState];
|
|
418
|
+
let re = this.regExps[currentState];
|
|
419
|
+
re.lastIndex = 0;
|
|
420
|
+
|
|
421
|
+
let match;
|
|
422
|
+
const tokens = [];
|
|
423
|
+
let lastIndex = 0;
|
|
424
|
+
|
|
425
|
+
let token = { type: null, value: '' };
|
|
426
|
+
|
|
427
|
+
/* eslint no-cond-assign: "off" */
|
|
428
|
+
while ((match = re.exec(line))) {
|
|
429
|
+
let type = mapping.defaultToken;
|
|
430
|
+
let rule = null;
|
|
431
|
+
const value = match[0];
|
|
432
|
+
const index = re.lastIndex;
|
|
433
|
+
|
|
434
|
+
if (index - value.length > lastIndex) {
|
|
435
|
+
const skipped = line.substring(lastIndex, index - value.length);
|
|
436
|
+
if (token.type === type) {
|
|
437
|
+
token.value += skipped;
|
|
438
|
+
} else {
|
|
439
|
+
if (token.type) tokens.push(token);
|
|
440
|
+
token = { type: type, value: skipped };
|
|
441
|
+
}
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
for (let i = 0; i < match.length - 2; i++) {
|
|
445
|
+
if (match[i + 1] === undefined) continue;
|
|
446
|
+
|
|
447
|
+
rule = state[mapping[i]];
|
|
448
|
+
|
|
449
|
+
if (rule.onMatch) type = rule.onMatch(value, currentState, stack);
|
|
450
|
+
else type = rule.token;
|
|
451
|
+
|
|
452
|
+
if (rule.next) {
|
|
453
|
+
if (typeof rule.next === 'string') currentState = rule.next;
|
|
454
|
+
else currentState = rule.next(currentState, stack);
|
|
455
|
+
|
|
456
|
+
state = this.states[currentState];
|
|
457
|
+
if (!state) {
|
|
458
|
+
window.console && console.error && console.error(currentState, "doesn't exist");
|
|
459
|
+
currentState = 'start';
|
|
460
|
+
state = this.states[currentState];
|
|
461
|
+
}
|
|
462
|
+
mapping = this.matchMappings[currentState];
|
|
463
|
+
lastIndex = index;
|
|
464
|
+
re = this.regExps[currentState];
|
|
465
|
+
re.lastIndex = index;
|
|
466
|
+
}
|
|
467
|
+
break;
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (value) {
|
|
471
|
+
if (typeof type === 'string') {
|
|
472
|
+
if ((!rule || rule.merge !== false) && token.type === type) {
|
|
473
|
+
token.value += value;
|
|
474
|
+
} else {
|
|
475
|
+
if (token.type) tokens.push(token);
|
|
476
|
+
token = { type: type, value: value };
|
|
477
|
+
}
|
|
478
|
+
} else if (type) {
|
|
479
|
+
if (token.type) tokens.push(token);
|
|
480
|
+
token = { type: null, value: '' };
|
|
481
|
+
for (let i = 0; i < type.length; i++) tokens.push(type[i]);
|
|
482
|
+
}
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
if (lastIndex === line.length) break;
|
|
486
|
+
|
|
487
|
+
lastIndex = index;
|
|
488
|
+
|
|
489
|
+
if (tokens.length > MAX_TOKEN_COUNT) {
|
|
490
|
+
// chrome doens't show contents of text nodes with very long text
|
|
491
|
+
while (lastIndex < line.length) {
|
|
492
|
+
if (token.type) tokens.push(token);
|
|
493
|
+
token = {
|
|
494
|
+
value: line.substring(lastIndex, (lastIndex += 2000)),
|
|
495
|
+
type: 'overflow',
|
|
496
|
+
};
|
|
497
|
+
}
|
|
498
|
+
currentState = 'start';
|
|
499
|
+
stack = [];
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
if (token.type) tokens.push(token);
|
|
505
|
+
|
|
506
|
+
if (stack.length > 1) {
|
|
507
|
+
if (stack[0] !== currentState) stack.unshift(currentState);
|
|
508
|
+
}
|
|
509
|
+
return {
|
|
510
|
+
tokens: tokens,
|
|
511
|
+
state: stack.length ? stack : currentState,
|
|
512
|
+
};
|
|
513
|
+
};
|
|
514
|
+
}.call(Tokenizer.prototype));
|
|
515
|
+
|
|
516
|
+
// Token conversion.
|
|
517
|
+
// See <https://github.com/ajaxorg/ace/wiki/Creating-or-Extending-an-Edit-Mode#common-tokens>
|
|
518
|
+
// This is not an exact match nor the best match that can be made.
|
|
519
|
+
const tokenFromAceToken = {
|
|
520
|
+
empty: null,
|
|
521
|
+
text: null,
|
|
522
|
+
|
|
523
|
+
// Keyword
|
|
524
|
+
keyword: 'keyword',
|
|
525
|
+
control: 'keyword',
|
|
526
|
+
operator: 'operator',
|
|
527
|
+
|
|
528
|
+
// Constants
|
|
529
|
+
constant: 'atom',
|
|
530
|
+
numeric: 'number',
|
|
531
|
+
character: 'atom',
|
|
532
|
+
escape: 'atom',
|
|
533
|
+
|
|
534
|
+
// Variables
|
|
535
|
+
variable: 'variable',
|
|
536
|
+
parameter: 'variable-3',
|
|
537
|
+
// Python's `self` uses that.
|
|
538
|
+
language: 'variable-2',
|
|
539
|
+
|
|
540
|
+
// Comments
|
|
541
|
+
comment: 'comment',
|
|
542
|
+
line: 'comment',
|
|
543
|
+
'double-slash': 'comment',
|
|
544
|
+
'double-dash': 'comment',
|
|
545
|
+
'number-sign': 'comment',
|
|
546
|
+
percentage: 'comment',
|
|
547
|
+
block: 'comment',
|
|
548
|
+
doc: 'comment',
|
|
549
|
+
|
|
550
|
+
// String
|
|
551
|
+
string: 'string',
|
|
552
|
+
quoted: 'string',
|
|
553
|
+
single: 'string',
|
|
554
|
+
double: 'string',
|
|
555
|
+
triple: 'string',
|
|
556
|
+
unquoted: 'string',
|
|
557
|
+
interpolated: 'string',
|
|
558
|
+
regexp: 'string-2',
|
|
559
|
+
|
|
560
|
+
meta: 'keyword',
|
|
561
|
+
literal: 'qualifier',
|
|
562
|
+
support: 'builtin',
|
|
563
|
+
|
|
564
|
+
// Markup
|
|
565
|
+
markup: 'tag',
|
|
566
|
+
underline: 'link',
|
|
567
|
+
link: 'link',
|
|
568
|
+
strong: 'strong',
|
|
569
|
+
heading: 'header',
|
|
570
|
+
em: 'em',
|
|
571
|
+
list: 'variable-2',
|
|
572
|
+
numbered: 'variable-2',
|
|
573
|
+
unnumbered: 'variable-2',
|
|
574
|
+
quote: 'quote',
|
|
575
|
+
// Markdown's raw block uses that.
|
|
576
|
+
raw: 'variable-2',
|
|
577
|
+
|
|
578
|
+
// Invalid
|
|
579
|
+
invalid: 'error',
|
|
580
|
+
illegal: 'invalidchar',
|
|
581
|
+
deprecated: 'error',
|
|
582
|
+
};
|
|
583
|
+
|
|
584
|
+
// Takes a list of Ace tokens, returns a (string) CodeMirror token.
|
|
585
|
+
const cmTokenFromAceTokens = function (tokens) {
|
|
586
|
+
let token = null;
|
|
587
|
+
for (let i = 0; i < tokens.length; i++) {
|
|
588
|
+
// Find the most specific token.
|
|
589
|
+
if (tokenFromAceToken[tokens[i]] !== undefined) {
|
|
590
|
+
token = tokenFromAceToken[tokens[i]];
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
return token;
|
|
594
|
+
};
|
|
595
|
+
|
|
596
|
+
// Consume a token from plannedTokens.
|
|
597
|
+
const consumeToken = function (stream, state) {
|
|
598
|
+
const plannedToken = state.plannedTokens.shift();
|
|
599
|
+
if (plannedToken === undefined) {
|
|
600
|
+
return null;
|
|
601
|
+
}
|
|
602
|
+
stream.match(plannedToken.value);
|
|
603
|
+
const tokens = plannedToken.type.split('.');
|
|
604
|
+
return cmTokenFromAceTokens(tokens);
|
|
605
|
+
};
|
|
606
|
+
|
|
607
|
+
const matchToken = function (stream, state) {
|
|
608
|
+
// Anormal start: we already have planned tokens to consume.
|
|
609
|
+
if (state.plannedTokens.length > 0) {
|
|
610
|
+
return consumeToken(stream, state);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Normal start.
|
|
614
|
+
const currentState = state.current;
|
|
615
|
+
const currentLine = stream.match(/.*$/, false)[0];
|
|
616
|
+
const tokenized = tokenizer.getLineTokens(currentLine, currentState);
|
|
617
|
+
// We got a {tokens, state} object.
|
|
618
|
+
// Each token is a {value, type} object.
|
|
619
|
+
state.plannedTokens = tokenized.tokens;
|
|
620
|
+
state.current = tokenized.state;
|
|
621
|
+
|
|
622
|
+
// Consume a token.
|
|
623
|
+
return consumeToken(stream, state);
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
// Initialize all state.
|
|
627
|
+
const aceHighlightRules = new HighlightRules();
|
|
628
|
+
const tokenizer = new Tokenizer(aceHighlightRules.$rules);
|
|
629
|
+
|
|
630
|
+
export const asciidoc = {
|
|
631
|
+
startState: function () {
|
|
632
|
+
return {
|
|
633
|
+
current: 'start',
|
|
634
|
+
// List of {value, type}, with type being an Ace token string.
|
|
635
|
+
plannedTokens: [],
|
|
636
|
+
};
|
|
637
|
+
},
|
|
638
|
+
blankLine: function (state) {
|
|
639
|
+
matchToken('', state);
|
|
640
|
+
},
|
|
641
|
+
token: matchToken,
|
|
642
|
+
};
|
|
@@ -52,13 +52,16 @@ export function InputElement(ParentClass) {
|
|
|
52
52
|
:host([invalid]) :not(.clipboard) ::slotted(.input),
|
|
53
53
|
:host([invalid]) :not(.clipboard) .box-icon-left,
|
|
54
54
|
:host([invalid]) :not(.clipboard) textarea,
|
|
55
|
-
:host([invalid]) :not(.clipboard) select
|
|
55
|
+
:host([invalid]) :not(.clipboard) select,
|
|
56
|
+
:host([invalid]) :not(.clipboard) .input {
|
|
56
57
|
box-shadow: inset 3px 0 0 var(--gv-input-invalid--bxshc, var(--gv-theme-color-error, #da1a1b));
|
|
57
58
|
}
|
|
58
59
|
|
|
59
60
|
:host([readonly]) :not(.clipboard) input,
|
|
60
61
|
:host([readonly]) :not(.clipboard) ::slotted(.input),
|
|
61
|
-
:host([readonly]) .textarea
|
|
62
|
+
:host([readonly]) .textarea,
|
|
63
|
+
:host([readonly]) :not(.clipboard) select,
|
|
64
|
+
:host([readonly]) .input {
|
|
62
65
|
border-left: 1px solid var(--gv-input--bdc, var(--gv-theme-neutral-color-dark, #d9d9d9));
|
|
63
66
|
}
|
|
64
67
|
|
|
@@ -86,7 +89,7 @@ export function InputElement(ParentClass) {
|
|
|
86
89
|
|
|
87
90
|
setValidity(isInvalid = false, violation = '') {
|
|
88
91
|
const element = this.getInputElement();
|
|
89
|
-
if (element) {
|
|
92
|
+
if (element && element.setCustomValidity) {
|
|
90
93
|
if (isInvalid) {
|
|
91
94
|
if (violation == null || violation.trim() === '') {
|
|
92
95
|
violation = 'field is not valid';
|
|
@@ -95,6 +98,7 @@ export function InputElement(ParentClass) {
|
|
|
95
98
|
} else {
|
|
96
99
|
element.setCustomValidity('');
|
|
97
100
|
}
|
|
101
|
+
element.reportValidity();
|
|
98
102
|
}
|
|
99
103
|
this.invalid = isInvalid;
|
|
100
104
|
this.valid = !this.invalid;
|
package/src/molecules/gv-code.js
CHANGED
|
@@ -13,12 +13,7 @@
|
|
|
13
13
|
* See the License for the specific language governing permissions and
|
|
14
14
|
* limitations under the License.
|
|
15
15
|
*/
|
|
16
|
-
import { css,
|
|
17
|
-
|
|
18
|
-
import { shapeClipboard, shapeCopied } from '../styles/shapes';
|
|
19
|
-
import { dispatchCustomEvent } from '../lib/events';
|
|
20
|
-
import { uuid } from '../lib/utils';
|
|
21
|
-
import { classMap } from 'lit-html/directives/class-map';
|
|
16
|
+
import { css, html } from 'lit';
|
|
22
17
|
|
|
23
18
|
import { EditorView, basicSetup } from '@codemirror/basic-setup';
|
|
24
19
|
import { EditorState, Compartment } from '@codemirror/state';
|
|
@@ -26,16 +21,16 @@ import { autocompletion } from '@codemirror/autocomplete';
|
|
|
26
21
|
import { json } from '@codemirror/lang-json';
|
|
27
22
|
import { languages } from '@codemirror/language-data';
|
|
28
23
|
import { placeholder } from '@codemirror/view';
|
|
29
|
-
|
|
30
|
-
import {
|
|
24
|
+
|
|
25
|
+
import { shapeClipboard } from '../styles/shapes';
|
|
26
|
+
import { dispatchCustomEvent } from '../lib/events';
|
|
27
|
+
import { uuid } from '../lib/utils';
|
|
28
|
+
import { classMap } from 'lit-html/directives/class-map';
|
|
29
|
+
import { GvInput } from '../atoms/gv-input';
|
|
31
30
|
import { skeleton } from '../styles/skeleton';
|
|
32
31
|
import { empty } from '../styles/empty';
|
|
33
32
|
import { input } from '../styles/input';
|
|
34
33
|
|
|
35
|
-
const languageCompartment = new Compartment();
|
|
36
|
-
const readonlyCompartment = new Compartment();
|
|
37
|
-
const placeholderCompartment = new Compartment();
|
|
38
|
-
|
|
39
34
|
/**
|
|
40
35
|
* Code component
|
|
41
36
|
*
|
|
@@ -59,16 +54,11 @@ const placeholderCompartment = new Compartment();
|
|
|
59
54
|
* @attr {Boolean} [autofocus=false] - true to put the focus on the input
|
|
60
55
|
* @attr {Boolean} [readonly=false] - true if field is readonly mode
|
|
61
56
|
*/
|
|
62
|
-
export class GvCode extends
|
|
57
|
+
export class GvCode extends GvInput {
|
|
63
58
|
static get properties() {
|
|
64
59
|
return {
|
|
65
60
|
...super.properties,
|
|
66
61
|
options: { type: Object },
|
|
67
|
-
large: { type: Boolean },
|
|
68
|
-
medium: { type: Boolean },
|
|
69
|
-
small: { type: Boolean },
|
|
70
|
-
clipboard: { type: Boolean },
|
|
71
|
-
_clipboardIcon: { type: String },
|
|
72
62
|
rows: { type: Number },
|
|
73
63
|
_error: { type: String, attribute: false },
|
|
74
64
|
};
|
|
@@ -82,6 +72,9 @@ export class GvCode extends InputElement(LitElement) {
|
|
|
82
72
|
this.autofocus = false;
|
|
83
73
|
this.clipboard = false;
|
|
84
74
|
this._clipboardIcon = shapeClipboard;
|
|
75
|
+
this.languageCompartment = new Compartment();
|
|
76
|
+
this.readonlyCompartment = new Compartment();
|
|
77
|
+
this.placeholderCompartment = new Compartment();
|
|
85
78
|
}
|
|
86
79
|
|
|
87
80
|
render() {
|
|
@@ -91,37 +84,32 @@ export class GvCode extends InputElement(LitElement) {
|
|
|
91
84
|
large: this.large,
|
|
92
85
|
medium: this.medium || (!this.large && !this.small),
|
|
93
86
|
small: this.small,
|
|
87
|
+
copied: this.hasClipboard && this._copied,
|
|
94
88
|
};
|
|
95
89
|
const inputClasses = {
|
|
96
90
|
content: true,
|
|
97
|
-
|
|
91
|
+
code: !this.hasInputStyle,
|
|
92
|
+
input: this.hasInputStyle,
|
|
98
93
|
};
|
|
99
94
|
|
|
100
95
|
return html`
|
|
101
96
|
<div class="${classMap(classes)}">
|
|
102
97
|
${this.label ? html`<label for="code">${this.label}</label>` : ''}
|
|
103
|
-
<div id="${this._id}" class="${classMap(inputClasses)}">
|
|
104
|
-
${this.clipboard
|
|
105
|
-
? html`<gv-button
|
|
106
|
-
class="btn-clipboard"
|
|
107
|
-
title="${i18n('gv-code.copy')}"
|
|
108
|
-
?outlined="${!this._copied}"
|
|
109
|
-
?primary="${this._copied}"
|
|
110
|
-
small
|
|
111
|
-
icon="${this._clipboardIcon}"
|
|
112
|
-
></gv-button>`
|
|
113
|
-
: ''}
|
|
114
|
-
</div>
|
|
98
|
+
<div id="${this._id}" class="${classMap(inputClasses)}">${this.renderIcon()}</div>
|
|
115
99
|
</div>
|
|
116
100
|
${this.description != null ? html`<div class="description" .innerHTML="${this.description}"></div>` : ''}
|
|
117
101
|
`;
|
|
118
102
|
}
|
|
119
103
|
|
|
104
|
+
bindInputEvents() {
|
|
105
|
+
dispatchCustomEvent(this, 'ready', { currentTarget: this });
|
|
106
|
+
}
|
|
107
|
+
|
|
120
108
|
_onChange() {
|
|
121
109
|
dispatchCustomEvent(this, 'input', this.value);
|
|
122
110
|
}
|
|
123
111
|
|
|
124
|
-
get
|
|
112
|
+
get hasInputStyle() {
|
|
125
113
|
return this.rows === 1;
|
|
126
114
|
}
|
|
127
115
|
|
|
@@ -131,34 +119,32 @@ export class GvCode extends InputElement(LitElement) {
|
|
|
131
119
|
}
|
|
132
120
|
|
|
133
121
|
findBestAutocompleteHandler(completionContext) {
|
|
134
|
-
return this.defaultCompletionHandler;
|
|
122
|
+
return { handler: this.defaultCompletionHandler, match: true };
|
|
135
123
|
}
|
|
136
124
|
|
|
137
125
|
get defaultCompletionHandler() {
|
|
138
126
|
return {
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
return { from: completionContext.pos, options: [] };
|
|
146
|
-
},
|
|
127
|
+
run(completionContext) {
|
|
128
|
+
const language = completionContext.state.languageDataAt('autocomplete', completionContext.pos);
|
|
129
|
+
if (language.length > 0) {
|
|
130
|
+
return language[0](completionContext);
|
|
131
|
+
}
|
|
132
|
+
return { from: completionContext.pos, options: [] };
|
|
147
133
|
},
|
|
148
|
-
match: true,
|
|
149
134
|
};
|
|
150
135
|
}
|
|
151
136
|
|
|
152
137
|
_getExtensions() {
|
|
153
138
|
return [
|
|
154
139
|
basicSetup,
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
EditorView.
|
|
160
|
-
|
|
161
|
-
|
|
140
|
+
GvCode.codemirrorTheme,
|
|
141
|
+
this.languageCompartment.of(json()),
|
|
142
|
+
this.placeholderCompartment.of(placeholder(this.placeholder || '')),
|
|
143
|
+
EditorState.transactionFilter.of((tr) => (this.hasInputStyle && tr.newDoc.lines > 1 ? [] : tr)),
|
|
144
|
+
this.readonlyCompartment.of(EditorView.editable.of(!this.readonly && !this.disabled)),
|
|
145
|
+
EditorView.updateListener.of((viewUpdate) => {
|
|
146
|
+
if (viewUpdate.docChanged) {
|
|
147
|
+
this.value = this._editorView.state.doc.toString();
|
|
162
148
|
}
|
|
163
149
|
}),
|
|
164
150
|
autocompletion({
|
|
@@ -173,9 +159,15 @@ export class GvCode extends InputElement(LitElement) {
|
|
|
173
159
|
return [];
|
|
174
160
|
}
|
|
175
161
|
|
|
162
|
+
getInputElement() {
|
|
163
|
+
return this.shadowRoot.querySelector(`[id=${this._id}]`);
|
|
164
|
+
}
|
|
165
|
+
|
|
176
166
|
firstUpdated() {
|
|
177
167
|
super.firstUpdated();
|
|
178
|
-
|
|
168
|
+
|
|
169
|
+
const parent = this.getInputElement();
|
|
170
|
+
|
|
179
171
|
this._editorState = EditorState.create({
|
|
180
172
|
doc: this.value,
|
|
181
173
|
extensions: this._getExtensions(),
|
|
@@ -185,35 +177,20 @@ export class GvCode extends InputElement(LitElement) {
|
|
|
185
177
|
parent,
|
|
186
178
|
state: this._editorState,
|
|
187
179
|
});
|
|
188
|
-
parent.appendChild(this._editorView.dom);
|
|
189
180
|
|
|
190
|
-
|
|
191
|
-
import('clipboard-copy').then((mod) => {
|
|
192
|
-
const copy = mod.default;
|
|
193
|
-
this.shadowRoot.querySelector('.btn-clipboard').addEventListener('gv-button:click', () => {
|
|
194
|
-
copy(this.value);
|
|
195
|
-
this._copied = true;
|
|
196
|
-
this._clipboardIcon = shapeCopied;
|
|
197
|
-
dispatchCustomEvent(this, 'clipboard-copy');
|
|
198
|
-
setTimeout(() => {
|
|
199
|
-
this._copied = false;
|
|
200
|
-
this._clipboardIcon = shapeClipboard;
|
|
201
|
-
}, 1000);
|
|
202
|
-
});
|
|
203
|
-
});
|
|
204
|
-
}
|
|
205
|
-
dispatchCustomEvent(this, 'ready');
|
|
181
|
+
parent.appendChild(this._editorView.dom);
|
|
206
182
|
}
|
|
207
183
|
|
|
208
184
|
async updated(properties) {
|
|
185
|
+
super.updated(properties);
|
|
209
186
|
if (properties.has('placeholder')) {
|
|
210
187
|
this._reflectPlaceholder();
|
|
211
188
|
}
|
|
212
189
|
if (properties.has('value')) {
|
|
213
190
|
this._reflectValue();
|
|
214
191
|
}
|
|
215
|
-
if (properties.has('readonly')) {
|
|
216
|
-
this.
|
|
192
|
+
if (properties.has('readonly') || properties.has('disabled')) {
|
|
193
|
+
this._reflectReadonlyDisabled();
|
|
217
194
|
}
|
|
218
195
|
if (properties.has('options') && this.options) {
|
|
219
196
|
await this._reflectOptions();
|
|
@@ -222,7 +199,7 @@ export class GvCode extends InputElement(LitElement) {
|
|
|
222
199
|
|
|
223
200
|
_reflectPlaceholder() {
|
|
224
201
|
this._editorView.dispatch({
|
|
225
|
-
effects: placeholderCompartment.reconfigure(placeholder(this.placeholder)),
|
|
202
|
+
effects: this.placeholderCompartment.reconfigure(placeholder(this.placeholder)),
|
|
226
203
|
});
|
|
227
204
|
}
|
|
228
205
|
|
|
@@ -237,38 +214,68 @@ export class GvCode extends InputElement(LitElement) {
|
|
|
237
214
|
this._editorState = transaction.state;
|
|
238
215
|
}
|
|
239
216
|
|
|
240
|
-
|
|
217
|
+
_reflectReadonlyDisabled() {
|
|
241
218
|
this._editorView.dispatch({
|
|
242
|
-
effects: readonlyCompartment.reconfigure(EditorView.editable.of(!this.readonly)),
|
|
219
|
+
effects: this.readonlyCompartment.reconfigure(EditorView.editable.of(!this.readonly && !this.disabled)),
|
|
243
220
|
});
|
|
244
221
|
}
|
|
245
222
|
|
|
246
|
-
async
|
|
247
|
-
if (
|
|
248
|
-
const
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
}
|
|
258
|
-
this._editorView.dispatch({
|
|
259
|
-
effects: languageCompartment.reconfigure(language.support.extension),
|
|
260
|
-
});
|
|
223
|
+
static async findLanguage(mode) {
|
|
224
|
+
if (mode) {
|
|
225
|
+
const modeOnly = mode.split('/').pop();
|
|
226
|
+
if (modeOnly === 'asciidoc') {
|
|
227
|
+
const [{ asciidoc }, { StreamLanguage }] = await Promise.all([import('../lib/asciidoc-lang'), import('@codemirror/stream-parser')]);
|
|
228
|
+
return {
|
|
229
|
+
name: 'asciidoc',
|
|
230
|
+
support: {
|
|
231
|
+
extension: StreamLanguage.define(asciidoc),
|
|
232
|
+
},
|
|
233
|
+
};
|
|
261
234
|
} else {
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
)
|
|
235
|
+
const language = languages.find((languageDescription) => {
|
|
236
|
+
return languageDescription.name.toUpperCase() === modeOnly.toUpperCase() || languageDescription.alias.includes(modeOnly);
|
|
237
|
+
});
|
|
238
|
+
if (language == null) {
|
|
239
|
+
console.warn(
|
|
240
|
+
`Cannot find language ${mode}, please use language supported by CodeMirror 6`,
|
|
241
|
+
languages.map((l) => l.name),
|
|
242
|
+
);
|
|
243
|
+
}
|
|
244
|
+
return language;
|
|
266
245
|
}
|
|
267
246
|
}
|
|
247
|
+
return null;
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
async _reflectOptions() {
|
|
251
|
+
const language = await GvCode.findLanguage(this.options.mode);
|
|
252
|
+
if (language != null) {
|
|
253
|
+
if (language.support == null) {
|
|
254
|
+
await language.load();
|
|
255
|
+
}
|
|
256
|
+
this._editorView.dispatch({
|
|
257
|
+
effects: this.languageCompartment.reconfigure(language.support.extension),
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
static get codemirrorTheme() {
|
|
263
|
+
return EditorView.theme({
|
|
264
|
+
'&.cm-editor.cm-focused': {
|
|
265
|
+
outline: 'none',
|
|
266
|
+
},
|
|
267
|
+
'.cm-gutters': {
|
|
268
|
+
backgroundColor: 'var(--gv-input-icon--bgc, var(--gv-theme-neutral-color, #f5f5f5))',
|
|
269
|
+
color: 'var(--gv-theme-font-color-dark, #262626)',
|
|
270
|
+
borderLeft: '5px solid',
|
|
271
|
+
borderColor: 'var(--gv-input--bdc, var(--gv-theme-neutral-color-dark, #d9d9d9))',
|
|
272
|
+
},
|
|
273
|
+
});
|
|
268
274
|
}
|
|
269
275
|
|
|
270
276
|
static get styles() {
|
|
271
277
|
return [
|
|
278
|
+
...super.styles,
|
|
272
279
|
skeleton,
|
|
273
280
|
empty,
|
|
274
281
|
input,
|
|
@@ -282,16 +289,25 @@ export class GvCode extends InputElement(LitElement) {
|
|
|
282
289
|
|
|
283
290
|
.content {
|
|
284
291
|
position: relative;
|
|
292
|
+
border: var(--gv-input--bdw, 1px) var(--gv-input--bds, solid) var(--gv-input--bdc, var(--gv-theme-neutral-color-dark, #d9d9d9));
|
|
293
|
+
box-sizing: border-box;
|
|
294
|
+
border-radius: 4px;
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
.btn_copy {
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
.box-icon {
|
|
301
|
+
bottom: -1px;
|
|
302
|
+
right: -1px;
|
|
303
|
+
z-index: 1;
|
|
285
304
|
}
|
|
286
305
|
|
|
287
|
-
.
|
|
288
|
-
|
|
289
|
-
right: 0;
|
|
290
|
-
top: 0;
|
|
291
|
-
z-index: 10;
|
|
306
|
+
.code .box-icon {
|
|
307
|
+
border-radius: 3px;
|
|
292
308
|
}
|
|
293
309
|
|
|
294
|
-
/** Override Codemirror
|
|
310
|
+
/** Override Codemirror theme */
|
|
295
311
|
.input .cm-gutters {
|
|
296
312
|
display: none;
|
|
297
313
|
}
|
|
@@ -300,7 +316,8 @@ export class GvCode extends InputElement(LitElement) {
|
|
|
300
316
|
overflow: hidden;
|
|
301
317
|
}
|
|
302
318
|
|
|
303
|
-
.input .cm-activeLine
|
|
319
|
+
.input .cm-activeLine,
|
|
320
|
+
:host([readonly]) .cm-activeLine {
|
|
304
321
|
background-color: transparent;
|
|
305
322
|
}
|
|
306
323
|
|
|
@@ -308,8 +325,8 @@ export class GvCode extends InputElement(LitElement) {
|
|
|
308
325
|
padding: 0;
|
|
309
326
|
}
|
|
310
327
|
|
|
311
|
-
|
|
312
|
-
|
|
328
|
+
:host([invalid]) .cm-gutters {
|
|
329
|
+
border-color: var(--gv-theme-color-error, #da1a1b);
|
|
313
330
|
}
|
|
314
331
|
`,
|
|
315
332
|
];
|
|
@@ -51,7 +51,7 @@ export class GvExpressionLanguage extends GvCode {
|
|
|
51
51
|
|
|
52
52
|
firstUpdated() {
|
|
53
53
|
super.firstUpdated();
|
|
54
|
-
dispatchCustomEvent(this, 'ready');
|
|
54
|
+
dispatchCustomEvent(this, 'ready', { currentTarget: this });
|
|
55
55
|
}
|
|
56
56
|
|
|
57
57
|
getExtensions() {
|
|
@@ -78,7 +78,7 @@ export class GvExpressionLanguage extends GvCode {
|
|
|
78
78
|
}
|
|
79
79
|
|
|
80
80
|
buildMethods(type) {
|
|
81
|
-
const modelType = this.
|
|
81
|
+
const modelType = this.getModelType(type);
|
|
82
82
|
return modelType.methods.map(({ name, params = [], returnType }) => {
|
|
83
83
|
const command = `${name}()`;
|
|
84
84
|
const displayParams = params.map((p) => `${p.type} ${p.name}`);
|
|
@@ -134,7 +134,6 @@ export class GvExpressionLanguage extends GvCode {
|
|
|
134
134
|
if (type) {
|
|
135
135
|
const lowerType = type.toLowerCase();
|
|
136
136
|
if (lowerType === 'string') {
|
|
137
|
-
// class, constant, enum, function, interface, keyword, method, namespace, property, text, type, and variable.
|
|
138
137
|
return 'text';
|
|
139
138
|
} else if (lowerType === 'httpheaders' || lowerType === 'multivaluemap') {
|
|
140
139
|
return 'type';
|
|
@@ -159,7 +158,6 @@ export class GvExpressionLanguage extends GvCode {
|
|
|
159
158
|
.filter((command) => !command.startsWith('_') && command.startsWith(prefix))
|
|
160
159
|
.map((command) => {
|
|
161
160
|
return {
|
|
162
|
-
// class, constant, enum, function, interface, keyword, method, namespace, property, text, type, and variable.
|
|
163
161
|
type: 'variable',
|
|
164
162
|
command,
|
|
165
163
|
apply: command,
|
|
@@ -176,11 +174,10 @@ export class GvExpressionLanguage extends GvCode {
|
|
|
176
174
|
const tokens = match.text.split('.');
|
|
177
175
|
const key = tokens[0].replaceAll('{#', '');
|
|
178
176
|
const prefix = tokens[1];
|
|
179
|
-
|
|
177
|
+
let candidate = this.grammar[key][prefix];
|
|
180
178
|
let options = [];
|
|
181
179
|
let from = completionContext.pos;
|
|
182
180
|
if (candidate) {
|
|
183
|
-
// const modelType = this._getModelType(candidate._type);
|
|
184
181
|
if (this.isMap(candidate._type)) {
|
|
185
182
|
options = this.getEnum(candidate._type).map((value) => {
|
|
186
183
|
const type = this.convertType(candidate._type);
|
|
@@ -195,7 +192,7 @@ export class GvExpressionLanguage extends GvCode {
|
|
|
195
192
|
}
|
|
196
193
|
} else {
|
|
197
194
|
from -= prefix.length;
|
|
198
|
-
|
|
195
|
+
candidate = this.grammar[key];
|
|
199
196
|
if (candidate._type) {
|
|
200
197
|
options = this.buildMethods(candidate._type);
|
|
201
198
|
} else {
|
|
@@ -224,16 +221,16 @@ export class GvExpressionLanguage extends GvCode {
|
|
|
224
221
|
let options = [];
|
|
225
222
|
let from = completionContext.pos;
|
|
226
223
|
if (candidate) {
|
|
227
|
-
if (this.
|
|
228
|
-
options = this.
|
|
224
|
+
if (this.isMap(candidate._type)) {
|
|
225
|
+
options = this.getEnum(candidate._type)
|
|
229
226
|
.filter((command) => !command.startsWith('_') && command.startsWith(prefix))
|
|
230
227
|
.map((label) => {
|
|
231
|
-
const type = this.
|
|
228
|
+
const type = this.convertType(candidate._type);
|
|
232
229
|
return {
|
|
233
230
|
type,
|
|
234
231
|
command: `['${label}'][0]`,
|
|
235
232
|
apply(view, completion, _from, to) {
|
|
236
|
-
|
|
233
|
+
from = _from - prefix.length - 1;
|
|
237
234
|
view.dispatch({
|
|
238
235
|
changes: { from, to, insert: completion.command },
|
|
239
236
|
selection: { anchor: from + completion.command.length },
|
|
@@ -246,14 +243,14 @@ export class GvExpressionLanguage extends GvCode {
|
|
|
246
243
|
});
|
|
247
244
|
} else {
|
|
248
245
|
if (candidate._type) {
|
|
249
|
-
options = this.
|
|
246
|
+
options = this.buildMethods(candidate._type);
|
|
250
247
|
} else {
|
|
251
248
|
from -= prefix.length;
|
|
252
249
|
options = Object.keys(candidate)
|
|
253
250
|
.filter((command) => command.startsWith(prefix))
|
|
254
251
|
.map((command) => {
|
|
255
252
|
return {
|
|
256
|
-
type: this.
|
|
253
|
+
type: this.convertType(candidate[command]._type),
|
|
257
254
|
command,
|
|
258
255
|
apply: command,
|
|
259
256
|
label: command,
|
package/src/styles/input.js
CHANGED
|
@@ -122,6 +122,7 @@ export const input = css`
|
|
|
122
122
|
::slotted(.input),
|
|
123
123
|
.input {
|
|
124
124
|
border: var(--gv-input--bdw, 1px) var(--gv-input--bds, solid) var(--gv-input--bdc, var(--gv-theme-neutral-color-dark, #d9d9d9));
|
|
125
|
+
transition: border 10ms ease-in-out;
|
|
125
126
|
box-sizing: border-box;
|
|
126
127
|
border-radius: 4px;
|
|
127
128
|
font-style: normal;
|
|
@@ -232,6 +233,7 @@ export const input = css`
|
|
|
232
233
|
}
|
|
233
234
|
|
|
234
235
|
:host([disabled]) input,
|
|
236
|
+
:host([disabled]) .input,
|
|
235
237
|
:host([disabled]) ::slotted(input) {
|
|
236
238
|
cursor: default;
|
|
237
239
|
opacity: 0.5;
|