@gravitee/ui-components 3.24.3-migrate-codemirror-f56ff96 → 3.24.4-migrate-codemirror-0dec695
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 +1 -6
- package/src/atoms/gv-button.js +0 -8
- package/src/atoms/gv-input.js +24 -22
- package/src/mixins/input-element.js +7 -3
- package/src/molecules/gv-code.js +132 -311
- package/src/molecules/gv-expression-language.js +241 -1
- package/src/policy-studio/gv-policy-studio.js +1 -5
- package/src/styles/input.js +1 -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-0dec695",
|
|
4
4
|
"description": "Gravitee.io UI Components library, based on Web Components",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -99,7 +99,6 @@
|
|
|
99
99
|
"babel-plugin-template-html-minifier": "4.1.0",
|
|
100
100
|
"bundle-phobia-cli": "0.14.13",
|
|
101
101
|
"chromatic": "6.1.0",
|
|
102
|
-
"codemirror-asciidoc": "1.0.4",
|
|
103
102
|
"danger": "10.7.1",
|
|
104
103
|
"del": "6.0.0",
|
|
105
104
|
"eslint": "8.4.0",
|
|
@@ -146,7 +145,6 @@
|
|
|
146
145
|
"@highcharts/map-collection": "^1.0.0",
|
|
147
146
|
"asciidoctor": "^2.2.4",
|
|
148
147
|
"asciidoctor-highlight.js": "^0.3.0 || ^0.4.0",
|
|
149
|
-
"codemirror-asciidoc": "^1.0.4",
|
|
150
148
|
"highcharts": "^8.0.0 || ^9.0.0",
|
|
151
149
|
"highlight.js": "^10.7.0 || ^11.1.0"
|
|
152
150
|
},
|
|
@@ -163,9 +161,6 @@
|
|
|
163
161
|
"asciidoctor-highlight.js": {
|
|
164
162
|
"optional": true
|
|
165
163
|
},
|
|
166
|
-
"codemirror-asciidoc": {
|
|
167
|
-
"optional": true
|
|
168
|
-
},
|
|
169
164
|
"highcharts": {
|
|
170
165
|
"optional": true
|
|
171
166
|
},
|
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
|
@@ -272,19 +272,7 @@ export class GvInput extends InputElement(LitElement) {
|
|
|
272
272
|
firstUpdated(changedProperties) {
|
|
273
273
|
super.firstUpdated(changedProperties);
|
|
274
274
|
|
|
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
|
-
}
|
|
275
|
+
this.catchSlot();
|
|
288
276
|
|
|
289
277
|
if (this.clipboard) {
|
|
290
278
|
import('clipboard-copy').then(
|
|
@@ -304,13 +292,6 @@ export class GvInput extends InputElement(LitElement) {
|
|
|
304
292
|
|
|
305
293
|
setTimeout(() => {
|
|
306
294
|
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
295
|
clipboardPopover.addEventListener('click', (e) => {
|
|
315
296
|
e.preventDefault();
|
|
316
297
|
e.stopPropagation();
|
|
@@ -325,11 +306,32 @@ export class GvInput extends InputElement(LitElement) {
|
|
|
325
306
|
}
|
|
326
307
|
|
|
327
308
|
this.getInputElement().id = this._id;
|
|
309
|
+
|
|
310
|
+
this.bindInputEvents();
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
bindInputEvents() {
|
|
328
314
|
this.getInputElement().addEventListener('input', this._onInput.bind(this));
|
|
329
315
|
this.getInputElement().addEventListener('keyup', this._onKeyUp.bind(this));
|
|
330
316
|
this.getInputElement().addEventListener('keypress', this._onKeyPress.bind(this));
|
|
331
317
|
}
|
|
332
318
|
|
|
319
|
+
catchSlot() {
|
|
320
|
+
const defaultInputElement = this.getInputElement();
|
|
321
|
+
for (const node of this.childNodes) {
|
|
322
|
+
if (node.nodeType === 1) {
|
|
323
|
+
const child = node.nodeName.toLowerCase() === 'input' ? node : node.querySelector('input');
|
|
324
|
+
if (child) {
|
|
325
|
+
this._input = child;
|
|
326
|
+
break;
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
if (this._input) {
|
|
331
|
+
defaultInputElement.remove();
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
333
335
|
updateState(value) {
|
|
334
336
|
super.updateState(value);
|
|
335
337
|
if (this.valid === true && !this.readonly) {
|
|
@@ -481,7 +483,7 @@ export class GvInput extends InputElement(LitElement) {
|
|
|
481
483
|
return !this.loading;
|
|
482
484
|
}
|
|
483
485
|
|
|
484
|
-
|
|
486
|
+
renderIcon() {
|
|
485
487
|
let shape = null;
|
|
486
488
|
if ((!this.isPassword && this.icon) || this.iconLeft) {
|
|
487
489
|
shape = (!this.isPassword && this.icon) || this.iconLeft;
|
|
@@ -545,7 +547,7 @@ export class GvInput extends InputElement(LitElement) {
|
|
|
545
547
|
${this.renderLabel()}
|
|
546
548
|
<input />
|
|
547
549
|
<slot></slot>
|
|
548
|
-
${this._renderClearIcon()} ${this.
|
|
550
|
+
${this._renderClearIcon()} ${this.renderIcon()} ${this._renderPasswordIcon()}
|
|
549
551
|
</div>
|
|
550
552
|
${this.description != null ? html`<div class="description" .innerHTML="${this.description}"></div>` : ''}
|
|
551
553
|
`;
|
|
@@ -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,22 +13,20 @@
|
|
|
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
|
-
import { EditorState, Compartment
|
|
25
|
-
import { autocompletion
|
|
19
|
+
import { EditorState, Compartment } from '@codemirror/state';
|
|
20
|
+
import { autocompletion } from '@codemirror/autocomplete';
|
|
26
21
|
import { json } from '@codemirror/lang-json';
|
|
27
22
|
import { languages } from '@codemirror/language-data';
|
|
28
|
-
import { placeholder
|
|
29
|
-
|
|
30
|
-
import {
|
|
31
|
-
import {
|
|
23
|
+
import { placeholder } from '@codemirror/view';
|
|
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';
|
|
32
30
|
import { skeleton } from '../styles/skeleton';
|
|
33
31
|
import { empty } from '../styles/empty';
|
|
34
32
|
import { input } from '../styles/input';
|
|
@@ -37,8 +35,20 @@ const languageCompartment = new Compartment();
|
|
|
37
35
|
const readonlyCompartment = new Compartment();
|
|
38
36
|
const placeholderCompartment = new Compartment();
|
|
39
37
|
|
|
38
|
+
const overrideTheme = EditorView.theme({
|
|
39
|
+
'&.cm-editor.cm-focused': {
|
|
40
|
+
outline: 'none',
|
|
41
|
+
},
|
|
42
|
+
'.cm-gutters': {
|
|
43
|
+
backgroundColor: 'var(--gv-input-icon--bgc, var(--gv-theme-neutral-color, #f5f5f5))',
|
|
44
|
+
color: 'var(--gv-theme-font-color-dark, #262626)',
|
|
45
|
+
borderLeft: '5px solid',
|
|
46
|
+
borderColor: 'var(--gv-input--bdc, var(--gv-theme-neutral-color-dark, #d9d9d9))',
|
|
47
|
+
},
|
|
48
|
+
});
|
|
49
|
+
|
|
40
50
|
/**
|
|
41
|
-
* Code
|
|
51
|
+
* Code component
|
|
42
52
|
*
|
|
43
53
|
* ## Details
|
|
44
54
|
* * has @theme facet
|
|
@@ -49,8 +59,7 @@ const placeholderCompartment = new Compartment();
|
|
|
49
59
|
*
|
|
50
60
|
* @attr {String} label - code language
|
|
51
61
|
* @attr {String} value - code content to be highlighted
|
|
52
|
-
* @attr {options} Object - options based on codemirror
|
|
53
|
-
* @attr {Object} grammar - The grammar for Expression Language support
|
|
62
|
+
* @attr {options} Object - options based on codemirror
|
|
54
63
|
* @attr {String} placeholder - an example value to display in the input when empty
|
|
55
64
|
* @attr {Number} rows - number of rows of the text element
|
|
56
65
|
* @attr {Boolean} large - for a large input (only if the field has one row)
|
|
@@ -61,17 +70,11 @@ const placeholderCompartment = new Compartment();
|
|
|
61
70
|
* @attr {Boolean} [autofocus=false] - true to put the focus on the input
|
|
62
71
|
* @attr {Boolean} [readonly=false] - true if field is readonly mode
|
|
63
72
|
*/
|
|
64
|
-
export class GvCode extends
|
|
73
|
+
export class GvCode extends GvInput {
|
|
65
74
|
static get properties() {
|
|
66
75
|
return {
|
|
67
76
|
...super.properties,
|
|
68
77
|
options: { type: Object },
|
|
69
|
-
large: { type: Boolean },
|
|
70
|
-
medium: { type: Boolean },
|
|
71
|
-
small: { type: Boolean },
|
|
72
|
-
clipboard: { type: Boolean },
|
|
73
|
-
_clipboardIcon: { type: String },
|
|
74
|
-
_codeMirror: { type: Object },
|
|
75
78
|
rows: { type: Number },
|
|
76
79
|
_error: { type: String, attribute: false },
|
|
77
80
|
};
|
|
@@ -97,352 +100,165 @@ export class GvCode extends InputElement(LitElement) {
|
|
|
97
100
|
};
|
|
98
101
|
const inputClasses = {
|
|
99
102
|
content: true,
|
|
100
|
-
|
|
103
|
+
code: !this.hasInputStyle,
|
|
104
|
+
input: this.hasInputStyle,
|
|
101
105
|
};
|
|
102
106
|
|
|
103
107
|
return html`
|
|
104
108
|
<div class="${classMap(classes)}">
|
|
105
109
|
${this.label ? html`<label for="code">${this.label}</label>` : ''}
|
|
106
|
-
<div id="${this._id}" class="${classMap(inputClasses)}">
|
|
107
|
-
${this.clipboard
|
|
108
|
-
? html`<gv-button
|
|
109
|
-
title="${i18n('gv-code.copy')}"
|
|
110
|
-
?outlined="${!this._copied}"
|
|
111
|
-
?primary="${this._copied}"
|
|
112
|
-
small
|
|
113
|
-
icon="${this._clipboardIcon}"
|
|
114
|
-
></gv-button>`
|
|
115
|
-
: ''}
|
|
116
|
-
</div>
|
|
110
|
+
<div id="${this._id}" class="${classMap(inputClasses)}">${this.renderIcon()}</div>
|
|
117
111
|
</div>
|
|
118
112
|
${this.description != null ? html`<div class="description" .innerHTML="${this.description}"></div>` : ''}
|
|
119
113
|
`;
|
|
120
114
|
}
|
|
121
115
|
|
|
116
|
+
bindInputEvents() {
|
|
117
|
+
dispatchCustomEvent(this, 'ready', { currentTarget: this });
|
|
118
|
+
}
|
|
119
|
+
|
|
122
120
|
_onChange() {
|
|
123
121
|
dispatchCustomEvent(this, 'input', this.value);
|
|
124
122
|
}
|
|
125
123
|
|
|
126
|
-
get
|
|
124
|
+
get hasInputStyle() {
|
|
127
125
|
return this.rows === 1;
|
|
128
126
|
}
|
|
129
127
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
return null;
|
|
128
|
+
_autocomplete(completionContext) {
|
|
129
|
+
const { handler, match } = this.findBestAutocompleteHandler(completionContext);
|
|
130
|
+
return handler.run.call(this, completionContext, match);
|
|
135
131
|
}
|
|
136
132
|
|
|
137
|
-
|
|
138
|
-
return
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
_getEnum(typeId) {
|
|
142
|
-
if (this.grammar != null) {
|
|
143
|
-
return get(this.grammar, `_enums.${typeId}`);
|
|
144
|
-
}
|
|
145
|
-
return [''];
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
_convertType(type) {
|
|
149
|
-
if (type) {
|
|
150
|
-
const lowerType = type.toLowerCase();
|
|
151
|
-
if (lowerType === 'string') {
|
|
152
|
-
// class, constant, enum, function, interface, keyword, method, namespace, property, text, type, and variable.
|
|
153
|
-
return 'text';
|
|
154
|
-
} else if (lowerType === 'httpheaders' || lowerType === 'multivaluemap') {
|
|
155
|
-
return 'type';
|
|
156
|
-
} else if (lowerType === 'int' || lowerType === 'long') {
|
|
157
|
-
return 'variable';
|
|
158
|
-
} else if (lowerType.includes('[]')) {
|
|
159
|
-
return 'enum';
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
return 'variable';
|
|
133
|
+
findBestAutocompleteHandler(completionContext) {
|
|
134
|
+
return { handler: this.defaultCompletionHandler, match: true };
|
|
163
135
|
}
|
|
164
136
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
const command = `${name}()`;
|
|
174
|
-
const displayParams = params.map((p) => `${p.type} ${p.name}`);
|
|
175
|
-
const label = `${name}(${displayParams.join(', ')})`;
|
|
176
|
-
const detail = `return ${returnType}`;
|
|
177
|
-
return {
|
|
178
|
-
type: 'method',
|
|
179
|
-
command,
|
|
180
|
-
apply: (view, completion, from, to) => {
|
|
181
|
-
const anchor = from + name.length + 1;
|
|
182
|
-
view.dispatch({
|
|
183
|
-
changes: { from, to, insert: completion.command },
|
|
184
|
-
selection: { anchor },
|
|
185
|
-
userEvent: 'input.complete',
|
|
186
|
-
annotations: pickedCompletion.of(view),
|
|
187
|
-
});
|
|
188
|
-
},
|
|
189
|
-
label,
|
|
190
|
-
detail,
|
|
191
|
-
};
|
|
192
|
-
});
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
_findAutocompleteHandler(ctx) {
|
|
196
|
-
return this._completionHandlers
|
|
197
|
-
.filter((handler) => (this.grammar != null && handler.supportEL === true) || handler.supportEL !== true)
|
|
198
|
-
.map((handler) => {
|
|
199
|
-
const match = handler.expr ? ctx.matchBefore(handler.expr) : true;
|
|
200
|
-
return { handler, match };
|
|
201
|
-
})
|
|
202
|
-
.find(({ match, expr }) => match);
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
get _completionHandlers() {
|
|
206
|
-
return [
|
|
207
|
-
{
|
|
208
|
-
expr: /{#[a-z]*/,
|
|
209
|
-
supportEL: true,
|
|
210
|
-
run(ctx, match) {
|
|
211
|
-
const prefix = match.text.replaceAll('{#', '');
|
|
212
|
-
const from = ctx.pos - prefix.length;
|
|
213
|
-
const options = Object.keys(this.grammar)
|
|
214
|
-
.filter((command) => !command.startsWith('_') && command.startsWith(prefix))
|
|
215
|
-
.map((command) => {
|
|
216
|
-
return {
|
|
217
|
-
// class, constant, enum, function, interface, keyword, method, namespace, property, text, type, and variable.
|
|
218
|
-
type: 'variable',
|
|
219
|
-
command,
|
|
220
|
-
apply: command,
|
|
221
|
-
label: command,
|
|
222
|
-
};
|
|
223
|
-
});
|
|
224
|
-
return { from, options };
|
|
225
|
-
},
|
|
226
|
-
},
|
|
227
|
-
{
|
|
228
|
-
expr: /{#[a-z]*.[a-zA-Z]*/,
|
|
229
|
-
supportEL: true,
|
|
230
|
-
run(ctx, match) {
|
|
231
|
-
const tokens = match.text.split('.');
|
|
232
|
-
const key = tokens[0].replaceAll('{#', '');
|
|
233
|
-
const prefix = tokens[1];
|
|
234
|
-
const candidate = this.grammar[key][prefix];
|
|
235
|
-
let options = [];
|
|
236
|
-
let from = ctx.pos;
|
|
237
|
-
if (candidate) {
|
|
238
|
-
// const modelType = this._getModelType(candidate._type);
|
|
239
|
-
if (this._isMap(candidate._type)) {
|
|
240
|
-
options = this._getEnum(candidate._type).map((value) => {
|
|
241
|
-
const type = this._convertType(candidate._type);
|
|
242
|
-
const command = `['${value}'][0]`;
|
|
243
|
-
return {
|
|
244
|
-
type,
|
|
245
|
-
command,
|
|
246
|
-
apply: command,
|
|
247
|
-
label: value,
|
|
248
|
-
};
|
|
249
|
-
});
|
|
250
|
-
}
|
|
251
|
-
} else {
|
|
252
|
-
from -= prefix.length;
|
|
253
|
-
const candidate = this.grammar[key];
|
|
254
|
-
if (candidate._type) {
|
|
255
|
-
options = this._buildMethods(candidate._type);
|
|
256
|
-
} else {
|
|
257
|
-
options = Object.keys(candidate)
|
|
258
|
-
.filter((command) => !command.startsWith('_') && command.startsWith(prefix))
|
|
259
|
-
.map((command) => ({
|
|
260
|
-
type: this._convertType(candidate[command]._type),
|
|
261
|
-
command,
|
|
262
|
-
apply: command,
|
|
263
|
-
label: command,
|
|
264
|
-
}));
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
return { from, options };
|
|
268
|
-
},
|
|
269
|
-
},
|
|
270
|
-
{
|
|
271
|
-
expr: /{#[a-z]*.[a-zA-Z]*.[a-zA-Z]*/,
|
|
272
|
-
supportEL: true,
|
|
273
|
-
run(ctx, match) {
|
|
274
|
-
const tokens = match.text.split('.');
|
|
275
|
-
const key = tokens[0].replaceAll('{#', '');
|
|
276
|
-
const word = tokens[1];
|
|
277
|
-
const prefix = tokens[2];
|
|
278
|
-
const candidate = this.grammar[key][word];
|
|
279
|
-
let options = [];
|
|
280
|
-
let from = ctx.pos;
|
|
281
|
-
if (candidate) {
|
|
282
|
-
if (this._isMap(candidate._type)) {
|
|
283
|
-
options = this._getEnum(candidate._type)
|
|
284
|
-
.filter((command) => !command.startsWith('_') && command.startsWith(prefix))
|
|
285
|
-
.map((label) => {
|
|
286
|
-
const type = this._convertType(candidate._type);
|
|
287
|
-
return {
|
|
288
|
-
type,
|
|
289
|
-
command: `['${label}'][0]`,
|
|
290
|
-
apply(view, completion, _from, to) {
|
|
291
|
-
const from = _from - prefix.length - 1;
|
|
292
|
-
view.dispatch({
|
|
293
|
-
changes: { from, to, insert: completion.command },
|
|
294
|
-
selection: { anchor: from + completion.command.length },
|
|
295
|
-
userEvent: 'input.complete',
|
|
296
|
-
annotations: pickedCompletion.of(view),
|
|
297
|
-
});
|
|
298
|
-
},
|
|
299
|
-
label,
|
|
300
|
-
};
|
|
301
|
-
});
|
|
302
|
-
} else {
|
|
303
|
-
if (candidate._type) {
|
|
304
|
-
options = this._buildMethods(candidate._type);
|
|
305
|
-
} else {
|
|
306
|
-
from -= prefix.length;
|
|
307
|
-
options = Object.keys(candidate)
|
|
308
|
-
.filter((command) => command.startsWith(prefix))
|
|
309
|
-
.map((command) => {
|
|
310
|
-
return {
|
|
311
|
-
type: this._convertType(candidate[command]._type),
|
|
312
|
-
command,
|
|
313
|
-
apply: command,
|
|
314
|
-
label: command,
|
|
315
|
-
};
|
|
316
|
-
});
|
|
317
|
-
}
|
|
318
|
-
}
|
|
319
|
-
}
|
|
320
|
-
return { from, options };
|
|
321
|
-
},
|
|
322
|
-
},
|
|
323
|
-
{
|
|
324
|
-
run(ctx) {
|
|
325
|
-
const autocompleteLanguage = ctx.state.languageDataAt('autocomplete', ctx.pos);
|
|
326
|
-
if (autocompleteLanguage.length > 0) {
|
|
327
|
-
return autocompleteLanguage[0](ctx);
|
|
328
|
-
}
|
|
329
|
-
return { from: ctx.pos, options: [] };
|
|
330
|
-
},
|
|
137
|
+
get defaultCompletionHandler() {
|
|
138
|
+
return {
|
|
139
|
+
run(completionContext) {
|
|
140
|
+
const language = completionContext.state.languageDataAt('autocomplete', completionContext.pos);
|
|
141
|
+
if (language.length > 0) {
|
|
142
|
+
return language[0](completionContext);
|
|
143
|
+
}
|
|
144
|
+
return { from: completionContext.pos, options: [] };
|
|
331
145
|
},
|
|
332
|
-
|
|
146
|
+
};
|
|
333
147
|
}
|
|
334
148
|
|
|
335
|
-
|
|
149
|
+
_getExtensions() {
|
|
336
150
|
return [
|
|
337
151
|
basicSetup,
|
|
152
|
+
overrideTheme,
|
|
338
153
|
languageCompartment.of(json()),
|
|
339
154
|
placeholderCompartment.of(placeholder(this.placeholder || '')),
|
|
340
|
-
EditorState.transactionFilter.of((tr) => (this.
|
|
341
|
-
readonlyCompartment.of(EditorView.editable.of(!this.readonly)),
|
|
342
|
-
EditorView.updateListener.of((
|
|
343
|
-
if (
|
|
344
|
-
this.value =
|
|
155
|
+
EditorState.transactionFilter.of((tr) => (this.hasInputStyle && tr.newDoc.lines > 1 ? [] : tr)),
|
|
156
|
+
readonlyCompartment.of(EditorView.editable.of(!this.readonly && !this.disabled)),
|
|
157
|
+
EditorView.updateListener.of((viewUpdate) => {
|
|
158
|
+
if (viewUpdate.docChanged) {
|
|
159
|
+
this.value = this._editorView.state.doc.toString();
|
|
345
160
|
}
|
|
346
161
|
}),
|
|
347
162
|
autocompletion({
|
|
348
163
|
activateOnTyping: true,
|
|
349
164
|
override: [this._autocomplete.bind(this)],
|
|
350
165
|
}),
|
|
351
|
-
|
|
166
|
+
...this.getExtensions(),
|
|
352
167
|
];
|
|
353
168
|
}
|
|
354
169
|
|
|
355
|
-
|
|
356
|
-
return
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
view.dispatch(
|
|
362
|
-
view.state.changeByRange((range) => ({
|
|
363
|
-
changes: [{ from: range.from, to: range.to, insert: '{#}' }],
|
|
364
|
-
range: EditorSelection.range(range.from + 2, range.to + 2),
|
|
365
|
-
})),
|
|
366
|
-
);
|
|
367
|
-
startCompletion(view);
|
|
368
|
-
return true;
|
|
369
|
-
},
|
|
370
|
-
},
|
|
371
|
-
]);
|
|
170
|
+
getExtensions() {
|
|
171
|
+
return [];
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
getInputElement() {
|
|
175
|
+
return this.shadowRoot.querySelector(`[id=${this._id}]`);
|
|
372
176
|
}
|
|
373
177
|
|
|
374
178
|
firstUpdated() {
|
|
375
179
|
super.firstUpdated();
|
|
376
|
-
|
|
180
|
+
|
|
181
|
+
const parent = this.getInputElement();
|
|
182
|
+
|
|
377
183
|
this._editorState = EditorState.create({
|
|
378
184
|
doc: this.value,
|
|
379
|
-
extensions: this.
|
|
185
|
+
extensions: this._getExtensions(),
|
|
380
186
|
});
|
|
381
187
|
this._editorView = new EditorView({
|
|
382
188
|
root: this.shadowRoot,
|
|
383
189
|
parent,
|
|
384
190
|
state: this._editorState,
|
|
385
191
|
});
|
|
386
|
-
parent.appendChild(this._editorView.dom);
|
|
387
192
|
|
|
388
|
-
|
|
389
|
-
import('clipboard-copy').then((mod) => {
|
|
390
|
-
const copy = mod.default;
|
|
391
|
-
this.shadowRoot.querySelector('gv-button').addEventListener('gv-button:click', () => {
|
|
392
|
-
copy(this.value);
|
|
393
|
-
this._copied = true;
|
|
394
|
-
this._clipboardIcon = shapeCopied;
|
|
395
|
-
dispatchCustomEvent(this, 'clipboard-copy');
|
|
396
|
-
setTimeout(() => {
|
|
397
|
-
this._copied = false;
|
|
398
|
-
this._clipboardIcon = shapeClipboard;
|
|
399
|
-
}, 1000);
|
|
400
|
-
});
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
dispatchCustomEvent(this, 'ready');
|
|
193
|
+
parent.appendChild(this._editorView.dom);
|
|
404
194
|
}
|
|
405
195
|
|
|
406
196
|
async updated(properties) {
|
|
197
|
+
super.updated(properties);
|
|
407
198
|
if (properties.has('placeholder')) {
|
|
408
|
-
this.
|
|
409
|
-
effects: placeholderCompartment.reconfigure(placeholder(this.placeholder)),
|
|
410
|
-
});
|
|
199
|
+
this._reflectPlaceholder();
|
|
411
200
|
}
|
|
412
201
|
if (properties.has('value')) {
|
|
413
|
-
|
|
414
|
-
this._editorState = transaction.state;
|
|
202
|
+
this._reflectValue();
|
|
415
203
|
}
|
|
416
|
-
if (properties.has('readonly')) {
|
|
417
|
-
this.
|
|
418
|
-
effects: readonlyCompartment.reconfigure(EditorView.editable.of(!this.readonly)),
|
|
419
|
-
});
|
|
204
|
+
if (properties.has('readonly') || properties.has('disabled')) {
|
|
205
|
+
this._reflectReadonlyDisabled();
|
|
420
206
|
}
|
|
421
|
-
|
|
422
207
|
if (properties.has('options') && this.options) {
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
208
|
+
await this._reflectOptions();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
_reflectPlaceholder() {
|
|
213
|
+
this._editorView.dispatch({
|
|
214
|
+
effects: placeholderCompartment.reconfigure(placeholder(this.placeholder)),
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
_reflectValue() {
|
|
219
|
+
const transaction = this._editorState.update({
|
|
220
|
+
changes: {
|
|
221
|
+
from: 0,
|
|
222
|
+
to: this._editorState.doc.length,
|
|
223
|
+
insert: this.value,
|
|
224
|
+
},
|
|
225
|
+
});
|
|
226
|
+
this._editorState = transaction.state;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
_reflectReadonlyDisabled() {
|
|
230
|
+
this._editorView.dispatch({
|
|
231
|
+
effects: readonlyCompartment.reconfigure(EditorView.editable.of(!this.readonly && !this.disabled)),
|
|
232
|
+
});
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
async _reflectOptions() {
|
|
236
|
+
if (this.options.mode) {
|
|
237
|
+
const language = languages.find((languageDescription) => {
|
|
238
|
+
return (
|
|
239
|
+
languageDescription.name.toUpperCase() === this.options.mode.toUpperCase() ||
|
|
240
|
+
languageDescription.alias.includes(this.options.mode)
|
|
241
|
+
);
|
|
242
|
+
});
|
|
243
|
+
if (language != null) {
|
|
244
|
+
if (language.support == null) {
|
|
245
|
+
await language.load();
|
|
439
246
|
}
|
|
247
|
+
this._editorView.dispatch({
|
|
248
|
+
effects: languageCompartment.reconfigure(language.support.extension),
|
|
249
|
+
});
|
|
250
|
+
} else {
|
|
251
|
+
console.warn(
|
|
252
|
+
`Cannot find language ${this.options.mode}, please use language supported by CodeMirror 6`,
|
|
253
|
+
languages.map((l) => l.name),
|
|
254
|
+
);
|
|
440
255
|
}
|
|
441
256
|
}
|
|
442
257
|
}
|
|
443
258
|
|
|
444
259
|
static get styles() {
|
|
445
260
|
return [
|
|
261
|
+
...super.styles,
|
|
446
262
|
skeleton,
|
|
447
263
|
empty,
|
|
448
264
|
input,
|
|
@@ -458,6 +274,18 @@ export class GvCode extends InputElement(LitElement) {
|
|
|
458
274
|
position: relative;
|
|
459
275
|
}
|
|
460
276
|
|
|
277
|
+
.box-icon {
|
|
278
|
+
bottom: -1px;
|
|
279
|
+
right: -1px;
|
|
280
|
+
z-index: 1;
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
.code .box-icon {
|
|
284
|
+
border-radius: 0;
|
|
285
|
+
top: 0;
|
|
286
|
+
}
|
|
287
|
+
|
|
288
|
+
/** Override Codemirror style */
|
|
461
289
|
.input .cm-gutters {
|
|
462
290
|
display: none;
|
|
463
291
|
}
|
|
@@ -474,15 +302,8 @@ export class GvCode extends InputElement(LitElement) {
|
|
|
474
302
|
padding: 0;
|
|
475
303
|
}
|
|
476
304
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
}
|
|
480
|
-
|
|
481
|
-
gv-button {
|
|
482
|
-
position: absolute;
|
|
483
|
-
right: 0;
|
|
484
|
-
top: 0;
|
|
485
|
-
z-index: 10;
|
|
305
|
+
:host([invalid]) .cm-gutters {
|
|
306
|
+
border-color: var(--gv-theme-color-error, #da1a1b);
|
|
486
307
|
}
|
|
487
308
|
`,
|
|
488
309
|
];
|
|
@@ -15,15 +15,255 @@
|
|
|
15
15
|
*/
|
|
16
16
|
import { GvCode } from '../molecules/gv-code';
|
|
17
17
|
import { dispatchCustomEvent } from '../lib/events';
|
|
18
|
+
import { pickedCompletion, startCompletion } from '@codemirror/autocomplete';
|
|
19
|
+
import { keymap } from '@codemirror/view';
|
|
20
|
+
import { EditorSelection, Prec } from '@codemirror/state';
|
|
21
|
+
import { get } from 'object-path';
|
|
18
22
|
|
|
19
23
|
/**
|
|
20
24
|
* Expression Language component
|
|
21
25
|
*
|
|
26
|
+
* @fires gv-expression-language:input - input events with the `value` on `detail`
|
|
27
|
+
* @fires gv-expression-language:ready - event dispatch when component is ready
|
|
28
|
+
* @fires gv-expression-language:clipboard-copy - event dispatch when component the `value` has been copied to clipboard
|
|
29
|
+
*
|
|
30
|
+
* @attr {String} label - code language
|
|
31
|
+
* @attr {String} value - code content to be highlighted
|
|
32
|
+
* @attr {options} Object - options based on codemirror
|
|
33
|
+
* @attr {String} placeholder - an example value to display in the input when empty
|
|
34
|
+
* @attr {Number} rows - number of rows of the text element
|
|
35
|
+
* @attr {Boolean} large - for a large input (only if the field has one row)
|
|
36
|
+
* @attr {Boolean} medium - for a medium input (only if the field has one row) (Default)
|
|
37
|
+
* @attr {Boolean} small - for a small input (only if the field has one row)
|
|
38
|
+
* @attr {Object} grammar - The grammar for Expression Language support
|
|
39
|
+
*
|
|
40
|
+
* @attr {Boolean} [clipboard=false]- true if field has clipboard button
|
|
41
|
+
* @attr {Boolean} [autofocus=false] - true to put the focus on the input
|
|
42
|
+
* @attr {Boolean} [readonly=false] - true if field is readonly mode
|
|
22
43
|
*/
|
|
23
44
|
export class GvExpressionLanguage extends GvCode {
|
|
45
|
+
static get properties() {
|
|
46
|
+
return {
|
|
47
|
+
...super.properties,
|
|
48
|
+
grammar: { type: Object },
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
24
52
|
firstUpdated() {
|
|
25
53
|
super.firstUpdated();
|
|
26
|
-
dispatchCustomEvent(this, 'ready');
|
|
54
|
+
dispatchCustomEvent(this, 'ready', { currentTarget: this });
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
getExtensions() {
|
|
58
|
+
return [Prec.high(this.insertELKeymap())];
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
insertELKeymap() {
|
|
62
|
+
return keymap.of([
|
|
63
|
+
{
|
|
64
|
+
key: 'Ctrl-Shift-e',
|
|
65
|
+
mac: 'Cmd-Shift-e',
|
|
66
|
+
run(view) {
|
|
67
|
+
view.dispatch(
|
|
68
|
+
view.state.changeByRange((range) => ({
|
|
69
|
+
changes: [{ from: range.from, to: range.to, insert: '{#}' }],
|
|
70
|
+
range: EditorSelection.range(range.from + 2, range.to + 2),
|
|
71
|
+
})),
|
|
72
|
+
);
|
|
73
|
+
startCompletion(view);
|
|
74
|
+
return true;
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
]);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
buildMethods(type) {
|
|
81
|
+
const modelType = this.getModelType(type);
|
|
82
|
+
return modelType.methods.map(({ name, params = [], returnType }) => {
|
|
83
|
+
const command = `${name}()`;
|
|
84
|
+
const displayParams = params.map((p) => `${p.type} ${p.name}`);
|
|
85
|
+
const label = `${name}(${displayParams.join(', ')})`;
|
|
86
|
+
const detail = `return ${returnType}`;
|
|
87
|
+
return {
|
|
88
|
+
type: 'method',
|
|
89
|
+
command,
|
|
90
|
+
apply: (view, completion, from, to) => {
|
|
91
|
+
const anchor = from + name.length + 1;
|
|
92
|
+
view.dispatch({
|
|
93
|
+
changes: { from, to, insert: completion.command },
|
|
94
|
+
selection: { anchor },
|
|
95
|
+
userEvent: 'input.complete',
|
|
96
|
+
annotations: pickedCompletion.of(view),
|
|
97
|
+
});
|
|
98
|
+
},
|
|
99
|
+
label,
|
|
100
|
+
detail,
|
|
101
|
+
};
|
|
102
|
+
});
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
findBestAutocompleteHandler(completionContext) {
|
|
106
|
+
return this.expressionLanguageCompletionHandlers
|
|
107
|
+
.filter((handler) => (this.grammar != null && handler.supportEL === true) || handler.supportEL !== true)
|
|
108
|
+
.map((handler) => {
|
|
109
|
+
const match = handler.expr ? completionContext.matchBefore(handler.expr) : true;
|
|
110
|
+
return { handler, match };
|
|
111
|
+
})
|
|
112
|
+
.find(({ match, expr }) => match);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
getModelType(typeId) {
|
|
116
|
+
if (this.grammar != null) {
|
|
117
|
+
return get(this.grammar, `_types.${typeId}`);
|
|
118
|
+
}
|
|
119
|
+
return null;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
isMap(typeId) {
|
|
123
|
+
return ['Map', 'HttpHeaders', 'MultiValueMap'].includes(typeId);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
getEnum(typeId) {
|
|
127
|
+
if (this.grammar != null) {
|
|
128
|
+
return get(this.grammar, `_enums.${typeId}`);
|
|
129
|
+
}
|
|
130
|
+
return [''];
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
convertType(type) {
|
|
134
|
+
if (type) {
|
|
135
|
+
const lowerType = type.toLowerCase();
|
|
136
|
+
if (lowerType === 'string') {
|
|
137
|
+
return 'text';
|
|
138
|
+
} else if (lowerType === 'httpheaders' || lowerType === 'multivaluemap') {
|
|
139
|
+
return 'type';
|
|
140
|
+
} else if (lowerType === 'int' || lowerType === 'long') {
|
|
141
|
+
return 'variable';
|
|
142
|
+
} else if (lowerType.includes('[]')) {
|
|
143
|
+
return 'enum';
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
return 'variable';
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
get expressionLanguageCompletionHandlers() {
|
|
150
|
+
return [
|
|
151
|
+
{
|
|
152
|
+
expr: /{#[a-z]*/,
|
|
153
|
+
supportEL: true,
|
|
154
|
+
run(completionContext, match) {
|
|
155
|
+
const prefix = match.text.replaceAll('{#', '');
|
|
156
|
+
const from = completionContext.pos - prefix.length;
|
|
157
|
+
const options = Object.keys(this.grammar)
|
|
158
|
+
.filter((command) => !command.startsWith('_') && command.startsWith(prefix))
|
|
159
|
+
.map((command) => {
|
|
160
|
+
return {
|
|
161
|
+
type: 'variable',
|
|
162
|
+
command,
|
|
163
|
+
apply: command,
|
|
164
|
+
label: command,
|
|
165
|
+
};
|
|
166
|
+
});
|
|
167
|
+
return { from, options };
|
|
168
|
+
},
|
|
169
|
+
},
|
|
170
|
+
{
|
|
171
|
+
expr: /{#[a-z]*.[a-zA-Z]*/,
|
|
172
|
+
supportEL: true,
|
|
173
|
+
run(completionContext, match) {
|
|
174
|
+
const tokens = match.text.split('.');
|
|
175
|
+
const key = tokens[0].replaceAll('{#', '');
|
|
176
|
+
const prefix = tokens[1];
|
|
177
|
+
let candidate = this.grammar[key][prefix];
|
|
178
|
+
let options = [];
|
|
179
|
+
let from = completionContext.pos;
|
|
180
|
+
if (candidate) {
|
|
181
|
+
if (this.isMap(candidate._type)) {
|
|
182
|
+
options = this.getEnum(candidate._type).map((value) => {
|
|
183
|
+
const type = this.convertType(candidate._type);
|
|
184
|
+
const command = `['${value}'][0]`;
|
|
185
|
+
return {
|
|
186
|
+
type,
|
|
187
|
+
command,
|
|
188
|
+
apply: command,
|
|
189
|
+
label: value,
|
|
190
|
+
};
|
|
191
|
+
});
|
|
192
|
+
}
|
|
193
|
+
} else {
|
|
194
|
+
from -= prefix.length;
|
|
195
|
+
candidate = this.grammar[key];
|
|
196
|
+
if (candidate._type) {
|
|
197
|
+
options = this.buildMethods(candidate._type);
|
|
198
|
+
} else {
|
|
199
|
+
options = Object.keys(candidate)
|
|
200
|
+
.filter((command) => !command.startsWith('_') && command.startsWith(prefix))
|
|
201
|
+
.map((command) => ({
|
|
202
|
+
type: this.convertType(candidate[command]._type),
|
|
203
|
+
command,
|
|
204
|
+
apply: command,
|
|
205
|
+
label: command,
|
|
206
|
+
}));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return { from, options };
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
expr: /{#[a-z]*.[a-zA-Z]*.[a-zA-Z]*/,
|
|
214
|
+
supportEL: true,
|
|
215
|
+
run(completionContext, match) {
|
|
216
|
+
const tokens = match.text.split('.');
|
|
217
|
+
const key = tokens[0].replaceAll('{#', '');
|
|
218
|
+
const word = tokens[1];
|
|
219
|
+
const prefix = tokens[2];
|
|
220
|
+
const candidate = this.grammar[key][word];
|
|
221
|
+
let options = [];
|
|
222
|
+
let from = completionContext.pos;
|
|
223
|
+
if (candidate) {
|
|
224
|
+
if (this.isMap(candidate._type)) {
|
|
225
|
+
options = this.getEnum(candidate._type)
|
|
226
|
+
.filter((command) => !command.startsWith('_') && command.startsWith(prefix))
|
|
227
|
+
.map((label) => {
|
|
228
|
+
const type = this.convertType(candidate._type);
|
|
229
|
+
return {
|
|
230
|
+
type,
|
|
231
|
+
command: `['${label}'][0]`,
|
|
232
|
+
apply(view, completion, _from, to) {
|
|
233
|
+
from = _from - prefix.length - 1;
|
|
234
|
+
view.dispatch({
|
|
235
|
+
changes: { from, to, insert: completion.command },
|
|
236
|
+
selection: { anchor: from + completion.command.length },
|
|
237
|
+
userEvent: 'input.complete',
|
|
238
|
+
annotations: pickedCompletion.of(view),
|
|
239
|
+
});
|
|
240
|
+
},
|
|
241
|
+
label,
|
|
242
|
+
};
|
|
243
|
+
});
|
|
244
|
+
} else {
|
|
245
|
+
if (candidate._type) {
|
|
246
|
+
options = this.buildMethods(candidate._type);
|
|
247
|
+
} else {
|
|
248
|
+
from -= prefix.length;
|
|
249
|
+
options = Object.keys(candidate)
|
|
250
|
+
.filter((command) => command.startsWith(prefix))
|
|
251
|
+
.map((command) => {
|
|
252
|
+
return {
|
|
253
|
+
type: this.convertType(candidate[command]._type),
|
|
254
|
+
command,
|
|
255
|
+
apply: command,
|
|
256
|
+
label: command,
|
|
257
|
+
};
|
|
258
|
+
});
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
return { from, options };
|
|
263
|
+
},
|
|
264
|
+
},
|
|
265
|
+
this.defaultCompletionHandler,
|
|
266
|
+
];
|
|
27
267
|
}
|
|
28
268
|
}
|
|
29
269
|
|
|
@@ -427,10 +427,6 @@ export class GvPolicyStudio extends KeyboardElement(LitElement) {
|
|
|
427
427
|
search.focus();
|
|
428
428
|
}
|
|
429
429
|
}
|
|
430
|
-
if (this.isPressed(KEYS.Esc)) {
|
|
431
|
-
this._closeFlowStepForm();
|
|
432
|
-
this._onCloseDocumentation();
|
|
433
|
-
}
|
|
434
430
|
}
|
|
435
431
|
}
|
|
436
432
|
|
|
@@ -1114,7 +1110,7 @@ export class GvPolicyStudio extends KeyboardElement(LitElement) {
|
|
|
1114
1110
|
outlined
|
|
1115
1111
|
small
|
|
1116
1112
|
@gv-button:click="${this._onCloseFlowStepForm}"
|
|
1117
|
-
title="Close
|
|
1113
|
+
title="Close"
|
|
1118
1114
|
></gv-button>
|
|
1119
1115
|
<gv-button
|
|
1120
1116
|
slot="header-left"
|