wuic-framework-lib 1.3.0 → 1.5.0
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/fesm2022/{wuic-framework-lib-chart-list.component-C02jeFGy.mjs → wuic-framework-lib-chart-list.component-0J1ghIrS.mjs} +4 -4
- package/fesm2022/{wuic-framework-lib-code-editor.component-BZNLr0Jj.mjs → wuic-framework-lib-code-editor.component-C21mvjyr.mjs} +277 -13
- package/fesm2022/{wuic-framework-lib-designer.component-N_CfbGnr.mjs → wuic-framework-lib-designer.component-x10ZzUEy.mjs} +1649 -184
- package/fesm2022/{wuic-framework-lib-first-run-wizard.component-lW7-xMm3.mjs → wuic-framework-lib-first-run-wizard.component-BuSxs_CM.mjs} +83 -43
- package/fesm2022/{wuic-framework-lib-framework-docs.component-CGQbmSkv.mjs → wuic-framework-lib-framework-docs.component-xTGLbEnp.mjs} +1326 -99
- package/fesm2022/{wuic-framework-lib-pivot-builder.component-0gJz9RWr.mjs → wuic-framework-lib-pivot-builder.component-BkFFjPm4.mjs} +6 -6
- package/fesm2022/{wuic-framework-lib-prompt-dialog-fallback-host.component-C9LvmFsL.mjs → wuic-framework-lib-prompt-dialog-fallback-host.component-Bi-TrJB6.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-report-designer.component-DcpdzFjh.mjs → wuic-framework-lib-report-designer.component-ZvB46-LV.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-report-viewer.component-BHpbGpp9.mjs → wuic-framework-lib-report-viewer.component-BR-BfI2r.mjs} +2 -2
- package/fesm2022/wuic-framework-lib-scene3d-designer.component-BQzFxSXP.mjs +4578 -0
- package/fesm2022/wuic-framework-lib-scene3d-light-baker-gpu-0LjqhSNn.mjs +303 -0
- package/fesm2022/wuic-framework-lib-scene3d-shader-effect-CQLWkuh1.mjs +2227 -0
- package/fesm2022/wuic-framework-lib-scene3d-viewer.component-imoV3HOs.mjs +999 -0
- package/fesm2022/{wuic-framework-lib-scheduler-list.component-DHoukjf-.mjs → wuic-framework-lib-scheduler-list.component-xzlTEkoq.mjs} +2 -2
- package/fesm2022/{wuic-framework-lib-spreadsheet-list-sf.component-VsaXepUC.mjs → wuic-framework-lib-spreadsheet-list-sf.component-CrS6fOGj.mjs} +4 -4
- package/fesm2022/wuic-framework-lib-workflow-designer.component-5xtQ7-6z.mjs +9474 -0
- package/fesm2022/{wuic-framework-lib-wuic-framework-lib-Deudd4MY.mjs → wuic-framework-lib-wuic-framework-lib-3TZ-j-yL.mjs} +2682 -732
- package/fesm2022/wuic-framework-lib.mjs +1 -1
- package/package.json +2 -1
- package/types/wuic-framework-lib.d.ts +762 -9
- package/fesm2022/wuic-framework-lib-workflow-designer.component-epj3oKq3.mjs +0 -5114
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
2
|
import { EventEmitter, ViewChild, Output, Input, Component } from '@angular/core';
|
|
3
3
|
import { BehaviorSubject } from 'rxjs';
|
|
4
|
-
import { W as WtoolboxService, k as WuicClientException, l as WuicErrorCodes, G as GlobalHandler, M as MetadataProviderService, T as TranslationManagerService, U as UserInfoService, A as ArchetypeConfiguratorComponent } from './wuic-framework-lib-wuic-framework-lib-
|
|
4
|
+
import { W as WtoolboxService, k as WuicClientException, l as WuicErrorCodes, G as GlobalHandler, M as MetadataProviderService, T as TranslationManagerService, U as UserInfoService, A as ArchetypeConfiguratorComponent } from './wuic-framework-lib-wuic-framework-lib-3TZ-j-yL.mjs';
|
|
5
5
|
import * as i5 from 'primeng/chart';
|
|
6
6
|
import { ChartModule } from 'primeng/chart';
|
|
7
|
-
import * as
|
|
7
|
+
import * as i2 from '@ngx-translate/core';
|
|
8
8
|
import { TranslateModule } from '@ngx-translate/core';
|
|
9
9
|
import * as i1 from '@angular/platform-browser';
|
|
10
10
|
import * as i1$1 from '@angular/router';
|
|
@@ -1345,7 +1345,7 @@ class ChartListComponent {
|
|
|
1345
1345
|
this.parentResizeObserver = undefined;
|
|
1346
1346
|
}
|
|
1347
1347
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ChartListComponent, deps: [{ token: i1.Title }, { token: i0.ChangeDetectorRef }, { token: i1$1.ActivatedRoute }, { token: TranslationManagerService }, { token: UserInfoService }], target: i0.ɵɵFactoryTarget.Component });
|
|
1348
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: ChartListComponent, isStandalone: true, selector: "wuic-chart-list", inputs: { hardcodedRoute: "hardcodedRoute", parentRecord: "parentRecord", parentMetaInfo: "parentMetaInfo", datasource: "datasource", hardcodedDatasource: "hardcodedDatasource", hideToolbar: "hideToolbar" }, outputs: { onChartDataSelect: "onChartDataSelect", onChartDrillDown: "onChartDrillDown", onChartDataBound: "onChartDataBound" }, viewQueries: [{ propertyName: "chartRef", first: true, predicate: ["chartRef"], descendants: true }, { propertyName: "chartHostRef", first: true, predicate: ["chartHostRef"], descendants: true }], ngImport: i0, template: "@if (chartOptions) {\n <div class=\"chart-list-root\">\n @if (!hideToolbar) {\n <div class=\"chart-list-toolbar\">\n @if (isAdmin) {\n <button class=\"p-element p-button p-component\" (click)=\"openConfigPopup()\">{{'chart.settings' | translate}}</button>\n }\n <button class=\"p-element p-button p-component\" (click)=\"exportChart()\">{{'chart.export' | translate}}</button>\n @if (isAdmin) {\n <button class=\"p-element p-button p-component\" (click)=\"saveChartMetadataPropsBag()\">{{ 'metadata.save_table' | translate }}</button>\n }\n </div>\n }\n\n <div class=\"chart-list-chart-host\" #chartHostRef [style.height.px]=\"chartHostHeightPx\" [style.max-height.px]=\"chartHostHeightPx\">\n <p-chart #chartRef [type]=\"chartOptions.type\" [data]=\"data\" [options]=\"chartOptions\" width=\"100%\"\n height=\"100%\" [responsive]=\"true\" (onDataSelect)=\"drillDown($event)\" />\n </div>\n </div>\n\n <wuic-archetype-configurator\n [visible]=\"showConfigPopup\"\n (visibleChange)=\"showConfigPopup = $event\"\n [archetype]=\"'chart'\"\n [metaInfo]=\"metaInfo\"\n [value]=\"getChartConfigValue()\"\n (applyConfig)=\"onArchetypeConfigApply($event)\">\n </wuic-archetype-configurator>\n}\n", styles: [":host{display:block;height:100%;min-height:0;overflow:hidden}.chart-list-root{display:flex;flex-direction:column;height:100%;width:100%;min-height:0;overflow:hidden}.chart-list-cutoff{flex:0 0 auto;padding:.5rem 0}.chart-list-toolbar{flex:0 0 auto;padding:.5rem 0;display:flex;gap:.5rem;flex-wrap:wrap}.chart-list-config{flex:0 0 auto;padding:.5rem 0}.chart-list-modal-backdrop{position:fixed;inset:0;background:#0006;z-index:1200;display:flex;align-items:center;justify-content:center;padding:1rem}.chart-list-modal{width:min(900px,100%);max-height:85vh;overflow:auto;background:#fff;color:#111827;border-radius:8px;box-shadow:0 10px 32px #00000040;padding:1rem}.chart-list-modal-header{display:flex;align-items:center;justify-content:space-between;gap:.75rem;margin-bottom:.75rem}.chart-list-modal-header h4{margin:0}.chart-list-config-row{display:flex;flex-direction:column;gap:.3rem;margin-bottom:.5rem}.chart-list-inline{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}.chart-list-inline label{display:inline-flex;align-items:center;gap:.35rem}.chart-list-type-select,.chart-list-inline select,.chart-list-input,.chart-list-input-sm{background:#fff;color:#111827;border:1px solid #d1d5db;border-radius:6px;padding:.35rem .45rem}.chart-list-config-label{font-weight:600;font-size:.9rem}.chart-list-type-select,.chart-list-input,.chart-list-input-sm{width:100%;box-sizing:border-box}.chart-list-input-sm{width:8rem}:host-context(.theme-dark) .chart-list-modal-backdrop{background:#000000a6}:host-context(.theme-dark) .chart-list-modal{background:#111827;color:#e5e7eb;box-shadow:0 10px 32px #0000008c}:host-context(.theme-dark) .chart-list-config-label,:host-context(.theme-dark) .chart-list-inline label{color:#e5e7eb}:host-context(.theme-dark) .chart-list-type-select,:host-context(.theme-dark) .chart-list-inline select,:host-context(.theme-dark) .chart-list-input,:host-context(.theme-dark) .chart-list-input-sm{background:#0f172a;color:#e5e7eb;border-color:#374151}:host-context(.theme-dark) .chart-list-type-select:focus,:host-context(.theme-dark) .chart-list-inline select:focus,:host-context(.theme-dark) .chart-list-input:focus,:host-context(.theme-dark) .chart-list-input-sm:focus{outline:1px solid #60a5fa;outline-offset:0}.chart-list-cutoff-label{display:block;font-weight:600}.chart-list-cutoff-slider{width:100%}.chart-list-chart-host{flex:1 1 auto;min-height:0;overflow:hidden}.chart-list-chart-host p-chart{display:block;height:100%}\n"], dependencies: [{ kind: "ngmodule", type: ChartModule }, { kind: "component", type: i5.UIChart, selector: "p-chart", inputs: ["type", "plugins", "width", "height", "responsive", "ariaLabel", "ariaLabelledBy", "data", "options"], outputs: ["onDataSelect"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: ArchetypeConfiguratorComponent, selector: "wuic-archetype-configurator", inputs: ["visible", "archetype", "metaInfo", "value"], outputs: ["visibleChange", "applyConfig"] }, { kind: "pipe", type:
|
|
1348
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: ChartListComponent, isStandalone: true, selector: "wuic-chart-list", inputs: { hardcodedRoute: "hardcodedRoute", parentRecord: "parentRecord", parentMetaInfo: "parentMetaInfo", datasource: "datasource", hardcodedDatasource: "hardcodedDatasource", hideToolbar: "hideToolbar" }, outputs: { onChartDataSelect: "onChartDataSelect", onChartDrillDown: "onChartDrillDown", onChartDataBound: "onChartDataBound" }, viewQueries: [{ propertyName: "chartRef", first: true, predicate: ["chartRef"], descendants: true }, { propertyName: "chartHostRef", first: true, predicate: ["chartHostRef"], descendants: true }], ngImport: i0, template: "@if (chartOptions) {\n <div class=\"chart-list-root\">\n @if (!hideToolbar) {\n <div class=\"chart-list-toolbar\">\n @if (isAdmin) {\n <button class=\"p-element p-button p-component\" (click)=\"openConfigPopup()\">{{'chart.settings' | translate}}</button>\n }\n <button class=\"p-element p-button p-component\" (click)=\"exportChart()\">{{'chart.export' | translate}}</button>\n @if (isAdmin) {\n <button class=\"p-element p-button p-component\" (click)=\"saveChartMetadataPropsBag()\">{{ 'metadata.save_table' | translate }}</button>\n }\n </div>\n }\n\n <div class=\"chart-list-chart-host\" #chartHostRef [style.height.px]=\"chartHostHeightPx\" [style.max-height.px]=\"chartHostHeightPx\">\n <p-chart #chartRef [type]=\"chartOptions.type\" [data]=\"data\" [options]=\"chartOptions\" width=\"100%\"\n height=\"100%\" [responsive]=\"true\" (onDataSelect)=\"drillDown($event)\" />\n </div>\n </div>\n\n <wuic-archetype-configurator\n [visible]=\"showConfigPopup\"\n (visibleChange)=\"showConfigPopup = $event\"\n [archetype]=\"'chart'\"\n [metaInfo]=\"metaInfo\"\n [value]=\"getChartConfigValue()\"\n (applyConfig)=\"onArchetypeConfigApply($event)\">\n </wuic-archetype-configurator>\n}\n", styles: [":host{display:block;height:100%;min-height:0;overflow:hidden}.chart-list-root{display:flex;flex-direction:column;height:100%;width:100%;min-height:0;overflow:hidden}.chart-list-cutoff{flex:0 0 auto;padding:.5rem 0}.chart-list-toolbar{flex:0 0 auto;padding:.5rem 0;display:flex;gap:.5rem;flex-wrap:wrap}.chart-list-config{flex:0 0 auto;padding:.5rem 0}.chart-list-modal-backdrop{position:fixed;inset:0;background:#0006;z-index:1200;display:flex;align-items:center;justify-content:center;padding:1rem}.chart-list-modal{width:min(900px,100%);max-height:85vh;overflow:auto;background:#fff;color:#111827;border-radius:8px;box-shadow:0 10px 32px #00000040;padding:1rem}.chart-list-modal-header{display:flex;align-items:center;justify-content:space-between;gap:.75rem;margin-bottom:.75rem}.chart-list-modal-header h4{margin:0}.chart-list-config-row{display:flex;flex-direction:column;gap:.3rem;margin-bottom:.5rem}.chart-list-inline{display:flex;align-items:center;gap:.75rem;flex-wrap:wrap}.chart-list-inline label{display:inline-flex;align-items:center;gap:.35rem}.chart-list-type-select,.chart-list-inline select,.chart-list-input,.chart-list-input-sm{background:#fff;color:#111827;border:1px solid #d1d5db;border-radius:6px;padding:.35rem .45rem}.chart-list-config-label{font-weight:600;font-size:.9rem}.chart-list-type-select,.chart-list-input,.chart-list-input-sm{width:100%;box-sizing:border-box}.chart-list-input-sm{width:8rem}:host-context(.theme-dark) .chart-list-modal-backdrop{background:#000000a6}:host-context(.theme-dark) .chart-list-modal{background:#111827;color:#e5e7eb;box-shadow:0 10px 32px #0000008c}:host-context(.theme-dark) .chart-list-config-label,:host-context(.theme-dark) .chart-list-inline label{color:#e5e7eb}:host-context(.theme-dark) .chart-list-type-select,:host-context(.theme-dark) .chart-list-inline select,:host-context(.theme-dark) .chart-list-input,:host-context(.theme-dark) .chart-list-input-sm{background:#0f172a;color:#e5e7eb;border-color:#374151}:host-context(.theme-dark) .chart-list-type-select:focus,:host-context(.theme-dark) .chart-list-inline select:focus,:host-context(.theme-dark) .chart-list-input:focus,:host-context(.theme-dark) .chart-list-input-sm:focus{outline:1px solid #60a5fa;outline-offset:0}.chart-list-cutoff-label{display:block;font-weight:600}.chart-list-cutoff-slider{width:100%}.chart-list-chart-host{flex:1 1 auto;min-height:0;overflow:hidden}.chart-list-chart-host p-chart{display:block;height:100%}\n"], dependencies: [{ kind: "ngmodule", type: ChartModule }, { kind: "component", type: i5.UIChart, selector: "p-chart", inputs: ["type", "plugins", "width", "height", "responsive", "ariaLabel", "ariaLabelledBy", "data", "options"], outputs: ["onDataSelect"] }, { kind: "ngmodule", type: TranslateModule }, { kind: "component", type: ArchetypeConfiguratorComponent, selector: "wuic-archetype-configurator", inputs: ["visible", "archetype", "metaInfo", "value"], outputs: ["visibleChange", "applyConfig"] }, { kind: "pipe", type: i2.TranslatePipe, name: "translate" }] });
|
|
1349
1349
|
}
|
|
1350
1350
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: ChartListComponent, decorators: [{
|
|
1351
1351
|
type: Component,
|
|
@@ -1377,4 +1377,4 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
1377
1377
|
}] } });
|
|
1378
1378
|
|
|
1379
1379
|
export { ChartListComponent };
|
|
1380
|
-
//# sourceMappingURL=wuic-framework-lib-chart-list.component-
|
|
1380
|
+
//# sourceMappingURL=wuic-framework-lib-chart-list.component-0J1ghIrS.mjs.map
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { inject, ElementRef, SecurityContext, ViewChild,
|
|
3
|
-
import * as i1
|
|
2
|
+
import { EventEmitter, Output, Input, Component, inject, ElementRef, SecurityContext, ViewChild, HostBinding } from '@angular/core';
|
|
3
|
+
import * as i1 from '@angular/forms';
|
|
4
4
|
import { FormsModule } from '@angular/forms';
|
|
5
|
-
import * as i1 from '@materia-ui/ngx-monaco-editor';
|
|
5
|
+
import * as i1$1 from '@materia-ui/ngx-monaco-editor';
|
|
6
6
|
import { MonacoEditorModule } from '@materia-ui/ngx-monaco-editor';
|
|
7
7
|
import { filter, take } from 'rxjs/operators';
|
|
8
8
|
import { Emitter } from 'monaco-editor/esm/vs/base/common/event';
|
|
9
|
-
import { W as WtoolboxService, M as MetadataProviderService, e as MetadatiColonna, m as MetaInfo, U as UserInfoService, f as DataProviderService } from './wuic-framework-lib-wuic-framework-lib-
|
|
10
|
-
import { NgClass, NgStyle } from '@angular/common';
|
|
11
|
-
import * as
|
|
9
|
+
import { W as WtoolboxService, M as MetadataProviderService, e as MetadatiColonna, m as MetaInfo, U as UserInfoService, f as DataProviderService } from './wuic-framework-lib-wuic-framework-lib-3TZ-j-yL.mjs';
|
|
10
|
+
import { NgTemplateOutlet, NgClass, NgStyle } from '@angular/common';
|
|
11
|
+
import * as i10 from 'primeng/contextmenu';
|
|
12
12
|
import { ContextMenuModule } from 'primeng/contextmenu';
|
|
13
13
|
import * as i4 from 'primeng/tree';
|
|
14
14
|
import { TreeModule } from 'primeng/tree';
|
|
15
|
-
import * as i1$
|
|
15
|
+
import * as i1$2 from '@angular/common/http';
|
|
16
16
|
import { HttpHeaders } from '@angular/common/http';
|
|
17
17
|
import { from, combineLatest } from 'rxjs';
|
|
18
18
|
import { parseFragment } from 'parse5';
|
|
19
|
-
import * as i1$
|
|
19
|
+
import * as i1$3 from '@angular/platform-browser';
|
|
20
20
|
import * as i3 from 'primeng/api';
|
|
21
21
|
|
|
22
22
|
class SqlModel {
|
|
@@ -2354,6 +2354,15 @@ class TSProvider {
|
|
|
2354
2354
|
let self = this;
|
|
2355
2355
|
let extraLibs = [];
|
|
2356
2356
|
let libs = [];
|
|
2357
|
+
// Snippet custom dal chiamante (customEditorConfig.snippets, mappa
|
|
2358
|
+
// label -> testo): si SOMMANO ai base perche' il menu contestuale
|
|
2359
|
+
// "Snippets" e' l'unico canale di inserimento guidato — es. il
|
|
2360
|
+
// workflow-designer inietta voci per-nodo che compilano
|
|
2361
|
+
// `wtoolbox.getWorkflowRouteNodePayload('<nodeId>')` con l'id reale.
|
|
2362
|
+
// Mappa d'istanza (un TSProvider per editor): nessun effetto altrove.
|
|
2363
|
+
if (formFieldOptions?.snippets && typeof formFieldOptions.snippets === 'object') {
|
|
2364
|
+
Object.assign(this.snippets, formFieldOptions.snippets);
|
|
2365
|
+
}
|
|
2357
2366
|
let contextMenuItems = [
|
|
2358
2367
|
{
|
|
2359
2368
|
label: 'Snippets', icon: 'pi pi-receipt',
|
|
@@ -2630,6 +2639,188 @@ class ContextMenuInteractionEmitter extends Emitter {
|
|
|
2630
2639
|
}
|
|
2631
2640
|
}
|
|
2632
2641
|
|
|
2642
|
+
/**
|
|
2643
|
+
* Property-editor "a struttura" guidato da JSON SCHEMA — vista alternativa
|
|
2644
|
+
* (toggle) del code-editor in modalita' json: aggiunta/rimozione di
|
|
2645
|
+
* nodi/sottonodi TIPIZZATI in base allo schema, senza scrivere JSON a mano.
|
|
2646
|
+
*
|
|
2647
|
+
* Copertura schema v1 (subset pragmatico dei casi usati dagli schemi WUIC,
|
|
2648
|
+
* es. customEditorConfig/props_bag/scene3d shader effect):
|
|
2649
|
+
* - object con `properties` (+`required`): righe per le proprieta' presenti,
|
|
2650
|
+
* dropdown "aggiungi" per quelle mancanti, rimozione per le non-required;
|
|
2651
|
+
* - string (input testo; color picker se pattern hex #rrggbb; select se enum);
|
|
2652
|
+
* - number/integer (input numerico con min/max dallo schema);
|
|
2653
|
+
* - boolean (checkbox); const (badge readonly);
|
|
2654
|
+
* - array di number a lunghezza fissa (minItems=maxItems, es. direzioni xyz)
|
|
2655
|
+
* e array generici (item add/remove col tipo di `items`).
|
|
2656
|
+
*
|
|
2657
|
+
* Il valore viene MUTATO su una copia locale e riemesso integralmente a ogni
|
|
2658
|
+
* modifica (`valueChange`): il code-editor lo serializza nel model Monaco e
|
|
2659
|
+
* nel record, cosi' le due viste restano sempre allineate.
|
|
2660
|
+
*/
|
|
2661
|
+
class JsonSchemaTreeEditorComponent {
|
|
2662
|
+
/** JSON schema radice (draft-07 style: type/properties/required/enum/const/items). */
|
|
2663
|
+
schema = null;
|
|
2664
|
+
/** Valore corrente (oggetto JS gia' parsato). Lavora su una copia profonda. */
|
|
2665
|
+
value = null;
|
|
2666
|
+
/** Emesso a ogni mutazione con l'intero valore aggiornato. */
|
|
2667
|
+
valueChange = new EventEmitter();
|
|
2668
|
+
/** Copia locale mutabile del valore. */
|
|
2669
|
+
model = {};
|
|
2670
|
+
ngOnChanges() {
|
|
2671
|
+
try {
|
|
2672
|
+
this.model = this.value != null ? JSON.parse(JSON.stringify(this.value)) : {};
|
|
2673
|
+
}
|
|
2674
|
+
catch {
|
|
2675
|
+
this.model = {};
|
|
2676
|
+
}
|
|
2677
|
+
}
|
|
2678
|
+
emit() {
|
|
2679
|
+
this.valueChange.emit(JSON.parse(JSON.stringify(this.model)));
|
|
2680
|
+
}
|
|
2681
|
+
// --- Introspezione schema -------------------------------------------------
|
|
2682
|
+
/** Righe (proprieta' PRESENTI nel valore) per un nodo object. */
|
|
2683
|
+
rows(schema, obj) {
|
|
2684
|
+
const props = schema?.properties || {};
|
|
2685
|
+
const required = Array.isArray(schema?.required) ? schema.required : [];
|
|
2686
|
+
return Object.keys(props)
|
|
2687
|
+
.filter((key) => obj != null && Object.prototype.hasOwnProperty.call(obj, key))
|
|
2688
|
+
.map((key) => ({
|
|
2689
|
+
key,
|
|
2690
|
+
schema: props[key],
|
|
2691
|
+
kind: this.kindOf(props[key]),
|
|
2692
|
+
required: required.includes(key)
|
|
2693
|
+
}));
|
|
2694
|
+
}
|
|
2695
|
+
/** Proprieta' dello schema NON ancora presenti nel valore (per il dropdown "aggiungi"). */
|
|
2696
|
+
addable(schema, obj) {
|
|
2697
|
+
const props = schema?.properties || {};
|
|
2698
|
+
return Object.keys(props).filter((key) => !(obj != null && Object.prototype.hasOwnProperty.call(obj, key)));
|
|
2699
|
+
}
|
|
2700
|
+
/** Classifica il tipo di editor per una property schema. */
|
|
2701
|
+
kindOf(propSchema) {
|
|
2702
|
+
if (!propSchema) {
|
|
2703
|
+
return 'text';
|
|
2704
|
+
}
|
|
2705
|
+
if (propSchema.const !== undefined) {
|
|
2706
|
+
return 'const';
|
|
2707
|
+
}
|
|
2708
|
+
if (Array.isArray(propSchema.enum)) {
|
|
2709
|
+
return 'enum';
|
|
2710
|
+
}
|
|
2711
|
+
const type = propSchema.type;
|
|
2712
|
+
if (type === 'boolean') {
|
|
2713
|
+
return 'boolean';
|
|
2714
|
+
}
|
|
2715
|
+
if (type === 'number' || type === 'integer') {
|
|
2716
|
+
return 'number';
|
|
2717
|
+
}
|
|
2718
|
+
if (type === 'object') {
|
|
2719
|
+
return 'object';
|
|
2720
|
+
}
|
|
2721
|
+
if (type === 'array') {
|
|
2722
|
+
const fixed = Number(propSchema.minItems) > 0 && propSchema.minItems === propSchema.maxItems
|
|
2723
|
+
&& (propSchema.items?.type === 'number' || propSchema.items?.type === 'integer');
|
|
2724
|
+
return fixed ? 'vector' : 'array';
|
|
2725
|
+
}
|
|
2726
|
+
if (type === 'string' && typeof propSchema.pattern === 'string' && propSchema.pattern.includes('#[0-9a-fA-F]{6}')) {
|
|
2727
|
+
return 'color';
|
|
2728
|
+
}
|
|
2729
|
+
return 'text';
|
|
2730
|
+
}
|
|
2731
|
+
/** Valore di default tipizzato per una property aggiunta dalla struttura. */
|
|
2732
|
+
defaultFor(propSchema) {
|
|
2733
|
+
if (!propSchema) {
|
|
2734
|
+
return '';
|
|
2735
|
+
}
|
|
2736
|
+
if (propSchema.default !== undefined) {
|
|
2737
|
+
return JSON.parse(JSON.stringify(propSchema.default));
|
|
2738
|
+
}
|
|
2739
|
+
if (propSchema.const !== undefined) {
|
|
2740
|
+
return propSchema.const;
|
|
2741
|
+
}
|
|
2742
|
+
if (Array.isArray(propSchema.enum)) {
|
|
2743
|
+
return propSchema.enum[0];
|
|
2744
|
+
}
|
|
2745
|
+
const type = propSchema.type;
|
|
2746
|
+
if (type === 'boolean') {
|
|
2747
|
+
return false;
|
|
2748
|
+
}
|
|
2749
|
+
if (type === 'number' || type === 'integer') {
|
|
2750
|
+
return typeof propSchema.minimum === 'number' ? propSchema.minimum : 0;
|
|
2751
|
+
}
|
|
2752
|
+
if (type === 'array') {
|
|
2753
|
+
const n = Number(propSchema.minItems) || 0;
|
|
2754
|
+
return Array.from({ length: n }, () => this.defaultFor(propSchema.items));
|
|
2755
|
+
}
|
|
2756
|
+
if (type === 'object') {
|
|
2757
|
+
const child = {};
|
|
2758
|
+
const required = Array.isArray(propSchema.required) ? propSchema.required : [];
|
|
2759
|
+
for (const key of required) {
|
|
2760
|
+
child[key] = this.defaultFor(propSchema.properties?.[key]);
|
|
2761
|
+
}
|
|
2762
|
+
return child;
|
|
2763
|
+
}
|
|
2764
|
+
if (this.kindOf(propSchema) === 'color') {
|
|
2765
|
+
return '#ffffff';
|
|
2766
|
+
}
|
|
2767
|
+
return '';
|
|
2768
|
+
}
|
|
2769
|
+
// --- Mutazioni ------------------------------------------------------------
|
|
2770
|
+
setProp(obj, key, value) {
|
|
2771
|
+
obj[key] = value;
|
|
2772
|
+
this.emit();
|
|
2773
|
+
}
|
|
2774
|
+
setNumberProp(obj, key, raw) {
|
|
2775
|
+
const parsed = Number(raw);
|
|
2776
|
+
obj[key] = Number.isFinite(parsed) ? parsed : 0;
|
|
2777
|
+
this.emit();
|
|
2778
|
+
}
|
|
2779
|
+
addProp(obj, key, propSchema, selectEl) {
|
|
2780
|
+
if (!key) {
|
|
2781
|
+
return;
|
|
2782
|
+
}
|
|
2783
|
+
obj[key] = this.defaultFor(propSchema);
|
|
2784
|
+
if (selectEl) {
|
|
2785
|
+
selectEl.value = '';
|
|
2786
|
+
}
|
|
2787
|
+
this.emit();
|
|
2788
|
+
}
|
|
2789
|
+
removeProp(obj, key) {
|
|
2790
|
+
delete obj[key];
|
|
2791
|
+
this.emit();
|
|
2792
|
+
}
|
|
2793
|
+
setVectorItem(arr, index, raw) {
|
|
2794
|
+
const parsed = Number(raw);
|
|
2795
|
+
arr[index] = Number.isFinite(parsed) ? parsed : 0;
|
|
2796
|
+
this.emit();
|
|
2797
|
+
}
|
|
2798
|
+
addArrayItem(arr, itemSchema) {
|
|
2799
|
+
arr.push(this.defaultFor(itemSchema));
|
|
2800
|
+
this.emit();
|
|
2801
|
+
}
|
|
2802
|
+
removeArrayItem(arr, index) {
|
|
2803
|
+
arr.splice(index, 1);
|
|
2804
|
+
this.emit();
|
|
2805
|
+
}
|
|
2806
|
+
/** Etichetta breve per gli hint (description dello schema, troncata). */
|
|
2807
|
+
hint(propSchema) {
|
|
2808
|
+
return String(propSchema?.description || '');
|
|
2809
|
+
}
|
|
2810
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: JsonSchemaTreeEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
2811
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: JsonSchemaTreeEditorComponent, isStandalone: true, selector: "wuic-json-schema-tree-editor", inputs: { schema: "schema", value: "value" }, outputs: { valueChange: "valueChange" }, usesOnChanges: true, ngImport: i0, template: "<!-- Editor \"a struttura\": ricorsione via ng-template (nessun self-import). -->\n<ng-template #objectEditor let-ctx>\n @for (row of rows(ctx.schema, ctx.obj); track row.key) {\n <div class=\"jste-row\" [class.jste-row-object]=\"row.kind === 'object'\">\n <div class=\"jste-row-head\">\n <span class=\"jste-key\" [title]=\"hint(row.schema)\">{{ row.key }}</span>\n\n @switch (row.kind) {\n @case ('const') {\n <span class=\"jste-const\">{{ ctx.obj[row.key] }}</span>\n }\n @case ('enum') {\n <select class=\"jste-input\" [ngModel]=\"ctx.obj[row.key]\"\n (ngModelChange)=\"setProp(ctx.obj, row.key, $event)\">\n @for (opt of row.schema.enum; track opt) {\n <option [ngValue]=\"opt\">{{ opt }}</option>\n }\n </select>\n }\n @case ('boolean') {\n <input type=\"checkbox\" [ngModel]=\"ctx.obj[row.key]\"\n (ngModelChange)=\"setProp(ctx.obj, row.key, $event)\" />\n }\n @case ('number') {\n <input class=\"jste-input jste-number\" type=\"number\" step=\"any\"\n [min]=\"row.schema.minimum\" [max]=\"row.schema.maximum\"\n [ngModel]=\"ctx.obj[row.key]\"\n (ngModelChange)=\"setNumberProp(ctx.obj, row.key, $event)\" />\n }\n @case ('color') {\n <input class=\"jste-color\" type=\"color\" [ngModel]=\"ctx.obj[row.key]\"\n (ngModelChange)=\"setProp(ctx.obj, row.key, $event)\" />\n <span class=\"jste-const\">{{ ctx.obj[row.key] }}</span>\n }\n @case ('vector') {\n <span class=\"jste-vector\">\n @for (component of ctx.obj[row.key]; track $index) {\n <input class=\"jste-input jste-number\" type=\"number\" step=\"any\"\n [ngModel]=\"ctx.obj[row.key][$index]\"\n (ngModelChange)=\"setVectorItem(ctx.obj[row.key], $index, $event)\" />\n }\n </span>\n }\n @case ('text') {\n <input class=\"jste-input\" type=\"text\" [ngModel]=\"ctx.obj[row.key]\"\n (ngModelChange)=\"setProp(ctx.obj, row.key, $event)\" />\n }\n }\n\n @if (!row.required) {\n <button type=\"button\" class=\"jste-btn jste-remove\" (click)=\"removeProp(ctx.obj, row.key)\"\n title=\"Rimuovi\">\n <i class=\"pi pi-times\"></i>\n </button>\n }\n </div>\n\n @if (row.kind === 'object') {\n <div class=\"jste-children\">\n <ng-container *ngTemplateOutlet=\"objectEditor; context: { $implicit: { schema: row.schema, obj: ctx.obj[row.key] } }\"></ng-container>\n </div>\n }\n @if (row.kind === 'array') {\n <div class=\"jste-children\">\n @for (item of ctx.obj[row.key]; track $index) {\n <div class=\"jste-row-head\">\n <span class=\"jste-key\">[{{ $index }}]</span>\n @if (row.schema.items?.type === 'object') {\n <ng-container *ngTemplateOutlet=\"objectEditor; context: { $implicit: { schema: row.schema.items, obj: ctx.obj[row.key][$index] } }\"></ng-container>\n } @else if (row.schema.items?.type === 'number' || row.schema.items?.type === 'integer') {\n <input class=\"jste-input jste-number\" type=\"number\" step=\"any\"\n [ngModel]=\"ctx.obj[row.key][$index]\"\n (ngModelChange)=\"setVectorItem(ctx.obj[row.key], $index, $event)\" />\n } @else {\n <input class=\"jste-input\" type=\"text\" [ngModel]=\"ctx.obj[row.key][$index]\"\n (ngModelChange)=\"setProp(ctx.obj[row.key], $index, $event)\" />\n }\n <button type=\"button\" class=\"jste-btn jste-remove\" (click)=\"removeArrayItem(ctx.obj[row.key], $index)\">\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n }\n <button type=\"button\" class=\"jste-btn jste-add-item\" (click)=\"addArrayItem(ctx.obj[row.key], row.schema.items)\">\n <i class=\"pi pi-plus\"></i>\n </button>\n </div>\n }\n @if (hint(row.schema)) {\n <div class=\"jste-hint\">{{ hint(row.schema) }}</div>\n }\n </div>\n }\n\n @if (addable(ctx.schema, ctx.obj).length) {\n <div class=\"jste-add-row\">\n <select #addSelect class=\"jste-input jste-add-select\"\n (change)=\"addProp(ctx.obj, addSelect.value, ctx.schema.properties[addSelect.value], addSelect)\">\n <option value=\"\" disabled selected>+ proprieta'...</option>\n @for (key of addable(ctx.schema, ctx.obj); track key) {\n <option [value]=\"key\" [title]=\"hint(ctx.schema.properties[key])\">{{ key }}</option>\n }\n </select>\n </div>\n }\n</ng-template>\n\n<div class=\"jste-root\">\n <ng-container *ngTemplateOutlet=\"objectEditor; context: { $implicit: { schema: schema, obj: model } }\"></ng-container>\n</div>\n", styles: [".jste-root{height:100%;overflow:auto;padding:8px 10px;background:#1e1e1e;color:#d4d4d4;font-size:12.5px;font-family:Consolas,Courier New,monospace}.jste-row{margin:2px 0}.jste-row-head{display:flex;align-items:center;gap:8px;min-height:26px}.jste-key{color:#9cdcfe;min-width:110px}.jste-const{color:#b5cea8}.jste-input{background:#2a2a31;color:#d4d4d4;border:1px solid #3c3c46;border-radius:4px;padding:3px 6px;font-size:12.5px;font-family:inherit;min-width:0}.jste-number{width:84px}.jste-color{width:34px;height:24px;padding:0;border:1px solid #3c3c46;background:transparent}.jste-vector{display:inline-flex;gap:4px}.jste-btn{border:none;background:none;color:#8a8a95;cursor:pointer;padding:2px 4px;border-radius:4px}.jste-btn:hover{color:#e0e0e6;background:#34343c}.jste-remove i{font-size:11px}.jste-children{margin-left:18px;padding-left:10px;border-left:1px solid #34343c}.jste-row-object>.jste-row-head .jste-key{color:#dcdcaa;font-weight:600}.jste-hint{margin-left:118px;color:#6f6f7a;font-size:11px;line-height:1.3;max-width:460px}.jste-add-row{margin:4px 0 2px}.jste-add-select{color:#8fd18f}\n"], dependencies: [{ kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgSelectOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.ɵNgSelectMultipleOption, selector: "option", inputs: ["ngValue", "value"] }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NumberValueAccessor, selector: "input[type=number][formControlName],input[type=number][formControl],input[type=number][ngModel]" }, { kind: "directive", type: i1.CheckboxControlValueAccessor, selector: "input[type=checkbox][formControlName],input[type=checkbox][formControl],input[type=checkbox][ngModel]" }, { kind: "directive", type: i1.SelectControlValueAccessor, selector: "select:not([multiple])[formControlName],select:not([multiple])[formControl],select:not([multiple])[ngModel]", inputs: ["compareWith"] }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.MinValidator, selector: "input[type=number][min][formControlName],input[type=number][min][formControl],input[type=number][min][ngModel]", inputs: ["min"] }, { kind: "directive", type: i1.MaxValidator, selector: "input[type=number][max][formControlName],input[type=number][max][formControl],input[type=number][max][ngModel]", inputs: ["max"] }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "directive", type: NgTemplateOutlet, selector: "[ngTemplateOutlet]", inputs: ["ngTemplateOutletContext", "ngTemplateOutlet", "ngTemplateOutletInjector"] }] });
|
|
2812
|
+
}
|
|
2813
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: JsonSchemaTreeEditorComponent, decorators: [{
|
|
2814
|
+
type: Component,
|
|
2815
|
+
args: [{ selector: 'wuic-json-schema-tree-editor', standalone: true, imports: [FormsModule, NgTemplateOutlet], template: "<!-- Editor \"a struttura\": ricorsione via ng-template (nessun self-import). -->\n<ng-template #objectEditor let-ctx>\n @for (row of rows(ctx.schema, ctx.obj); track row.key) {\n <div class=\"jste-row\" [class.jste-row-object]=\"row.kind === 'object'\">\n <div class=\"jste-row-head\">\n <span class=\"jste-key\" [title]=\"hint(row.schema)\">{{ row.key }}</span>\n\n @switch (row.kind) {\n @case ('const') {\n <span class=\"jste-const\">{{ ctx.obj[row.key] }}</span>\n }\n @case ('enum') {\n <select class=\"jste-input\" [ngModel]=\"ctx.obj[row.key]\"\n (ngModelChange)=\"setProp(ctx.obj, row.key, $event)\">\n @for (opt of row.schema.enum; track opt) {\n <option [ngValue]=\"opt\">{{ opt }}</option>\n }\n </select>\n }\n @case ('boolean') {\n <input type=\"checkbox\" [ngModel]=\"ctx.obj[row.key]\"\n (ngModelChange)=\"setProp(ctx.obj, row.key, $event)\" />\n }\n @case ('number') {\n <input class=\"jste-input jste-number\" type=\"number\" step=\"any\"\n [min]=\"row.schema.minimum\" [max]=\"row.schema.maximum\"\n [ngModel]=\"ctx.obj[row.key]\"\n (ngModelChange)=\"setNumberProp(ctx.obj, row.key, $event)\" />\n }\n @case ('color') {\n <input class=\"jste-color\" type=\"color\" [ngModel]=\"ctx.obj[row.key]\"\n (ngModelChange)=\"setProp(ctx.obj, row.key, $event)\" />\n <span class=\"jste-const\">{{ ctx.obj[row.key] }}</span>\n }\n @case ('vector') {\n <span class=\"jste-vector\">\n @for (component of ctx.obj[row.key]; track $index) {\n <input class=\"jste-input jste-number\" type=\"number\" step=\"any\"\n [ngModel]=\"ctx.obj[row.key][$index]\"\n (ngModelChange)=\"setVectorItem(ctx.obj[row.key], $index, $event)\" />\n }\n </span>\n }\n @case ('text') {\n <input class=\"jste-input\" type=\"text\" [ngModel]=\"ctx.obj[row.key]\"\n (ngModelChange)=\"setProp(ctx.obj, row.key, $event)\" />\n }\n }\n\n @if (!row.required) {\n <button type=\"button\" class=\"jste-btn jste-remove\" (click)=\"removeProp(ctx.obj, row.key)\"\n title=\"Rimuovi\">\n <i class=\"pi pi-times\"></i>\n </button>\n }\n </div>\n\n @if (row.kind === 'object') {\n <div class=\"jste-children\">\n <ng-container *ngTemplateOutlet=\"objectEditor; context: { $implicit: { schema: row.schema, obj: ctx.obj[row.key] } }\"></ng-container>\n </div>\n }\n @if (row.kind === 'array') {\n <div class=\"jste-children\">\n @for (item of ctx.obj[row.key]; track $index) {\n <div class=\"jste-row-head\">\n <span class=\"jste-key\">[{{ $index }}]</span>\n @if (row.schema.items?.type === 'object') {\n <ng-container *ngTemplateOutlet=\"objectEditor; context: { $implicit: { schema: row.schema.items, obj: ctx.obj[row.key][$index] } }\"></ng-container>\n } @else if (row.schema.items?.type === 'number' || row.schema.items?.type === 'integer') {\n <input class=\"jste-input jste-number\" type=\"number\" step=\"any\"\n [ngModel]=\"ctx.obj[row.key][$index]\"\n (ngModelChange)=\"setVectorItem(ctx.obj[row.key], $index, $event)\" />\n } @else {\n <input class=\"jste-input\" type=\"text\" [ngModel]=\"ctx.obj[row.key][$index]\"\n (ngModelChange)=\"setProp(ctx.obj[row.key], $index, $event)\" />\n }\n <button type=\"button\" class=\"jste-btn jste-remove\" (click)=\"removeArrayItem(ctx.obj[row.key], $index)\">\n <i class=\"pi pi-times\"></i>\n </button>\n </div>\n }\n <button type=\"button\" class=\"jste-btn jste-add-item\" (click)=\"addArrayItem(ctx.obj[row.key], row.schema.items)\">\n <i class=\"pi pi-plus\"></i>\n </button>\n </div>\n }\n @if (hint(row.schema)) {\n <div class=\"jste-hint\">{{ hint(row.schema) }}</div>\n }\n </div>\n }\n\n @if (addable(ctx.schema, ctx.obj).length) {\n <div class=\"jste-add-row\">\n <select #addSelect class=\"jste-input jste-add-select\"\n (change)=\"addProp(ctx.obj, addSelect.value, ctx.schema.properties[addSelect.value], addSelect)\">\n <option value=\"\" disabled selected>+ proprieta'...</option>\n @for (key of addable(ctx.schema, ctx.obj); track key) {\n <option [value]=\"key\" [title]=\"hint(ctx.schema.properties[key])\">{{ key }}</option>\n }\n </select>\n </div>\n }\n</ng-template>\n\n<div class=\"jste-root\">\n <ng-container *ngTemplateOutlet=\"objectEditor; context: { $implicit: { schema: schema, obj: model } }\"></ng-container>\n</div>\n", styles: [".jste-root{height:100%;overflow:auto;padding:8px 10px;background:#1e1e1e;color:#d4d4d4;font-size:12.5px;font-family:Consolas,Courier New,monospace}.jste-row{margin:2px 0}.jste-row-head{display:flex;align-items:center;gap:8px;min-height:26px}.jste-key{color:#9cdcfe;min-width:110px}.jste-const{color:#b5cea8}.jste-input{background:#2a2a31;color:#d4d4d4;border:1px solid #3c3c46;border-radius:4px;padding:3px 6px;font-size:12.5px;font-family:inherit;min-width:0}.jste-number{width:84px}.jste-color{width:34px;height:24px;padding:0;border:1px solid #3c3c46;background:transparent}.jste-vector{display:inline-flex;gap:4px}.jste-btn{border:none;background:none;color:#8a8a95;cursor:pointer;padding:2px 4px;border-radius:4px}.jste-btn:hover{color:#e0e0e6;background:#34343c}.jste-remove i{font-size:11px}.jste-children{margin-left:18px;padding-left:10px;border-left:1px solid #34343c}.jste-row-object>.jste-row-head .jste-key{color:#dcdcaa;font-weight:600}.jste-hint{margin-left:118px;color:#6f6f7a;font-size:11px;line-height:1.3;max-width:460px}.jste-add-row{margin:4px 0 2px}.jste-add-select{color:#8fd18f}\n"] }]
|
|
2816
|
+
}], propDecorators: { schema: [{
|
|
2817
|
+
type: Input
|
|
2818
|
+
}], value: [{
|
|
2819
|
+
type: Input
|
|
2820
|
+
}], valueChange: [{
|
|
2821
|
+
type: Output
|
|
2822
|
+
}] } });
|
|
2823
|
+
|
|
2633
2824
|
const WUIC_COMMON_INPUTS = [
|
|
2634
2825
|
'record',
|
|
2635
2826
|
'field',
|
|
@@ -3303,6 +3494,20 @@ class CodeEditorComponent {
|
|
|
3303
3494
|
* Proprieta di stato del componente per editor model value, usata dalla logica interna e dal template.
|
|
3304
3495
|
*/
|
|
3305
3496
|
editorModelValue = '';
|
|
3497
|
+
/**
|
|
3498
|
+
* Toggle "Struttura" per il json: se true (via @Input o
|
|
3499
|
+
* `customEditorConfig.jsonTreeToggle`) la toolbar espone il passaggio
|
|
3500
|
+
* Codice <-> property-editor treeview guidato dallo schema JSON
|
|
3501
|
+
* ({@link JsonSchemaTreeEditorComponent}). Le due viste restano allineate:
|
|
3502
|
+
* ogni modifica nella struttura riscrive model Monaco e record.
|
|
3503
|
+
*/
|
|
3504
|
+
jsonTreeToggle = false;
|
|
3505
|
+
/** true quando e' attiva la vista struttura (Monaco nascosto ma vivo). */
|
|
3506
|
+
treeViewActive = false;
|
|
3507
|
+
/** Schema JSON radice per la vista struttura (primo schema configurato). */
|
|
3508
|
+
jsonTreeSchema = null;
|
|
3509
|
+
/** Valore parsato passato alla vista struttura. */
|
|
3510
|
+
treeValue = null;
|
|
3306
3511
|
/**
|
|
3307
3512
|
* Proprieta di stato del componente per sample code, usata dalla logica interna e dal template.
|
|
3308
3513
|
*/
|
|
@@ -3578,6 +3783,10 @@ class CodeEditorComponent {
|
|
|
3578
3783
|
await this.tsProvider.registerTSProvider(formFieldOptions, this.field, this.codeContext, this.record, this.metaSrv, this.userInfo);
|
|
3579
3784
|
}
|
|
3580
3785
|
else if (this.editorOptions.language === 'json') {
|
|
3786
|
+
// Vista "Struttura" (property-editor treeview da schema): abilitabile
|
|
3787
|
+
// via @Input jsonTreeToggle o `customEditorConfig.jsonTreeToggle`.
|
|
3788
|
+
this.jsonTreeToggle = this.jsonTreeToggle || formFieldOptions.jsonTreeToggle === true;
|
|
3789
|
+
this.jsonTreeSchema = formFieldOptions.schemas?.[0]?.schema || null;
|
|
3581
3790
|
// https://json-schema.org/learn/getting-started-step-by-step
|
|
3582
3791
|
// string.
|
|
3583
3792
|
// number.
|
|
@@ -3772,6 +3981,59 @@ class CodeEditorComponent {
|
|
|
3772
3981
|
this.skipNextAutoFormat = true;
|
|
3773
3982
|
this.editor.getAction('editor.action.formatDocument')?.run().catch(() => undefined);
|
|
3774
3983
|
}
|
|
3984
|
+
/**
|
|
3985
|
+
* Toggle Codice <-> Struttura (json): attivando la struttura il testo
|
|
3986
|
+
* corrente viene parsato (JSON invalido -> toast e resta il codice);
|
|
3987
|
+
* Monaco resta VIVO ma nascosto, cosi' il rientro e' istantaneo.
|
|
3988
|
+
*/
|
|
3989
|
+
toggleJsonTree($event) {
|
|
3990
|
+
$event?.stopPropagation?.();
|
|
3991
|
+
$event?.preventDefault?.();
|
|
3992
|
+
if (!this.isJsonEditor || !this.jsonTreeToggle) {
|
|
3993
|
+
return;
|
|
3994
|
+
}
|
|
3995
|
+
if (this.treeViewActive) {
|
|
3996
|
+
this.treeViewActive = false;
|
|
3997
|
+
this.scheduleEditorLayout();
|
|
3998
|
+
return;
|
|
3999
|
+
}
|
|
4000
|
+
const raw = String(this.editor?.getValue?.() ?? this.editorModelValue ?? '');
|
|
4001
|
+
let parsed = {};
|
|
4002
|
+
if (raw.trim()) {
|
|
4003
|
+
try {
|
|
4004
|
+
parsed = JSON.parse(raw);
|
|
4005
|
+
}
|
|
4006
|
+
catch {
|
|
4007
|
+
WtoolboxService.messageNotificationService.add({
|
|
4008
|
+
severity: 'error',
|
|
4009
|
+
summary: 'json_format_error',
|
|
4010
|
+
detail: this.t('json_format_error_detail', 'JSON non valido: impossibile formattare.')
|
|
4011
|
+
});
|
|
4012
|
+
return;
|
|
4013
|
+
}
|
|
4014
|
+
}
|
|
4015
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
|
|
4016
|
+
WtoolboxService.messageNotificationService.add({
|
|
4017
|
+
severity: 'warn',
|
|
4018
|
+
summary: 'json_tree_root_object',
|
|
4019
|
+
detail: this.t('json_tree_root_object_detail', 'La vista struttura richiede un oggetto JSON alla radice.')
|
|
4020
|
+
});
|
|
4021
|
+
return;
|
|
4022
|
+
}
|
|
4023
|
+
this.treeValue = parsed;
|
|
4024
|
+
this.treeViewActive = true;
|
|
4025
|
+
}
|
|
4026
|
+
/**
|
|
4027
|
+
* Modifica dalla vista struttura: riscrive il JSON formattato nel model
|
|
4028
|
+
* Monaco e nel record (stesso percorso di formatJsonNow), cosi' le due
|
|
4029
|
+
* viste e il valore persistito restano allineati.
|
|
4030
|
+
*/
|
|
4031
|
+
onTreeValueChange(value) {
|
|
4032
|
+
const pretty = JSON.stringify(value ?? {}, null, 2);
|
|
4033
|
+
this.editorModelValue = pretty;
|
|
4034
|
+
this.editor?.setValue(pretty);
|
|
4035
|
+
this.record?.[this.field.mc_nome_colonna]?.next(pretty);
|
|
4036
|
+
}
|
|
3775
4037
|
/**
|
|
3776
4038
|
* Gestisce la logica operativa di `formatJsonNow` orchestrando parse/stringify JSON e sync nel model editor.
|
|
3777
4039
|
* @param $event Evento UI o payload evento che innesca il flusso del metodo.
|
|
@@ -3969,13 +4231,13 @@ class CodeEditorComponent {
|
|
|
3969
4231
|
children: this.mapToPrimeTreeNodes(node?.items || [])
|
|
3970
4232
|
}));
|
|
3971
4233
|
}
|
|
3972
|
-
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CodeEditorComponent, deps: [{ token: i1.MonacoEditorLoaderService }, { token: i1$
|
|
3973
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: CodeEditorComponent, isStandalone: true, selector: "wuic-code-editor", inputs: { field: "field", record: "record", metaInfo: "metaInfo" }, host: { properties: { "style": "this.style" } }, viewQueries: [{ propertyName: "contextMenuAnchor", first: true, predicate: ["contextMenuAnchor"], descendants: true }, { propertyName: "editorRef", first: true, predicate: ["editorRef"], descendants: true }, { propertyName: "ctxs", first: true, predicate: ["ctxs"], descendants: true }], ngImport: i0, template: "@if (render) {\n<div [ngClass]=\"{'fullscreen': fullscreen, 'no-full-screen': !fullscreen }\">\n <div\n [ngStyle]=\"{width: sqlObjView ? '22%' : null, display: sqlObjView ? null : 'none', position: fullscreen ? 'absolute' : null, 'left': fullscreen ? '0px' : null, 'top': fullscreen ? '0px' : null }\"\n style=\"float: left; height: 100%; overflow: auto; background-color: #1e1e1e; z-index: 2000;\">\n <p-tree [value]=\"primeTreeNodes\">\n <ng-template let-node pTemplate=\"default\">\n <span style=\"-webkit-user-select: none; -ms-user-select: none; user-select: none;\" draggable=\"true\"\n (dragstart)=\"onTreeNodeDragStart($event, node.data)\" (click)=\"editorOptions.onNodeClick($event, node.data)\"\n (dragend)=\"onTreeNodeDragEnd($event, node.data)\">\n <span>\n {{ node.label }}\n </span>\n </span>\n </ng-template>\n </p-tree>\n </div>\n <div [ngStyle]=\"{width: sqlObjView ? '78%' : '100%', 'left': fullscreen ? (!sqlObjView ? '0px' : '22%') : null }\"\n style=\"height: 100%; float: left;\">\n <ul class=\"editor-btn\">\n <li>\n <div (click)=\"setFullScreen($event, this)\">\n <i\n [ngClass]=\"{'pi': true, 'pi-window-maximize': fullscreen == false, 'pi-window-minimize': fullscreen == true}\"></i>\n </div>\n </li>\n @if (editorOptions.language == 'sql') {\n <li>\n <div (click)=\"toggleSqlObjView($event, this)\">\n <i [ngClass]=\"{'pi': true, 'pi-server': true}\"></i>\n </div>\n </li>\n }\n @if (editorOptions.language == 'sql') {\n <li>\n <div (click)=\"testSql($event, this)\">\n <i [ngClass]=\"{'pi': true, 'pi-verified': true}\"></i>\n </div>\n </li>\n }\n @if (field.mc_suggest_value_callback) {\n <li>\n <div (click)=\"suggest($event, this)\">\n <i [ngClass]=\"{'pi': true, 'pi-question': true}\"></i>\n </div>\n </li>\n }\n @if (isHtmlEditor) {\n <li>\n <div (click)=\"formatHtmlNow($event)\" title=\"Format HTML\">\n <i [ngClass]=\"{'pi': true, 'pi-align-left': true}\"></i>\n </div>\n </li>\n <li>\n <div (click)=\"toggleHtmlPreview($event)\" title=\"Toggle HTML preview\">\n <i [ngClass]=\"{'pi': true, 'pi-eye': showHtmlPreview, 'pi-eye-slash': !showHtmlPreview}\"></i>\n </div>\n </li>\n }\n @if (isJsonEditor) {\n <li>\n <div (click)=\"formatJsonNow($event)\" title=\"Format JSON\">\n <i [ngClass]=\"{'pi': true, 'pi-code': true}\"></i>\n </div>\n </li>\n }\n </ul>\n <div class=\"editor-shell\">\n <div class=\"editor-pane\" [ngClass]=\"{'editor-pane--with-preview': isHtmlEditor && showHtmlPreview}\">\n <ngx-monaco-editor #editorRef [options]=\"editorOptions\" [ngModel]=\"editorModelValue\"\n (ngModelChange)=\"onEditorModelChange($event)\"\n [ngModelOptions]=\"{standalone: true}\"\n [ngStyle]=\"{'left': fullscreen ? (!sqlObjView ? '0px' : '22%') : null, width: '100%' }\"\n style=\"width: 100%; height: 100%;\"\n (onDropIntoEditor)=\"editorOptions.onDropIntoEditor($event)\"></ngx-monaco-editor>\n </div>\n @if (isHtmlEditor && showHtmlPreview) {\n <div class=\"html-preview-pane\">\n <div class=\"html-preview-pane__header\">HTML Pseudo-Preview (sanitized)</div>\n <div class=\"html-preview-pane__body\" [innerHTML]=\"sanitizedHtmlPreview\"></div>\n </div>\n }\n </div>\n </div>\n</div>\n}\n\n@if (editorRef?.editorContent?.nativeElement) {\n<p-contextMenu [target]=\"editorRef?.editorContent?.nativeElement\" [model]=\"editorOptions.contextMenuItems\"\n appendTo=\"body\" />\n}\n", styles: [".editor-btn{color:#fff;list-style-type:none;z-index:2001;visibility:visible;position:absolute;right:10px;top:10px;display:flex;gap:8px;margin:0;padding:0}.editor-btn li{list-style:none}.editor-btn li div{width:24px;height:24px;display:flex;align-items:center;justify-content:center;border:1px solid #334155;border-radius:4px;background:#0f172ad9;cursor:pointer}.fullscreen{position:fixed;inset:16px;z-index:3000;background:#1e1e1e;width:auto;height:auto}.fullscreen .editor-shell{position:absolute;inset:44px 0 0;height:auto}.fullscreen .editor-pane ngx-monaco-editor{position:relative;height:auto!important}.no-full-screen{width:100%;height:200px;position:relative}.editor-container{overflow:visible!important}.editor-shell{display:flex;width:100%;height:100%;min-height:0}.editor-pane{flex:1 1 auto;min-width:0;height:100%}.editor-pane--with-preview{flex:0 0 62%}.html-preview-pane{flex:0 0 38%;min-width:260px;border-left:1px solid #404040;background:#111827;color:#e5e7eb;display:flex;flex-direction:column}.html-preview-pane__header{font-size:12px;letter-spacing:.04em;text-transform:uppercase;padding:10px 12px;border-bottom:1px solid #374151;color:#9ca3af}.html-preview-pane__body{flex:1 1 auto;overflow:auto;padding:12px;background:#fff;color:#111827}:host ::ng-deep .html-preview-pane__body .wuic-preview-component{border:1px solid #cbd5e1;border-left:4px solid #2563eb;border-radius:6px;padding:8px 10px;margin-bottom:10px;background:#f8fafc}:host ::ng-deep .html-preview-pane__body .wuic-preview-component__title{font-weight:600;color:#0f172a;margin-bottom:4px}:host ::ng-deep .html-preview-pane__body .wuic-preview-component__content{margin-top:8px}:host ::ng-deep .html-preview-pane__body .wuic-preview-field__label{display:block;font-size:13px;font-weight:600;color:#0f172a;margin-bottom:6px}:host ::ng-deep .html-preview-pane__body .wuic-preview-field__input{display:block;width:100%;border:1px solid #3b82f6;border-radius:4px;min-height:36px;box-sizing:border-box;background:#fff}:host ::ng-deep .monaco-editor .suggest-widget,:host ::ng-deep .monaco-editor .parameter-hints-widget,:host ::ng-deep .monaco-editor .monaco-hover{z-index:4000!important}:host ::ng-deep .monaco-editor .suggest-widget{height:220px!important;margin-top:-30px!important}:host ::ng-deep .monaco-editor .suggest-widget .tree,:host ::ng-deep .monaco-editor .suggest-widget .monaco-list,:host ::ng-deep .monaco-editor .suggest-widget .monaco-list-rows,:host ::ng-deep .monaco-editor .suggest-widget .monaco-scrollable-element{height:186px!important;max-height:186px!important}:host ::ng-deep .monaco-editor .suggest-widget .monaco-list-rows{box-sizing:border-box;padding-bottom:20px!important}::-webkit-scrollbar{width:12px}::-webkit-scrollbar-track{box-shadow:inset 0 0 5px gray;border-radius:10px}::-webkit-scrollbar-thumb{background:#ffffff80;border-radius:10px;visibility:hidden}::-webkit-scrollbar-thumb:hover{visibility:visible}::-webkit-scrollbar-thumb:hover{background:#fffc}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1$3.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$3.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MonacoEditorModule }, { kind: "component", type: i1.MonacoEditorComponent, selector: "ngx-monaco-editor", inputs: ["options", "uri"], outputs: ["init"] }, { kind: "ngmodule", type: ContextMenuModule }, { kind: "component", type: i14.ContextMenu, selector: "p-contextMenu, p-contextmenu, p-context-menu", inputs: ["model", "triggerEvent", "target", "global", "style", "styleClass", "autoZIndex", "baseZIndex", "id", "breakpoint", "ariaLabel", "ariaLabelledBy", "pressDelay", "appendTo", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: TreeModule }, { kind: "component", type: i4.Tree, selector: "p-tree", inputs: ["value", "selectionMode", "loadingMode", "selection", "styleClass", "contextMenu", "contextMenuSelectionMode", "contextMenuSelection", "draggableScope", "droppableScope", "draggableNodes", "droppableNodes", "metaKeySelection", "propagateSelectionUp", "propagateSelectionDown", "loading", "loadingIcon", "emptyMessage", "ariaLabel", "togglerAriaLabel", "ariaLabelledBy", "validateDrop", "filter", "filterInputAutoFocus", "filterBy", "filterMode", "filterOptions", "filterPlaceholder", "filteredNodes", "filterLocale", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "indentation", "_templateMap", "trackBy", "highlightOnSelect"], outputs: ["selectionChange", "contextMenuSelectionChange", "onNodeSelect", "onNodeUnselect", "onNodeExpand", "onNodeCollapse", "onNodeContextMenuSelect", "onNodeDoubleClick", "onNodeDrop", "onLazyLoad", "onScroll", "onScrollIndexChange", "onFilter"] }] });
|
|
4234
|
+
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CodeEditorComponent, deps: [{ token: i1$1.MonacoEditorLoaderService }, { token: i1$2.HttpClient }, { token: MetadataProviderService }, { token: UserInfoService }, { token: DataProviderService }, { token: WtoolboxService }, { token: i1$3.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component });
|
|
4235
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.2.9", type: CodeEditorComponent, isStandalone: true, selector: "wuic-code-editor", inputs: { field: "field", record: "record", metaInfo: "metaInfo", jsonTreeToggle: "jsonTreeToggle" }, host: { properties: { "style": "this.style" } }, viewQueries: [{ propertyName: "contextMenuAnchor", first: true, predicate: ["contextMenuAnchor"], descendants: true }, { propertyName: "editorRef", first: true, predicate: ["editorRef"], descendants: true }, { propertyName: "ctxs", first: true, predicate: ["ctxs"], descendants: true }], ngImport: i0, template: "@if (render) {\n<div [ngClass]=\"{'fullscreen': fullscreen, 'no-full-screen': !fullscreen }\">\n <div\n [ngStyle]=\"{width: sqlObjView ? '22%' : null, display: sqlObjView ? null : 'none', position: fullscreen ? 'absolute' : null, 'left': fullscreen ? '0px' : null, 'top': fullscreen ? '0px' : null }\"\n style=\"float: left; height: 100%; overflow: auto; background-color: #1e1e1e; z-index: 2000;\">\n <p-tree [value]=\"primeTreeNodes\">\n <ng-template let-node pTemplate=\"default\">\n <span style=\"-webkit-user-select: none; -ms-user-select: none; user-select: none;\" draggable=\"true\"\n (dragstart)=\"onTreeNodeDragStart($event, node.data)\" (click)=\"editorOptions.onNodeClick($event, node.data)\"\n (dragend)=\"onTreeNodeDragEnd($event, node.data)\">\n <span>\n {{ node.label }}\n </span>\n </span>\n </ng-template>\n </p-tree>\n </div>\n <div [ngStyle]=\"{width: sqlObjView ? '78%' : '100%', 'left': fullscreen ? (!sqlObjView ? '0px' : '22%') : null }\"\n style=\"height: 100%; float: left;\">\n <ul class=\"editor-btn\">\n <li>\n <div (click)=\"setFullScreen($event, this)\">\n <i\n [ngClass]=\"{'pi': true, 'pi-window-maximize': fullscreen == false, 'pi-window-minimize': fullscreen == true}\"></i>\n </div>\n </li>\n @if (editorOptions.language == 'sql') {\n <li>\n <div (click)=\"toggleSqlObjView($event, this)\">\n <i [ngClass]=\"{'pi': true, 'pi-server': true}\"></i>\n </div>\n </li>\n }\n @if (editorOptions.language == 'sql') {\n <li>\n <div (click)=\"testSql($event, this)\">\n <i [ngClass]=\"{'pi': true, 'pi-verified': true}\"></i>\n </div>\n </li>\n }\n @if (field.mc_suggest_value_callback) {\n <li>\n <div (click)=\"suggest($event, this)\">\n <i [ngClass]=\"{'pi': true, 'pi-question': true}\"></i>\n </div>\n </li>\n }\n @if (isHtmlEditor) {\n <li>\n <div (click)=\"formatHtmlNow($event)\" title=\"Format HTML\">\n <i [ngClass]=\"{'pi': true, 'pi-align-left': true}\"></i>\n </div>\n </li>\n <li>\n <div (click)=\"toggleHtmlPreview($event)\" title=\"Toggle HTML preview\">\n <i [ngClass]=\"{'pi': true, 'pi-eye': showHtmlPreview, 'pi-eye-slash': !showHtmlPreview}\"></i>\n </div>\n </li>\n }\n @if (isJsonEditor) {\n <li>\n <div (click)=\"formatJsonNow($event)\" title=\"Format JSON\">\n <i [ngClass]=\"{'pi': true, 'pi-code': true}\"></i>\n </div>\n </li>\n }\n @if (isJsonEditor && jsonTreeToggle) {\n <li>\n <div (click)=\"toggleJsonTree($event)\" [title]=\"treeViewActive ? 'Codice' : 'Struttura'\">\n <i [ngClass]=\"{'pi': true, 'pi-sitemap': !treeViewActive, 'pi-pencil': treeViewActive}\"></i>\n </div>\n </li>\n }\n </ul>\n <div class=\"editor-shell\">\n <!-- Monaco resta VIVO anche in vista struttura (solo nascosto): il model\n e il record vengono riscritti a ogni modifica della struttura. -->\n <div class=\"editor-pane\" [ngClass]=\"{'editor-pane--with-preview': isHtmlEditor && showHtmlPreview}\"\n [style.display]=\"treeViewActive ? 'none' : null\">\n <ngx-monaco-editor #editorRef [options]=\"editorOptions\" [ngModel]=\"editorModelValue\"\n (ngModelChange)=\"onEditorModelChange($event)\"\n [ngModelOptions]=\"{standalone: true}\"\n [ngStyle]=\"{'left': fullscreen ? (!sqlObjView ? '0px' : '22%') : null, width: '100%' }\"\n style=\"width: 100%; height: 100%;\"\n (onDropIntoEditor)=\"editorOptions.onDropIntoEditor($event)\"></ngx-monaco-editor>\n </div>\n @if (treeViewActive) {\n <div class=\"editor-pane\">\n <wuic-json-schema-tree-editor\n [schema]=\"jsonTreeSchema\"\n [value]=\"treeValue\"\n (valueChange)=\"onTreeValueChange($event)\" />\n </div>\n }\n @if (isHtmlEditor && showHtmlPreview) {\n <div class=\"html-preview-pane\">\n <div class=\"html-preview-pane__header\">HTML Pseudo-Preview (sanitized)</div>\n <div class=\"html-preview-pane__body\" [innerHTML]=\"sanitizedHtmlPreview\"></div>\n </div>\n }\n </div>\n </div>\n</div>\n} @else {\n <!-- Monaco viene inizializzato in modo asincrono (loader + registrazione\n language provider) DOPO che il @defer del code-area-editor ha gia'\n terminato il fetch del chunk: senza questo placeholder la sezione\n collasserebbe a nulla in quel gap. Riserva l'altezza dell'editor\n (200px, come .no-full-screen) per evitare il salto di layout. -->\n <div class=\"code-editor-monaco-loading\">\n <i class=\"pi pi-spin pi-spinner\"></i> Inizializzazione editor\u2026\n </div>\n}\n\n@if (editorRef?.editorContent?.nativeElement) {\n<p-contextMenu [target]=\"editorRef?.editorContent?.nativeElement\" [model]=\"editorOptions.contextMenuItems\"\n appendTo=\"body\" />\n}\n", styles: [".editor-btn{color:#fff;list-style-type:none;z-index:2001;visibility:visible;position:absolute;right:10px;top:10px;display:flex;gap:8px;margin:0;padding:0}.editor-btn li{list-style:none}.editor-btn li div{width:24px;height:24px;display:flex;align-items:center;justify-content:center;border:1px solid #334155;border-radius:4px;background:#0f172ad9;cursor:pointer}.fullscreen{position:fixed;inset:16px;z-index:3000;background:#1e1e1e;width:auto;height:auto}.fullscreen .editor-shell{position:absolute;inset:44px 0 0;height:auto}.fullscreen .editor-pane ngx-monaco-editor{position:relative;height:auto!important}.no-full-screen{width:100%;height:200px;position:relative}.editor-container{overflow:visible!important}.editor-shell{display:flex;width:100%;height:100%;min-height:0}.editor-pane{flex:1 1 auto;min-width:0;height:100%}.editor-pane--with-preview{flex:0 0 62%}.code-editor-monaco-loading{display:flex;align-items:center;justify-content:center;gap:8px;height:200px;color:#64748b;font-size:.9rem;background:#f1f5f9;border:1px dashed #cbd5e1;border-radius:6px}.code-editor-monaco-loading .pi-spinner{font-size:1rem}.html-preview-pane{flex:0 0 38%;min-width:260px;border-left:1px solid #404040;background:#111827;color:#e5e7eb;display:flex;flex-direction:column}.html-preview-pane__header{font-size:12px;letter-spacing:.04em;text-transform:uppercase;padding:10px 12px;border-bottom:1px solid #374151;color:#9ca3af}.html-preview-pane__body{flex:1 1 auto;overflow:auto;padding:12px;background:#fff;color:#111827}:host ::ng-deep .html-preview-pane__body .wuic-preview-component{border:1px solid #cbd5e1;border-left:4px solid #2563eb;border-radius:6px;padding:8px 10px;margin-bottom:10px;background:#f8fafc}:host ::ng-deep .html-preview-pane__body .wuic-preview-component__title{font-weight:600;color:#0f172a;margin-bottom:4px}:host ::ng-deep .html-preview-pane__body .wuic-preview-component__content{margin-top:8px}:host ::ng-deep .html-preview-pane__body .wuic-preview-field__label{display:block;font-size:13px;font-weight:600;color:#0f172a;margin-bottom:6px}:host ::ng-deep .html-preview-pane__body .wuic-preview-field__input{display:block;width:100%;border:1px solid #3b82f6;border-radius:4px;min-height:36px;box-sizing:border-box;background:#fff}:host ::ng-deep .monaco-editor .suggest-widget,:host ::ng-deep .monaco-editor .parameter-hints-widget,:host ::ng-deep .monaco-editor .monaco-hover{z-index:4000!important}:host ::ng-deep .monaco-editor .suggest-widget{height:220px!important;margin-top:-30px!important}:host ::ng-deep .monaco-editor .suggest-widget .tree,:host ::ng-deep .monaco-editor .suggest-widget .monaco-list,:host ::ng-deep .monaco-editor .suggest-widget .monaco-list-rows,:host ::ng-deep .monaco-editor .suggest-widget .monaco-scrollable-element{height:186px!important;max-height:186px!important}:host ::ng-deep .monaco-editor .suggest-widget .monaco-list-rows{box-sizing:border-box;padding-bottom:20px!important}::-webkit-scrollbar{width:12px}::-webkit-scrollbar-track{box-shadow:inset 0 0 5px gray;border-radius:10px}::-webkit-scrollbar-thumb{background:#ffffff80;border-radius:10px;visibility:hidden}::-webkit-scrollbar-thumb:hover{visibility:visible}::-webkit-scrollbar-thumb:hover{background:#fffc}\n"], dependencies: [{ kind: "directive", type: NgClass, selector: "[ngClass]", inputs: ["class", "ngClass"] }, { kind: "directive", type: NgStyle, selector: "[ngStyle]", inputs: ["ngStyle"] }, { kind: "ngmodule", type: FormsModule }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgModel, selector: "[ngModel]:not([formControlName]):not([formControl])", inputs: ["name", "disabled", "ngModel", "ngModelOptions"], outputs: ["ngModelChange"], exportAs: ["ngModel"] }, { kind: "ngmodule", type: MonacoEditorModule }, { kind: "component", type: i1$1.MonacoEditorComponent, selector: "ngx-monaco-editor", inputs: ["options", "uri"], outputs: ["init"] }, { kind: "ngmodule", type: ContextMenuModule }, { kind: "component", type: i10.ContextMenu, selector: "p-contextMenu, p-contextmenu, p-context-menu", inputs: ["model", "triggerEvent", "target", "global", "style", "styleClass", "autoZIndex", "baseZIndex", "id", "breakpoint", "ariaLabel", "ariaLabelledBy", "pressDelay", "appendTo", "motionOptions"], outputs: ["onShow", "onHide"] }, { kind: "directive", type: i3.PrimeTemplate, selector: "[pTemplate]", inputs: ["type", "pTemplate"] }, { kind: "ngmodule", type: TreeModule }, { kind: "component", type: i4.Tree, selector: "p-tree", inputs: ["value", "selectionMode", "loadingMode", "selection", "styleClass", "contextMenu", "contextMenuSelectionMode", "contextMenuSelection", "draggableScope", "droppableScope", "draggableNodes", "droppableNodes", "metaKeySelection", "propagateSelectionUp", "propagateSelectionDown", "loading", "loadingIcon", "emptyMessage", "ariaLabel", "togglerAriaLabel", "ariaLabelledBy", "validateDrop", "filter", "filterInputAutoFocus", "filterBy", "filterMode", "filterOptions", "filterPlaceholder", "filteredNodes", "filterLocale", "scrollHeight", "lazy", "virtualScroll", "virtualScrollItemSize", "virtualScrollOptions", "indentation", "_templateMap", "trackBy", "highlightOnSelect"], outputs: ["selectionChange", "contextMenuSelectionChange", "onNodeSelect", "onNodeUnselect", "onNodeExpand", "onNodeCollapse", "onNodeContextMenuSelect", "onNodeDoubleClick", "onNodeDrop", "onLazyLoad", "onScroll", "onScrollIndexChange", "onFilter"] }, { kind: "component", type: JsonSchemaTreeEditorComponent, selector: "wuic-json-schema-tree-editor", inputs: ["schema", "value"], outputs: ["valueChange"] }] });
|
|
3974
4236
|
}
|
|
3975
4237
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CodeEditorComponent, decorators: [{
|
|
3976
4238
|
type: Component,
|
|
3977
|
-
args: [{ selector: 'wuic-code-editor', imports: [NgClass, NgStyle, FormsModule, MonacoEditorModule, ContextMenuModule, TreeModule], template: "@if (render) {\n<div [ngClass]=\"{'fullscreen': fullscreen, 'no-full-screen': !fullscreen }\">\n <div\n [ngStyle]=\"{width: sqlObjView ? '22%' : null, display: sqlObjView ? null : 'none', position: fullscreen ? 'absolute' : null, 'left': fullscreen ? '0px' : null, 'top': fullscreen ? '0px' : null }\"\n style=\"float: left; height: 100%; overflow: auto; background-color: #1e1e1e; z-index: 2000;\">\n <p-tree [value]=\"primeTreeNodes\">\n <ng-template let-node pTemplate=\"default\">\n <span style=\"-webkit-user-select: none; -ms-user-select: none; user-select: none;\" draggable=\"true\"\n (dragstart)=\"onTreeNodeDragStart($event, node.data)\" (click)=\"editorOptions.onNodeClick($event, node.data)\"\n (dragend)=\"onTreeNodeDragEnd($event, node.data)\">\n <span>\n {{ node.label }}\n </span>\n </span>\n </ng-template>\n </p-tree>\n </div>\n <div [ngStyle]=\"{width: sqlObjView ? '78%' : '100%', 'left': fullscreen ? (!sqlObjView ? '0px' : '22%') : null }\"\n style=\"height: 100%; float: left;\">\n <ul class=\"editor-btn\">\n <li>\n <div (click)=\"setFullScreen($event, this)\">\n <i\n [ngClass]=\"{'pi': true, 'pi-window-maximize': fullscreen == false, 'pi-window-minimize': fullscreen == true}\"></i>\n </div>\n </li>\n @if (editorOptions.language == 'sql') {\n <li>\n <div (click)=\"toggleSqlObjView($event, this)\">\n <i [ngClass]=\"{'pi': true, 'pi-server': true}\"></i>\n </div>\n </li>\n }\n @if (editorOptions.language == 'sql') {\n <li>\n <div (click)=\"testSql($event, this)\">\n <i [ngClass]=\"{'pi': true, 'pi-verified': true}\"></i>\n </div>\n </li>\n }\n @if (field.mc_suggest_value_callback) {\n <li>\n <div (click)=\"suggest($event, this)\">\n <i [ngClass]=\"{'pi': true, 'pi-question': true}\"></i>\n </div>\n </li>\n }\n @if (isHtmlEditor) {\n <li>\n <div (click)=\"formatHtmlNow($event)\" title=\"Format HTML\">\n <i [ngClass]=\"{'pi': true, 'pi-align-left': true}\"></i>\n </div>\n </li>\n <li>\n <div (click)=\"toggleHtmlPreview($event)\" title=\"Toggle HTML preview\">\n <i [ngClass]=\"{'pi': true, 'pi-eye': showHtmlPreview, 'pi-eye-slash': !showHtmlPreview}\"></i>\n </div>\n </li>\n }\n @if (isJsonEditor) {\n <li>\n <div (click)=\"formatJsonNow($event)\" title=\"Format JSON\">\n <i [ngClass]=\"{'pi': true, 'pi-code': true}\"></i>\n </div>\n </li>\n }\n </ul>\n <div class=\"editor-shell\">\n <div class=\"editor-pane\" [ngClass]=\"{'editor-pane--with-preview': isHtmlEditor && showHtmlPreview}\">\n <ngx-monaco-editor #editorRef [options]=\"editorOptions\" [ngModel]=\"editorModelValue\"\n (ngModelChange)=\"onEditorModelChange($event)\"\n [ngModelOptions]=\"{standalone: true}\"\n [ngStyle]=\"{'left': fullscreen ? (!sqlObjView ? '0px' : '22%') : null, width: '100%' }\"\n style=\"width: 100%; height: 100%;\"\n (onDropIntoEditor)=\"editorOptions.onDropIntoEditor($event)\"></ngx-monaco-editor>\n </div>\n @if (isHtmlEditor && showHtmlPreview) {\n <div class=\"html-preview-pane\">\n <div class=\"html-preview-pane__header\">HTML Pseudo-Preview (sanitized)</div>\n <div class=\"html-preview-pane__body\" [innerHTML]=\"sanitizedHtmlPreview\"></div>\n </div>\n }\n </div>\n </div>\n</div>\n}\n\n@if (editorRef?.editorContent?.nativeElement) {\n<p-contextMenu [target]=\"editorRef?.editorContent?.nativeElement\" [model]=\"editorOptions.contextMenuItems\"\n appendTo=\"body\" />\n}\n", styles: [".editor-btn{color:#fff;list-style-type:none;z-index:2001;visibility:visible;position:absolute;right:10px;top:10px;display:flex;gap:8px;margin:0;padding:0}.editor-btn li{list-style:none}.editor-btn li div{width:24px;height:24px;display:flex;align-items:center;justify-content:center;border:1px solid #334155;border-radius:4px;background:#0f172ad9;cursor:pointer}.fullscreen{position:fixed;inset:16px;z-index:3000;background:#1e1e1e;width:auto;height:auto}.fullscreen .editor-shell{position:absolute;inset:44px 0 0;height:auto}.fullscreen .editor-pane ngx-monaco-editor{position:relative;height:auto!important}.no-full-screen{width:100%;height:200px;position:relative}.editor-container{overflow:visible!important}.editor-shell{display:flex;width:100%;height:100%;min-height:0}.editor-pane{flex:1 1 auto;min-width:0;height:100%}.editor-pane--with-preview{flex:0 0 62%}.html-preview-pane{flex:0 0 38%;min-width:260px;border-left:1px solid #404040;background:#111827;color:#e5e7eb;display:flex;flex-direction:column}.html-preview-pane__header{font-size:12px;letter-spacing:.04em;text-transform:uppercase;padding:10px 12px;border-bottom:1px solid #374151;color:#9ca3af}.html-preview-pane__body{flex:1 1 auto;overflow:auto;padding:12px;background:#fff;color:#111827}:host ::ng-deep .html-preview-pane__body .wuic-preview-component{border:1px solid #cbd5e1;border-left:4px solid #2563eb;border-radius:6px;padding:8px 10px;margin-bottom:10px;background:#f8fafc}:host ::ng-deep .html-preview-pane__body .wuic-preview-component__title{font-weight:600;color:#0f172a;margin-bottom:4px}:host ::ng-deep .html-preview-pane__body .wuic-preview-component__content{margin-top:8px}:host ::ng-deep .html-preview-pane__body .wuic-preview-field__label{display:block;font-size:13px;font-weight:600;color:#0f172a;margin-bottom:6px}:host ::ng-deep .html-preview-pane__body .wuic-preview-field__input{display:block;width:100%;border:1px solid #3b82f6;border-radius:4px;min-height:36px;box-sizing:border-box;background:#fff}:host ::ng-deep .monaco-editor .suggest-widget,:host ::ng-deep .monaco-editor .parameter-hints-widget,:host ::ng-deep .monaco-editor .monaco-hover{z-index:4000!important}:host ::ng-deep .monaco-editor .suggest-widget{height:220px!important;margin-top:-30px!important}:host ::ng-deep .monaco-editor .suggest-widget .tree,:host ::ng-deep .monaco-editor .suggest-widget .monaco-list,:host ::ng-deep .monaco-editor .suggest-widget .monaco-list-rows,:host ::ng-deep .monaco-editor .suggest-widget .monaco-scrollable-element{height:186px!important;max-height:186px!important}:host ::ng-deep .monaco-editor .suggest-widget .monaco-list-rows{box-sizing:border-box;padding-bottom:20px!important}::-webkit-scrollbar{width:12px}::-webkit-scrollbar-track{box-shadow:inset 0 0 5px gray;border-radius:10px}::-webkit-scrollbar-thumb{background:#ffffff80;border-radius:10px;visibility:hidden}::-webkit-scrollbar-thumb:hover{visibility:visible}::-webkit-scrollbar-thumb:hover{background:#fffc}\n"] }]
|
|
3978
|
-
}], ctorParameters: () => [{ type: i1.MonacoEditorLoaderService }, { type: i1$
|
|
4239
|
+
args: [{ selector: 'wuic-code-editor', imports: [NgClass, NgStyle, FormsModule, MonacoEditorModule, ContextMenuModule, TreeModule, JsonSchemaTreeEditorComponent], template: "@if (render) {\n<div [ngClass]=\"{'fullscreen': fullscreen, 'no-full-screen': !fullscreen }\">\n <div\n [ngStyle]=\"{width: sqlObjView ? '22%' : null, display: sqlObjView ? null : 'none', position: fullscreen ? 'absolute' : null, 'left': fullscreen ? '0px' : null, 'top': fullscreen ? '0px' : null }\"\n style=\"float: left; height: 100%; overflow: auto; background-color: #1e1e1e; z-index: 2000;\">\n <p-tree [value]=\"primeTreeNodes\">\n <ng-template let-node pTemplate=\"default\">\n <span style=\"-webkit-user-select: none; -ms-user-select: none; user-select: none;\" draggable=\"true\"\n (dragstart)=\"onTreeNodeDragStart($event, node.data)\" (click)=\"editorOptions.onNodeClick($event, node.data)\"\n (dragend)=\"onTreeNodeDragEnd($event, node.data)\">\n <span>\n {{ node.label }}\n </span>\n </span>\n </ng-template>\n </p-tree>\n </div>\n <div [ngStyle]=\"{width: sqlObjView ? '78%' : '100%', 'left': fullscreen ? (!sqlObjView ? '0px' : '22%') : null }\"\n style=\"height: 100%; float: left;\">\n <ul class=\"editor-btn\">\n <li>\n <div (click)=\"setFullScreen($event, this)\">\n <i\n [ngClass]=\"{'pi': true, 'pi-window-maximize': fullscreen == false, 'pi-window-minimize': fullscreen == true}\"></i>\n </div>\n </li>\n @if (editorOptions.language == 'sql') {\n <li>\n <div (click)=\"toggleSqlObjView($event, this)\">\n <i [ngClass]=\"{'pi': true, 'pi-server': true}\"></i>\n </div>\n </li>\n }\n @if (editorOptions.language == 'sql') {\n <li>\n <div (click)=\"testSql($event, this)\">\n <i [ngClass]=\"{'pi': true, 'pi-verified': true}\"></i>\n </div>\n </li>\n }\n @if (field.mc_suggest_value_callback) {\n <li>\n <div (click)=\"suggest($event, this)\">\n <i [ngClass]=\"{'pi': true, 'pi-question': true}\"></i>\n </div>\n </li>\n }\n @if (isHtmlEditor) {\n <li>\n <div (click)=\"formatHtmlNow($event)\" title=\"Format HTML\">\n <i [ngClass]=\"{'pi': true, 'pi-align-left': true}\"></i>\n </div>\n </li>\n <li>\n <div (click)=\"toggleHtmlPreview($event)\" title=\"Toggle HTML preview\">\n <i [ngClass]=\"{'pi': true, 'pi-eye': showHtmlPreview, 'pi-eye-slash': !showHtmlPreview}\"></i>\n </div>\n </li>\n }\n @if (isJsonEditor) {\n <li>\n <div (click)=\"formatJsonNow($event)\" title=\"Format JSON\">\n <i [ngClass]=\"{'pi': true, 'pi-code': true}\"></i>\n </div>\n </li>\n }\n @if (isJsonEditor && jsonTreeToggle) {\n <li>\n <div (click)=\"toggleJsonTree($event)\" [title]=\"treeViewActive ? 'Codice' : 'Struttura'\">\n <i [ngClass]=\"{'pi': true, 'pi-sitemap': !treeViewActive, 'pi-pencil': treeViewActive}\"></i>\n </div>\n </li>\n }\n </ul>\n <div class=\"editor-shell\">\n <!-- Monaco resta VIVO anche in vista struttura (solo nascosto): il model\n e il record vengono riscritti a ogni modifica della struttura. -->\n <div class=\"editor-pane\" [ngClass]=\"{'editor-pane--with-preview': isHtmlEditor && showHtmlPreview}\"\n [style.display]=\"treeViewActive ? 'none' : null\">\n <ngx-monaco-editor #editorRef [options]=\"editorOptions\" [ngModel]=\"editorModelValue\"\n (ngModelChange)=\"onEditorModelChange($event)\"\n [ngModelOptions]=\"{standalone: true}\"\n [ngStyle]=\"{'left': fullscreen ? (!sqlObjView ? '0px' : '22%') : null, width: '100%' }\"\n style=\"width: 100%; height: 100%;\"\n (onDropIntoEditor)=\"editorOptions.onDropIntoEditor($event)\"></ngx-monaco-editor>\n </div>\n @if (treeViewActive) {\n <div class=\"editor-pane\">\n <wuic-json-schema-tree-editor\n [schema]=\"jsonTreeSchema\"\n [value]=\"treeValue\"\n (valueChange)=\"onTreeValueChange($event)\" />\n </div>\n }\n @if (isHtmlEditor && showHtmlPreview) {\n <div class=\"html-preview-pane\">\n <div class=\"html-preview-pane__header\">HTML Pseudo-Preview (sanitized)</div>\n <div class=\"html-preview-pane__body\" [innerHTML]=\"sanitizedHtmlPreview\"></div>\n </div>\n }\n </div>\n </div>\n</div>\n} @else {\n <!-- Monaco viene inizializzato in modo asincrono (loader + registrazione\n language provider) DOPO che il @defer del code-area-editor ha gia'\n terminato il fetch del chunk: senza questo placeholder la sezione\n collasserebbe a nulla in quel gap. Riserva l'altezza dell'editor\n (200px, come .no-full-screen) per evitare il salto di layout. -->\n <div class=\"code-editor-monaco-loading\">\n <i class=\"pi pi-spin pi-spinner\"></i> Inizializzazione editor\u2026\n </div>\n}\n\n@if (editorRef?.editorContent?.nativeElement) {\n<p-contextMenu [target]=\"editorRef?.editorContent?.nativeElement\" [model]=\"editorOptions.contextMenuItems\"\n appendTo=\"body\" />\n}\n", styles: [".editor-btn{color:#fff;list-style-type:none;z-index:2001;visibility:visible;position:absolute;right:10px;top:10px;display:flex;gap:8px;margin:0;padding:0}.editor-btn li{list-style:none}.editor-btn li div{width:24px;height:24px;display:flex;align-items:center;justify-content:center;border:1px solid #334155;border-radius:4px;background:#0f172ad9;cursor:pointer}.fullscreen{position:fixed;inset:16px;z-index:3000;background:#1e1e1e;width:auto;height:auto}.fullscreen .editor-shell{position:absolute;inset:44px 0 0;height:auto}.fullscreen .editor-pane ngx-monaco-editor{position:relative;height:auto!important}.no-full-screen{width:100%;height:200px;position:relative}.editor-container{overflow:visible!important}.editor-shell{display:flex;width:100%;height:100%;min-height:0}.editor-pane{flex:1 1 auto;min-width:0;height:100%}.editor-pane--with-preview{flex:0 0 62%}.code-editor-monaco-loading{display:flex;align-items:center;justify-content:center;gap:8px;height:200px;color:#64748b;font-size:.9rem;background:#f1f5f9;border:1px dashed #cbd5e1;border-radius:6px}.code-editor-monaco-loading .pi-spinner{font-size:1rem}.html-preview-pane{flex:0 0 38%;min-width:260px;border-left:1px solid #404040;background:#111827;color:#e5e7eb;display:flex;flex-direction:column}.html-preview-pane__header{font-size:12px;letter-spacing:.04em;text-transform:uppercase;padding:10px 12px;border-bottom:1px solid #374151;color:#9ca3af}.html-preview-pane__body{flex:1 1 auto;overflow:auto;padding:12px;background:#fff;color:#111827}:host ::ng-deep .html-preview-pane__body .wuic-preview-component{border:1px solid #cbd5e1;border-left:4px solid #2563eb;border-radius:6px;padding:8px 10px;margin-bottom:10px;background:#f8fafc}:host ::ng-deep .html-preview-pane__body .wuic-preview-component__title{font-weight:600;color:#0f172a;margin-bottom:4px}:host ::ng-deep .html-preview-pane__body .wuic-preview-component__content{margin-top:8px}:host ::ng-deep .html-preview-pane__body .wuic-preview-field__label{display:block;font-size:13px;font-weight:600;color:#0f172a;margin-bottom:6px}:host ::ng-deep .html-preview-pane__body .wuic-preview-field__input{display:block;width:100%;border:1px solid #3b82f6;border-radius:4px;min-height:36px;box-sizing:border-box;background:#fff}:host ::ng-deep .monaco-editor .suggest-widget,:host ::ng-deep .monaco-editor .parameter-hints-widget,:host ::ng-deep .monaco-editor .monaco-hover{z-index:4000!important}:host ::ng-deep .monaco-editor .suggest-widget{height:220px!important;margin-top:-30px!important}:host ::ng-deep .monaco-editor .suggest-widget .tree,:host ::ng-deep .monaco-editor .suggest-widget .monaco-list,:host ::ng-deep .monaco-editor .suggest-widget .monaco-list-rows,:host ::ng-deep .monaco-editor .suggest-widget .monaco-scrollable-element{height:186px!important;max-height:186px!important}:host ::ng-deep .monaco-editor .suggest-widget .monaco-list-rows{box-sizing:border-box;padding-bottom:20px!important}::-webkit-scrollbar{width:12px}::-webkit-scrollbar-track{box-shadow:inset 0 0 5px gray;border-radius:10px}::-webkit-scrollbar-thumb{background:#ffffff80;border-radius:10px;visibility:hidden}::-webkit-scrollbar-thumb:hover{visibility:visible}::-webkit-scrollbar-thumb:hover{background:#fffc}\n"] }]
|
|
4240
|
+
}], ctorParameters: () => [{ type: i1$1.MonacoEditorLoaderService }, { type: i1$2.HttpClient }, { type: MetadataProviderService }, { type: UserInfoService }, { type: DataProviderService }, { type: WtoolboxService }, { type: i1$3.DomSanitizer }], propDecorators: { style: [{
|
|
3979
4241
|
type: HostBinding,
|
|
3980
4242
|
args: ['style']
|
|
3981
4243
|
}], contextMenuAnchor: [{
|
|
@@ -3993,7 +4255,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
|
|
|
3993
4255
|
}], ctxs: [{
|
|
3994
4256
|
type: ViewChild,
|
|
3995
4257
|
args: ['ctxs']
|
|
4258
|
+
}], jsonTreeToggle: [{
|
|
4259
|
+
type: Input
|
|
3996
4260
|
}] } });
|
|
3997
4261
|
|
|
3998
4262
|
export { CodeEditorComponent };
|
|
3999
|
-
//# sourceMappingURL=wuic-framework-lib-code-editor.component-
|
|
4263
|
+
//# sourceMappingURL=wuic-framework-lib-code-editor.component-C21mvjyr.mjs.map
|