Browse Source

UI: SCADA symbol functions completers and highlights.

pull/11391/head
Igor Kulikov 2 years ago
parent
commit
a4504ad9ce
  1. 18
      ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg.models.ts
  2. 10
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.html
  3. 19
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.ts
  4. 2
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.html
  5. 7
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.ts
  6. 7
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.html
  7. 36
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.scss
  8. 72
      ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.ts
  9. 253
      ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.models.ts
  10. 34
      ui-ngx/src/app/shared/components/js-func.component.ts
  11. 6
      ui-ngx/src/app/shared/models/ace/ace.models.ts
  12. 4
      ui-ngx/src/app/shared/models/ace/completion.models.ts

18
ui-ngx/src/app/modules/home/components/widget/lib/svg/iot-svg.models.ts

@ -61,13 +61,13 @@ export interface IotSvgContext {
properties: {[id: string]: any};
}
export type IotSvgStateRenderFunction = (svg: Svg, ctx: IotSvgContext) => void;
export type IotSvgStateRenderFunction = (ctx: IotSvgContext, svg: Svg) => void;
export type IotSvgTagStateRenderFunction = (element: Element, ctx: IotSvgContext) => void;
export type IotSvgTagStateRenderFunction = (ctx: IotSvgContext, element: Element) => void;
export type IotSvgActionTrigger = 'click';
export type IotSvgActionFunction = (event: Event, ctx: IotSvgContext) => void;
export type IotSvgActionFunction = (ctx: IotSvgContext, event: Event) => void;
export interface IotSvgAction {
actionFunction?: string;
action?: IotSvgActionFunction;
@ -421,13 +421,13 @@ export class IotSvgObject {
}
private prepareMetadata() {
this.metadata.stateRender = parseFunction(this.metadata.stateRenderFunction, ['svg', 'ctx']) || (() => {});
this.metadata.stateRender = parseFunction(this.metadata.stateRenderFunction, ['ctx', 'svg']) || (() => {});
for (const tag of this.metadata.tags) {
tag.stateRender = parseFunction(tag.stateRenderFunction, ['element', 'ctx']) || (() => {});
tag.stateRender = parseFunction(tag.stateRenderFunction, ['ctx', 'element']) || (() => {});
if (tag.actions) {
for (const trigger of Object.keys(tag.actions)) {
const action = tag.actions[trigger];
action.action = parseFunction(action.actionFunction, ['event', 'ctx']) || (() => {});
action.action = parseFunction(action.actionFunction, ['ctx', 'event']) || (() => {});
}
}
}
@ -483,7 +483,7 @@ export class IotSvgObject {
elements.forEach(element => {
element.attr('cursor', 'pointer');
element.on(trigger, (event) => {
action.action(event, this.context);
action.action(this.context, event);
});
});
}
@ -637,11 +637,11 @@ export class IotSvgObject {
}
private renderState(): void {
this.metadata.stateRender(this.svgShape, this.context);
this.metadata.stateRender(this.context, this.svgShape);
for (const tag of this.metadata.tags) {
const elements = this.context.tags[tag.tag];// this.svgShape.find(`[tb\\:tag="${tag.tag}"]`);
elements.forEach(element => {
tag.stateRender(element, this.context);
tag.stateRender(this.context, element);
});
}
}

10
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.html

@ -49,7 +49,10 @@
<ng-template matExpansionPanelContent>
<tb-js-func #stateRenderFunction
formControlName="stateRenderFunction"
[functionArgs]="['element', 'ctx']"
[objectHighlightRules]="scadaSymbolElementStateRenderHighlightRules"
[propertyHighlightRules]="scadaSymbolElementStateRenderPropertiesHighlightRules"
[editorCompleter]="elementStateRenderFunctionCompleter"
[functionArgs]="['ctx', 'element']"
helpId="widget/lib/timeseries/cell_style_fn">
</tb-js-func>
</ng-template>
@ -65,7 +68,10 @@
<ng-template matExpansionPanelContent>
<tb-js-func #clickAction
formControlName="clickAction"
[functionArgs]="['event', 'ctx']"
[objectHighlightRules]="scadaSymbolClickActionHighlightRules"
[propertyHighlightRules]="scadaSymbolClickActionPropertiesHighlightRules"
[editorCompleter]="clickActionFunctionCompleter"
[functionArgs]="['ctx', 'event']"
helpId="widget/lib/timeseries/cell_style_fn">
</tb-js-func>
</ng-template>

19
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component.ts

@ -38,6 +38,13 @@ import { IotSvgTag } from '@home/components/widget/lib/svg/iot-svg.models';
import { MatExpansionPanel } from '@angular/material/expansion';
import { JsFuncComponent } from '@shared/components/js-func.component';
import { MatSelect } from '@angular/material/select';
import { TbEditorCompleter } from '@shared/models/ace/completion.models';
import {
scadaSymbolClickActionHighlightRules,
scadaSymbolClickActionPropertiesHighlightRules,
scadaSymbolElementStateRenderHighlightRules,
scadaSymbolElementStateRenderPropertiesHighlightRules
} from '@home/pages/scada-symbol/scada-symbol.models';
@Component({
selector: 'tb-scada-symbol-metadata-tag',
@ -78,6 +85,12 @@ export class ScadaSymbolMetadataTagComponent implements ControlValueAccessor, On
@Input()
tags: string[];
@Input()
elementStateRenderFunctionCompleter: TbEditorCompleter;
@Input()
clickActionFunctionCompleter: TbEditorCompleter;
@Output()
tagRemoved = new EventEmitter();
@ -87,6 +100,12 @@ export class ScadaSymbolMetadataTagComponent implements ControlValueAccessor, On
modelValue: IotSvgTag;
scadaSymbolElementStateRenderHighlightRules = scadaSymbolElementStateRenderHighlightRules;
scadaSymbolElementStateRenderPropertiesHighlightRules = scadaSymbolElementStateRenderPropertiesHighlightRules;
scadaSymbolClickActionHighlightRules = scadaSymbolClickActionHighlightRules;
scadaSymbolClickActionPropertiesHighlightRules = scadaSymbolClickActionPropertiesHighlightRules;
private propagateChange = (_val: any) => {};
constructor(private fb: UntypedFormBuilder,

2
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.html

@ -19,6 +19,8 @@
<div *ngIf="tagsFormArray().controls.length; else noTags" class="tb-scada-symbol-metadata-tags-list">
<div *ngFor="let tagControl of tagsFormArray().controls; trackBy: trackByTag; let $index = index; let $last = last">
<tb-scada-symbol-metadata-tag fxFlex
[elementStateRenderFunctionCompleter]="elementStateRenderFunctionCompleter"
[clickActionFunctionCompleter]="clickActionFunctionCompleter"
[formControl]="tagControl"
[tags]="availableTags"
(tagRemoved)="removeTag($index)">

7
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component.ts

@ -40,6 +40,7 @@ import { IotSvgTag } from '@home/components/widget/lib/svg/iot-svg.models';
import {
ScadaSymbolMetadataTagComponent
} from '@home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tag.component';
import { TbEditorCompleter } from '@shared/models/ace/completion.models';
const tagValidator = (control: AbstractControl): ValidationErrors | null => {
const tag: IotSvgTag = control.value;
@ -83,6 +84,12 @@ export class ScadaSymbolMetadataTagsComponent implements ControlValueAccessor, O
@Input()
tags: string[];
@Input()
elementStateRenderFunctionCompleter: TbEditorCompleter;
@Input()
clickActionFunctionCompleter: TbEditorCompleter;
availableTags: string[];
tagsFormGroup: UntypedFormGroup;

7
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.html

@ -43,7 +43,10 @@
<ng-template matExpansionPanelContent>
<tb-js-func formControlName="stateRenderFunction"
minHeight="300px"
[functionArgs]="['svg', 'ctx']"
[editorCompleter]="generalStateRenderFunctionCompleter"
[objectHighlightRules]="scadaSymbolGeneralStateRenderHighlightRules"
[propertyHighlightRules]="scadaSymbolGeneralStateRenderPropertiesHighlightRules"
[functionArgs]="['ctx', 'svg']"
helpId="widget/lib/timeseries/cell_style_fn">
</tb-js-func>
</ng-template>
@ -55,6 +58,8 @@
<tb-scada-symbol-metadata-tags
#symbolMetadataTags
[tags]="tags"
[clickActionFunctionCompleter]="clickActionFunctionCompleter"
[elementStateRenderFunctionCompleter]="elementStateRenderFunctionCompleter"
formControlName="tags">
</tb-scada-symbol-metadata-tags>
</div>

36
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.scss

@ -73,4 +73,40 @@
}
}
}
.ace_tb {
&.ace_scada-symbol {
&-ctx {
color: orangered;
font-weight: bold;
&-properties, &-property {
color: #0c959c;
}
&-values, &-value {
color: #669900;
}
&-tags, &-tag {
color: #cc8500;
}
&-api, &-api-method {
color: #ff00fe;
}
&-properties, &-values, &-tags, &-api {
font-style: italic;
// font-weight: bold;
}
&-property, &-value, &-tag, &-api-method {
font-weight: bold;
// font-weight: bold;
}
}
&-svg, &-element, &-event {
color: orangered;
font-weight: bold;
&-properties {
color: #0c959c;
font-weight: bold;
}
}
}
}
}

72
ui-ngx/src/app/modules/home/pages/scada-symbol/metadata-components/scada-symbol-metadata.component.ts

@ -14,7 +14,16 @@
/// limitations under the License.
///
import { Component, forwardRef, Input, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import {
Component,
forwardRef,
Input,
OnChanges,
OnInit,
SimpleChanges,
ViewChild,
ViewEncapsulation
} from '@angular/core';
import {
ControlValueAccessor,
NG_VALIDATORS,
@ -26,7 +35,7 @@ import {
Validators
} from '@angular/forms';
import { PageComponent } from '@shared/components/page.component';
import { IotSvgMetadata } from '@home/components/widget/lib/svg/iot-svg.models';
import { emptyMetadata, IotSvgMetadata } from '@home/components/widget/lib/svg/iot-svg.models';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { ToggleHeaderOption } from '@shared/components/toggle-header.component';
@ -34,6 +43,16 @@ import { TranslateService } from '@ngx-translate/core';
import {
ScadaSymbolMetadataTagsComponent
} from '@home/pages/scada-symbol/metadata-components/scada-symbol-metadata-tags.component';
import { TbEditorCompleter } from '@shared/models/ace/completion.models';
import {
clickActionFunctionCompletions,
elementStateRenderFunctionCompletions,
generalStateRenderFunctionCompletions,
iotSvgContextCompletion,
scadaSymbolGeneralStateRenderHighlightRules,
scadaSymbolGeneralStateRenderPropertiesHighlightRules
} from '@home/pages/scada-symbol/scada-symbol.models';
import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe';
@Component({
selector: 'tb-scada-symbol-metadata',
@ -53,7 +72,7 @@ import {
],
encapsulation: ViewEncapsulation.None
})
export class ScadaSymbolMetadataComponent extends PageComponent implements OnInit, ControlValueAccessor, Validator {
export class ScadaSymbolMetadataComponent extends PageComponent implements OnInit, OnChanges, ControlValueAccessor, Validator {
@ViewChild('symbolMetadataTags')
symbolMetadataTags: ScadaSymbolMetadataTagsComponent;
@ -91,9 +110,18 @@ export class ScadaSymbolMetadataComponent extends PageComponent implements OnIni
selectedOption = 'general';
generalStateRenderFunctionCompleter: TbEditorCompleter;
elementStateRenderFunctionCompleter: TbEditorCompleter;
clickActionFunctionCompleter: TbEditorCompleter;
scadaSymbolGeneralStateRenderHighlightRules = scadaSymbolGeneralStateRenderHighlightRules;
scadaSymbolGeneralStateRenderPropertiesHighlightRules = scadaSymbolGeneralStateRenderPropertiesHighlightRules;
constructor(protected store: Store<AppState>,
private fb: UntypedFormBuilder,
private translate: TranslateService) {
private translate: TranslateService,
private customTranslate: CustomTranslatePipe) {
super(store);
}
@ -105,12 +133,24 @@ export class ScadaSymbolMetadataComponent extends PageComponent implements OnIni
behavior: [null],
properties: [null]
});
this.updateFunctionCompleters(emptyMetadata());
this.metadataFormGroup.valueChanges.subscribe(() => {
this.updateModel();
});
}
ngOnChanges(changes: SimpleChanges): void {
for (const propName of Object.keys(changes)) {
const change = changes[propName];
if (!change.firstChange && change.currentValue !== change.previousValue) {
if (['tags'].includes(propName)) {
this.updateFunctionCompleters(this.modelValue);
}
}
}
}
registerOnChange(fn: any): void {
this.propagateChange = fn;
}
@ -132,6 +172,7 @@ export class ScadaSymbolMetadataComponent extends PageComponent implements OnIni
this.metadataFormGroup.patchValue(
value, {emitEvent: false}
);
this.updateFunctionCompleters(value);
}
editTagStateRenderFunction(tag: string): void {
@ -157,5 +198,28 @@ export class ScadaSymbolMetadataComponent extends PageComponent implements OnIni
const metadata: IotSvgMetadata = this.metadataFormGroup.getRawValue();
this.modelValue = metadata;
this.propagateChange(this.modelValue);
this.updateFunctionCompleters(metadata);
}
private updateFunctionCompleters(metadata: IotSvgMetadata) {
const contextCompleter = iotSvgContextCompletion(metadata, this.tags, this.customTranslate);
const generalStateRender = generalStateRenderFunctionCompletions(contextCompleter);
if (!this.generalStateRenderFunctionCompleter) {
this.generalStateRenderFunctionCompleter = new TbEditorCompleter(generalStateRender);
} else {
this.generalStateRenderFunctionCompleter.updateCompletions(generalStateRender);
}
const elementStateRender = elementStateRenderFunctionCompletions(contextCompleter);
if (!this.elementStateRenderFunctionCompleter) {
this.elementStateRenderFunctionCompleter = new TbEditorCompleter(elementStateRender);
} else {
this.elementStateRenderFunctionCompleter.updateCompletions(elementStateRender);
}
const clickAction = clickActionFunctionCompletions(contextCompleter);
if (!this.clickActionFunctionCompleter) {
this.clickActionFunctionCompleter = new TbEditorCompleter(clickAction);
} else {
this.clickActionFunctionCompleter.updateCompletions(clickAction);
}
}
}

253
ui-ngx/src/app/modules/home/pages/scada-symbol/scada-symbol.models.ts

@ -24,11 +24,22 @@ import {
setupAddTagPanelTooltip,
setupTagPanelTooltip
} from '@home/pages/scada-symbol/scada-symbol-tooltip.components';
import { iotSvgContentData } from '@home/components/widget/lib/svg/iot-svg.models';
import {
IotSvgBehavior,
IotSvgBehaviorType,
iotSvgContentData,
IotSvgMetadata,
IotSvgProperty,
IotSvgPropertyType
} from '@home/components/widget/lib/svg/iot-svg.models';
import { TbEditorCompletion, TbEditorCompletions } from '@shared/models/ace/completion.models';
import { CustomTranslatePipe } from '@shared/pipe/custom-translate.pipe';
import { TbHighlightRule } from '@shared/models/ace/ace.models';
import ITooltipsterInstance = JQueryTooltipster.ITooltipsterInstance;
import TooltipPositioningSide = JQueryTooltipster.TooltipPositioningSide;
import ITooltipsterHelper = JQueryTooltipster.ITooltipsterHelper;
import ITooltipPosition = JQueryTooltipster.ITooltipPosition;
import { ValueType } from '@shared/models/constants';
export interface ScadaSymbolData {
imageResource: ImageResourceInfo;
@ -747,3 +758,243 @@ export class ScadaSymbolElement {
}
}
const scadaSymbolCtxObjectHighlightRules: TbHighlightRule[] = [
{
class: 'scada-symbol-ctx',
regex: /(?<=\W|^)(ctx)(?=\.)\b/
}
];
export const scadaSymbolGeneralStateRenderHighlightRules: TbHighlightRule[] =
scadaSymbolCtxObjectHighlightRules.concat({
class: 'scada-symbol-svg',
regex: /(?<=\W|^)(svg)(?=\.)\b/
});
export const scadaSymbolElementStateRenderHighlightRules: TbHighlightRule[] =
scadaSymbolCtxObjectHighlightRules.concat({
class: 'scada-symbol-element',
regex: /(?<=\W|^)(element)(?=\.)\b/
});
export const scadaSymbolClickActionHighlightRules: TbHighlightRule[] =
scadaSymbolCtxObjectHighlightRules.concat({
class: 'scada-symbol-event',
regex: /(?<=\W|^)(event)(?=\.)\b/
});
const scadaSymbolCtxPropertyHighlightRules: TbHighlightRule[] = [
{
class: 'scada-symbol-ctx-properties',
regex: /(?<=ctx\.)(properties)\b/
},
{
class: 'scada-symbol-ctx-tags',
regex: /(?<=ctx\.)(tags)\b/
},
{
class: 'scada-symbol-ctx-values',
regex: /(?<=ctx\.)(values)\b/
},
{
class: 'scada-symbol-ctx-api',
regex: /(?<=ctx\.)(api)\b/
},
{
class: 'scada-symbol-ctx-property',
regex: /(?<=ctx\.properties\.)([a-zA-Z\$_\u00a1-\uffff][a-zA-Z\d\$_\u00a1-\uffff]*)\b/
},
{
class: 'scada-symbol-ctx-tag',
regex: /(?<=ctx\.tags\.)([a-zA-Z\$_\u00a1-\uffff][a-zA-Z\d\$_\u00a1-\uffff]*)\b/
},
{
class: 'scada-symbol-ctx-value',
regex: /(?<=ctx\.values\.)([a-zA-Z\$_\u00a1-\uffff][a-zA-Z\d\$_\u00a1-\uffff]*)\b/
},
{
class: 'scada-symbol-ctx-api-method',
regex: /(?<=ctx\.api\.)([a-zA-Z\$_\u00a1-\uffff][a-zA-Z\d\$_\u00a1-\uffff]*)\b/
}
];
export const scadaSymbolGeneralStateRenderPropertiesHighlightRules: TbHighlightRule[] =
scadaSymbolCtxPropertyHighlightRules.concat({
class: 'scada-symbol-svg-properties',
regex: /(?<=svg\.)([a-zA-Z\$_\u00a1-\uffff][a-zA-Z\d\$_\u00a1-\uffff]*)\b/
});
export const scadaSymbolElementStateRenderPropertiesHighlightRules: TbHighlightRule[] =
scadaSymbolCtxPropertyHighlightRules.concat({
class: 'scada-symbol-element-properties',
regex: /(?<=element\.)([a-zA-Z\$_\u00a1-\uffff][a-zA-Z\d\$_\u00a1-\uffff]*)\b/
});
export const scadaSymbolClickActionPropertiesHighlightRules: TbHighlightRule[] =
scadaSymbolCtxPropertyHighlightRules.concat({
class: 'scada-symbol-event-properties',
regex: /(?<=event\.)([a-zA-Z\$_\u00a1-\uffff][a-zA-Z\d\$_\u00a1-\uffff]*)\b/
});
export const generalStateRenderFunctionCompletions = (ctxCompletion: TbEditorCompletion): TbEditorCompletions => {
return {
ctx: ctxCompletion,
svg: {
meta: 'argument',
type: 'Svg',
description: 'A root svg node. Instance of SVG.Svg.'
}
};
};
export const elementStateRenderFunctionCompletions = (ctxCompletion: TbEditorCompletion): TbEditorCompletions => {
return {
ctx: ctxCompletion,
element: {
meta: 'argument',
type: 'Element',
description: 'An SVG element.'
},
};
};
export const clickActionFunctionCompletions = (ctxCompletion: TbEditorCompletion): TbEditorCompletions => {
return {
ctx: ctxCompletion,
event: {
meta: 'argument',
type: 'Event',
description: 'DOM event.'
},
};
};
export const iotSvgContextCompletion = (metadata: IotSvgMetadata, tags: string[],
customTranslate: CustomTranslatePipe): TbEditorCompletion => {
const properties: TbEditorCompletion = {
meta: 'object',
type: 'object',
description: 'An object holding all defined SVG object properties.',
children: {}
};
for (const property of metadata.properties) {
properties.children[property.id] = iotSvgPropertyCompletion(property, customTranslate);
}
const values: TbEditorCompletion = {
meta: 'object',
type: 'object',
description: 'An object holding all values obtained using behaviors of type \'Value\'',
children: {}
};
const getValues = metadata.behavior.filter(b => b.type === IotSvgBehaviorType.value);
for (const value of getValues) {
values.children[value.id] = iotSvgValueCompletion(value, customTranslate);
}
const tagsCompletions: TbEditorCompletion = {
meta: 'object',
type: 'object',
description: 'An object holding all tagged SVG elements grouped by tags (object keys).',
children: {}
};
if (tags?.length) {
for (const tag of tags) {
tagsCompletions.children[tag] = {
meta: 'property',
description: 'An array of SVG elements.',
type: 'Array<Element>'
};
}
}
return {
meta: 'argument',
type: 'IotSvgContext',
description: 'Context of svg object.',
children: {
api: {
meta: 'object',
type: 'IotSvgApi',
description: 'Svg object API',
children: {
animate: {
meta: 'function',
description: 'Animate SVG element',
args: [
{
name: 'element',
description: 'SVG element',
type: 'Element'
},
{
name: 'duration',
description: 'Animation duretion is milliseconds',
type: 'number'
}
],
return: {
description: 'Instance of SVG.Runner which has the same methods as any element and additional methods to control the runner.',
type: 'SVG.Runner'
}
}
}
},
properties,
values,
tags: tagsCompletions
}
};
};
const iotSvgPropertyCompletion = (property: IotSvgProperty, customTranslate: CustomTranslatePipe): TbEditorCompletion => {
let description = customTranslate.transform(property.name, property.name);
if (property.subLabel) {
description += ` <small>${customTranslate.transform(property.subLabel, property.subLabel)}</small>`;
}
return {
meta: 'property',
description,
type: iotSvgPropertyCompletionType(property.type)
};
};
const iotSvgValueCompletion = (value: IotSvgBehavior, customTranslate: CustomTranslatePipe): TbEditorCompletion => {
const description = customTranslate.transform(value.name, value.name);
return {
meta: 'property',
description,
type: iotSvgValueCompletionType(value.valueType)
};
};
const iotSvgPropertyCompletionType = (type: IotSvgPropertyType): string => {
switch (type) {
case IotSvgPropertyType.text:
return 'string';
case IotSvgPropertyType.number:
return 'number';
case IotSvgPropertyType.switch:
return 'boolean';
case IotSvgPropertyType.color:
return 'color string';
case IotSvgPropertyType.color_settings:
return 'ColorProcessor';
case IotSvgPropertyType.font:
return 'Font';
case IotSvgPropertyType.units:
return 'units string';
}
};
const iotSvgValueCompletionType = (type: ValueType): string => {
switch (type) {
case ValueType.STRING:
return 'string';
case ValueType.INTEGER:
case ValueType.DOUBLE:
return 'number';
case ValueType.BOOLEAN:
return 'boolean';
case ValueType.JSON:
return 'object';
}
};

34
ui-ngx/src/app/shared/components/js-func.component.ts

@ -27,13 +27,13 @@ import {
} from '@angular/core';
import { ControlValueAccessor, UntypedFormControl, NG_VALIDATORS, NG_VALUE_ACCESSOR, Validator } from '@angular/forms';
import { Ace } from 'ace-builds';
import { getAce, Range } from '@shared/models/ace/ace.models';
import { getAce, Range, TbHighlightRule } from '@shared/models/ace/ace.models';
import { coerceBooleanProperty } from '@angular/cdk/coercion';
import { ActionNotificationHide, ActionNotificationShow } from '@core/notification/notification.actions';
import { Store } from '@ngrx/store';
import { AppState } from '@core/core.state';
import { UtilsService } from '@core/services/utils.service';
import { guid, isUndefined } from '@app/core/utils';
import { deepClone, guid, isUndefined } from '@app/core/utils';
import { TranslateService } from '@ngx-translate/core';
import { CancelAnimationFrame, RafService } from '@core/services/raf.service';
import { ResizeObserver } from '@juggle/resize-observer';
@ -90,6 +90,10 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor,
@Input() editorCompleter: TbEditorCompleter;
@Input() propertyHighlightRules: TbHighlightRule[];
@Input() objectHighlightRules: TbHighlightRule[];
@Input() globalVariables: Array<string>;
@Input() disableUndefinedCheck = false;
@ -216,6 +220,32 @@ export class JsFuncComponent implements OnInit, OnDestroy, ControlValueAccessor,
});
}
// @ts-ignore
if ((this.propertyHighlightRules?.length || this.objectHighlightRules?.length) && !!this.jsEditor.session.$mode) {
// @ts-ignore
const newMode = new this.jsEditor.session.$mode.constructor();
newMode.$highlightRules = new newMode.HighlightRules();
if (this.propertyHighlightRules?.length) {
const propertiesRules: { token: string; regex: RegExp }[] = newMode.$highlightRules.$rules.property;
const index = propertiesRules.findIndex(p => p.token === 'support.constant');
const additionalPropertyRules: { token: string; regex: RegExp }[] = this.propertyHighlightRules.map(r => ({
token: `tb.${r.class}`,
regex: r.regex
}));
propertiesRules.splice(index, 0, ...additionalPropertyRules);
}
if (this.objectHighlightRules?.length) {
const noRegexRules: { token: string; regex: RegExp }[] = newMode.$highlightRules.$rules.no_regex;
const index = noRegexRules.findIndex(p => Array.isArray(p.token) && p.token[0] === 'support.constant');
const additionalNoRegexRules: { token: string; regex: RegExp }[] = this.objectHighlightRules.map(r => ({
token: `tb.${r.class}`,
regex: r.regex
}));
noRegexRules.splice(index, 0, ...additionalNoRegexRules);
}
// @ts-ignore
this.jsEditor.session.$onChangeMode(newMode);
}
// @ts-ignore
if (!!this.jsEditor.session.$worker) {
const jsWorkerOptions = {
undef: !this.disableUndefinedCheck,

6
ui-ngx/src/app/shared/models/ace/ace.models.ts

@ -347,3 +347,9 @@ export class Range implements Ace.Range {
}
}
export interface TbHighlightRule {
class: string;
regex: RegExp;
}

4
ui-ngx/src/app/shared/models/ace/completion.models.ts

@ -59,6 +59,10 @@ export class TbEditorCompleter implements Ace.Completer {
constructor(private editorCompletions: TbEditorCompletions) {
}
updateCompletions(completions: TbEditorCompletions): void {
this.editorCompletions = completions;
}
getCompletions(editor: Ace.Editor, session: Ace.EditSession,
position: Ace.Point, prefix: string, callback: Ace.CompleterCallback): void {
const result = this.prepareCompletions(prefix);

Loading…
Cancel
Save