wuic-framework-lib 1.3.2 → 1.7.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.
Files changed (27) hide show
  1. package/fesm2022/{wuic-framework-lib-chart-list.component-DAP-TPJR.mjs → wuic-framework-lib-chart-list.component-Bl424n7x.mjs} +49 -37
  2. package/fesm2022/{wuic-framework-lib-code-editor.component-CLMDvOWs.mjs → wuic-framework-lib-code-editor.component-N6HMl2mf.mjs} +441 -277
  3. package/fesm2022/{wuic-framework-lib-designer.component-DA7abiLW.mjs → wuic-framework-lib-designer.component-Bd2fwl6H.mjs} +1948 -641
  4. package/fesm2022/{wuic-framework-lib-first-run-wizard.component-BLrUrfZ9.mjs → wuic-framework-lib-first-run-wizard.component-NN6cWVHL.mjs} +18 -20
  5. package/fesm2022/{wuic-framework-lib-framework-docs.component-DphKhTef.mjs → wuic-framework-lib-framework-docs.component-B867JAYe.mjs} +4205 -380
  6. package/fesm2022/{wuic-framework-lib-pivot-builder.component-BqUUwrJM.mjs → wuic-framework-lib-pivot-builder.component-DWukH0L-.mjs} +578 -66
  7. package/fesm2022/{wuic-framework-lib-prompt-dialog-fallback-host.component-DZrhwMH5.mjs → wuic-framework-lib-prompt-dialog-fallback-host.component-DWO1Rcgv.mjs} +2 -2
  8. package/fesm2022/wuic-framework-lib-report-designer.component-QcrU81m6.mjs +380 -0
  9. package/fesm2022/wuic-framework-lib-report-scaffold-dialog.component-U-zdOoRV.mjs +431 -0
  10. package/fesm2022/{wuic-framework-lib-report-viewer.component-CIN2fY0P.mjs → wuic-framework-lib-report-viewer.component-B4LhA3SL.mjs} +8 -13
  11. package/fesm2022/wuic-framework-lib-scene3d-designer.component-DjOfzKLo.mjs +4813 -0
  12. package/fesm2022/wuic-framework-lib-scene3d-light-baker-gpu-C96T9uIW.mjs +303 -0
  13. package/fesm2022/wuic-framework-lib-scene3d-shader-effect-DjHyCAFK.mjs +2807 -0
  14. package/fesm2022/wuic-framework-lib-scene3d-viewer.component-Dboz1fjl.mjs +1130 -0
  15. package/fesm2022/{wuic-framework-lib-scheduler-list.component-CdcI1Uor.mjs → wuic-framework-lib-scheduler-list.component--wY21R3o.mjs} +169 -53
  16. package/fesm2022/{wuic-framework-lib-spreadsheet-list-sf.component-j1HTRI_P.mjs → wuic-framework-lib-spreadsheet-list-sf.component-Ek30J8v-.mjs} +147 -106
  17. package/fesm2022/{wuic-framework-lib-stimulsoft-license.service-BIyxB4pO.mjs → wuic-framework-lib-stimulsoft-license.service-CsNNSFYs.mjs} +3 -3
  18. package/fesm2022/wuic-framework-lib-timeline-list.component-aqCH4P0G.mjs +805 -0
  19. package/fesm2022/wuic-framework-lib-workflow-designer.component-DMM8BeXm.mjs +9504 -0
  20. package/fesm2022/{wuic-framework-lib-wuic-framework-lib-BRujEwpR.mjs → wuic-framework-lib-wuic-framework-lib-dfLTqam5.mjs} +14713 -8403
  21. package/fesm2022/wuic-framework-lib.mjs +1 -1
  22. package/package.json +5 -2
  23. package/styles/_wuic-tokens.scss +82 -0
  24. package/styles/styles.scss +160 -0
  25. package/types/wuic-framework-lib.d.ts +5971 -3666
  26. package/fesm2022/wuic-framework-lib-report-designer.component-D_qbefud.mjs +0 -194
  27. package/fesm2022/wuic-framework-lib-workflow-designer.component-SE_7ZogW.mjs +0 -5114
@@ -1,22 +1,22 @@
1
1
  import * as i0 from '@angular/core';
2
- import { inject, ElementRef, SecurityContext, ViewChild, Input, HostBinding, Component } from '@angular/core';
3
- import * as i1$3 from '@angular/forms';
2
+ import { EventEmitter, Output, Input, Component, inject, ElementRef, NgZone, ChangeDetectorRef, 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-BRujEwpR.mjs';
10
- import { NgClass, NgStyle } from '@angular/common';
9
+ import { W as WtoolboxService, M as MetadataProviderService, g as MetadatiColonna, o as MetaInfo, U as UserInfoService, h as DataProviderService } from './wuic-framework-lib-wuic-framework-lib-dfLTqam5.mjs';
10
+ import { NgTemplateOutlet, NgClass, NgStyle } from '@angular/common';
11
11
  import * as i14 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$1 from '@angular/common/http';
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$2 from '@angular/platform-browser';
19
+ import * as i1$3 from '@angular/platform-browser';
20
20
  import * as i3 from 'primeng/api';
21
21
 
22
22
  class SqlModel {
@@ -92,9 +92,6 @@ class Statement {
92
92
  }
93
93
  }
94
94
 
95
- // import { editor } from 'monaco-editor';
96
- // import { LinkedList } from 'monaco-editor/esm/vs/base/common/linkedList';
97
- // import { MenuId, MenuRegistry } from 'monaco-editor/esm/vs/platform/actions/common/actions';
98
95
  class SqlProvider {
99
96
  http;
100
97
  currents;
@@ -124,8 +121,6 @@ class SqlProvider {
124
121
  this.editor = editor;
125
122
  this.editor['_onDropIntoEditor'] = this.editor['_register'](new DragDropInteractionEmitter$1(this.editor['_contributions'], this.editor['_deliveryQueue'], this.editor, this));
126
123
  this.editor['onDropIntoEditor'] = this.editor['_onDropIntoEditor'].event;
127
- // this._onContextMenu = this._register(new InteractionEmitter(this._contributions, this._deliveryQueue));
128
- // this.onContextMenu = this._onContextMenu.event;
129
124
  this.editor['_onContextMenu'] = this.editor['_register'](new ContextMenuInteractionEmitter$1(this.editor['_contributions'], this.editor['_deliveryQueue'], this.editor, this));
130
125
  this.editor['onContextMenu'] = this.editor['_onContextMenu'].event;
131
126
  }
@@ -196,10 +191,8 @@ class SqlProvider {
196
191
  }
197
192
  });
198
193
  this.editorOptions.onNodeClick = (event, dataItem) => {
199
- // debugger;
200
194
  };
201
195
  this.editorOptions.onInit = (editor) => {
202
- // debugger;
203
196
  this.editor = editor;
204
197
  };
205
198
  this.editorOptions.onNodeDragStart = (event, dataItem) => {
@@ -208,50 +201,11 @@ class SqlProvider {
208
201
  event.dataTransfer.setData("text/plain", JSON.stringify(dataItem));
209
202
  };
210
203
  this.editorOptions.onNodeDragEnd = (event, dataItem) => {
211
- // debugger;
212
204
  };
213
205
  // monaco.languages.registerSignatureHelpProvider('sql', {
214
206
  // signatureHelpTriggerCharacters: ['(', ','],
215
207
  // provideSignatureHelp: (model: monaco.editor.ITextModel, position: monaco.Position, token: any, context: any) => {
216
- // var lastWord = model.getWordUntilPosition(position); //getWordUntilPosition //getWordAtPosition
217
- // var originalText = model.getValueInRange(model.getFullModelRange());
218
- // var fullText = this.sanitize(originalText);
219
- // var range: IRange = {
220
- // startLineNumber: position.lineNumber,
221
- // endLineNumber: position.lineNumber,
222
- // startColumn: lastWord.startColumn,
223
- // endColumn: lastWord.endColumn,
224
- // };
225
- // var contextInfo = this.getContextInfo(originalText, position);
226
- // this.parseStatements();
227
- // var currentStatement = this.currents.statements.find(x => x.index == contextInfo.currentStmntIndex);
228
- // if (currentStatement && currentStatement.words.length > 0
229
- // && currentStatement.words[0].toUpperCase() == 'INSERT INTO') {
230
208
  // } else {
231
- // return {
232
- // dispose: () => { },
233
- // value: {
234
- // activeParameter: 0,
235
- // activeSignature: 0,
236
- // signatures: [{
237
- // label: 'string substr(string $string, int $start [, int $length])',
238
- // parameters: [
239
- // {
240
- // label: 'string $string',
241
- // documentation: 'The input string. Must be one character or longer.'
242
- // },
243
- // {
244
- // label: 'int $start',
245
- // documentation: "If "
246
- // },
247
- // {
248
- // label: 'int $length',
249
- // documentation: 'If '
250
- // }
251
- // ]
252
- // }]
253
- // }
254
- // };
255
209
  // }
256
210
  // }
257
211
  // });
@@ -387,7 +341,7 @@ class SqlProvider {
387
341
  * @returns SQL sanificato in singola linea.
388
342
  */
389
343
  sanitize(str) {
390
- return str.replace(/(\r\n|\n|\r|\t)/gm, " ").replace(/ +(?= )/g, '');
344
+ return str.replaceAll(/(\r\n|\n|\r|\t)/gm, " ").replaceAll(/ +(?= )/g, '');
391
345
  }
392
346
  normalizeStatement(previousWords) {
393
347
  let skipNext = false;
@@ -567,8 +521,8 @@ class SqlProvider {
567
521
  if (!levelBlock && position.column == 1 && position.lineNumber > 1) {
568
522
  let levelLineBlock = parsedText.filter(y => y.find(z => z.lineNumber == position.lineNumber - 1));
569
523
  if (levelLineBlock.length > 0) {
570
- levelBlock = levelLineBlock[levelLineBlock.length - 1];
571
- charToken = levelBlock[levelBlock.length - 1];
524
+ levelBlock = levelLineBlock.at(-1);
525
+ charToken = levelBlock.at(-1);
572
526
  }
573
527
  }
574
528
  else {
@@ -576,7 +530,7 @@ class SqlProvider {
576
530
  }
577
531
  if (!levelBlock) {
578
532
  // Fallback: pick last parsed row block so autocomplete can continue safely.
579
- levelBlock = parsedText[parsedText.length - 1];
533
+ levelBlock = parsedText.at(-1);
580
534
  }
581
535
  if (!charToken) {
582
536
  charToken = levelBlock?.[levelBlock.length - 1];
@@ -634,7 +588,8 @@ class SqlProvider {
634
588
  let statementIndex = 1;
635
589
  let txtLines = originalText.split('\r\n');
636
590
  let nestedStatements = this.getNestedStatements(originalText);
637
- let parsedInput = this.processText(originalText, position);
591
+ let parsedInput;
592
+ this.processText(originalText, position);
638
593
  let adjacentChars = '';
639
594
  let x = txtLines[position.lineNumber - 1];
640
595
  if (x.length >= position.column - 1) {
@@ -661,7 +616,7 @@ class SqlProvider {
661
616
  absolutePosition = endPosition;
662
617
  previousWords = previousWords.concat(line.split(' ').filter(x => x.length > 0).map(x => x.trim().toUpperCase()).map(x => { return { word: x, statementIndx: statementIndex }; }));
663
618
  if (cleanString != line) {
664
- previousNonNestedWords = previousNonNestedWords.concat(cleanString.substring(0, Math.min(position.column, line.length)).split(' ').filter(x => x.length > 0).map(x => x.trim().toUpperCase()).map(x => { return { word: x.replace(/§/g, ''), statementIndx: statementIndex }; }));
619
+ previousNonNestedWords = previousNonNestedWords.concat(cleanString.substring(0, Math.min(position.column, line.length)).split(' ').filter(x => x.length > 0).map(x => x.trim().toUpperCase()).map(x => { return { word: x.replaceAll('§', ''), statementIndx: statementIndex }; }));
665
620
  }
666
621
  else {
667
622
  previousNonNestedWords = previousNonNestedWords.concat(previousWords);
@@ -679,7 +634,7 @@ class SqlProvider {
679
634
  absolutePosition = endPosition;
680
635
  previousWords = previousWords.concat(line.substring(0, Math.min(position.column, line.length)).split(' ').filter(x => x.length > 0).map(x => x.trim().toUpperCase()).map(x => { return { word: x, statementIndx: statementIndex }; }));
681
636
  if (cleanString != line) {
682
- previousNonNestedWords = previousNonNestedWords.concat(cleanString.substring(0, Math.min(position.column, line.length)).split(' ').filter(x => x.length > 0).map(x => x.trim().toUpperCase()).map(x => { return { word: x.replace(/§/g, ''), statementIndx: statementIndex }; }));
637
+ previousNonNestedWords = previousNonNestedWords.concat(cleanString.substring(0, Math.min(position.column, line.length)).split(' ').filter(x => x.length > 0).map(x => x.trim().toUpperCase()).map(x => { return { word: x.replaceAll('§', ''), statementIndx: statementIndex }; }));
683
638
  }
684
639
  else {
685
640
  previousNonNestedWords = previousNonNestedWords.concat(previousWords);
@@ -734,8 +689,8 @@ class SqlProvider {
734
689
  let normalized = this.normalizeStatement(contextWords.map((x, indx) => { return { token: x.word, tokenIndx: indx }; }));
735
690
  currentStatementWords = normalized.map(x => x.token.replace("(", ""));
736
691
  let keywordIndx = -1;
737
- let matchingKeyWords = currentStatementWords.filter(x => sqlKeywords.indexOf(x.toUpperCase()) >= 0);
738
- let matchingKeyWord = matchingKeyWords.length > 0 ? matchingKeyWords[matchingKeyWords.length - 1] : '';
692
+ let matchingKeyWords = currentStatementWords.filter(x => sqlKeywords.includes(x.toUpperCase()));
693
+ let matchingKeyWord = matchingKeyWords.length > 0 ? matchingKeyWords.at(-1) : '';
739
694
  if (matchingKeyWord) {
740
695
  keywordIndx = sqlKeywords.indexOf(matchingKeyWord.toUpperCase());
741
696
  }
@@ -765,7 +720,7 @@ class SqlProvider {
765
720
  let currentSubStmntWords = subStmnt.statement.words;
766
721
  switch (subStmnt.key) {
767
722
  case 'DECLARE':
768
- if (currentSubStmntWords[currentSubStmntWords.length - 1].token.indexOf('@') < 0) {
723
+ if (!currentSubStmntWords[currentSubStmntWords.length - 1].token.includes('@')) {
769
724
  return autocompleteContext.declaration;
770
725
  }
771
726
  else {
@@ -786,37 +741,38 @@ class SqlProvider {
786
741
  console.log('table!!!');
787
742
  return autocompleteContext.table;
788
743
  });
789
- case 'SELECT':
744
+ case 'SELECT': {
790
745
  let previousWord;
791
746
  let nextWord;
792
747
  let previousWords = currentSubStmntWords.filter(x => x.tokenIndx < contextInfo.position.column - 1);
793
748
  if (previousWords.length > 0) {
794
- previousWord = previousWords[previousWords.length - 1];
749
+ previousWord = previousWords.at(-1);
795
750
  }
796
751
  let nextWords = currentSubStmntWords.filter(x => x.tokenIndx >= contextInfo.position.column - 1);
797
752
  if (nextWords.length > 0) {
798
753
  nextWord = nextWords[0];
799
754
  }
800
- let selectLastToken = (currentSubStmntWords[currentSubStmntWords.length - 1]?.token || '').trim();
801
- if (selectLastToken.indexOf('.') >= 0) {
755
+ let selectLastToken = (currentSubStmntWords.at(-1)?.token || '').trim();
756
+ if (selectLastToken.includes('.')) {
802
757
  // Alias-qualified column completion (e.g. AppCit. or AppCit.Sta)
803
758
  return autocompleteContext.columnWhereRestricted;
804
759
  }
805
760
  if (contextInfo.adjacentChars == '()' || (previousWord && nextWord && previousWord.token[previousWord.token.length - 1] == '(' && nextWord.token[0] == ')')) {
806
761
  return autocompleteContext.columnSelect;
807
762
  }
808
- else if (currentSubStmntWords[currentSubStmntWords.length - 1].token.indexOf(',') >= 0 || currentSubStmntWords[currentSubStmntWords.length - 1].token.toUpperCase() == 'SELECT') {
763
+ else if (currentSubStmntWords.at(-1).token.includes(',') || currentSubStmntWords.at(-1).token.toUpperCase() == 'SELECT') {
809
764
  return autocompleteContext.columnSelect;
810
765
  }
811
766
  else {
812
767
  return autocompleteContext.statementFrom;
813
768
  }
769
+ }
814
770
  case 'FROM':
815
771
  // After at least one table in FROM, allow partial clause prefixes
816
772
  // (e.g. "I" => "INNER JOIN") while keeping schema suggestions otherwise.
817
773
  return this.evaluateAutocompleteContext(contextInfo, subStmnt.statement, false, subStmnt.statement.sqlTables.length > 0 ? autocompleteContext.statementWhereJoin : null);
818
774
  case 'AS':
819
- if (matchingKeyWords.length > 1 && matchingKeyWords[matchingKeyWords.length - 2] == 'WITH') {
775
+ if (matchingKeyWords.length > 1 && matchingKeyWords.at(-2) == 'WITH') {
820
776
  return autocompleteContext.statementSelect;
821
777
  }
822
778
  else {
@@ -832,16 +788,18 @@ class SqlProvider {
832
788
  if (schemaTableAliasToken) {
833
789
  let schemaAndTableOrAlias = schemaTableAliasToken.token.split('.').filter(x => x.length > 0);
834
790
  if (schemaAndTableOrAlias.length > 0) {
791
+ // intentionally empty: schema part already typed, fall through to next token checks
835
792
  }
836
793
  else {
837
794
  return autocompleteContext.schema;
838
795
  }
839
796
  if (schemaAndTableOrAlias.length >= 1) {
797
+ // intentionally empty: table part already typed, fall through to join context checks
840
798
  }
841
799
  else {
842
800
  return autocompleteContext.table;
843
801
  }
844
- if (currentSubStmntWords[currentSubStmntWords.length - 1].token.toUpperCase() == subStmnt.key.toUpperCase()) {
802
+ if (currentSubStmntWords.at(-1).token.toUpperCase() == subStmnt.key.toUpperCase()) {
845
803
  return autocompleteContext.schemaJoin;
846
804
  }
847
805
  else {
@@ -862,28 +820,24 @@ class SqlProvider {
862
820
  case 'GROUP BY':
863
821
  return autocompleteContext.columnGroupBy;
864
822
  case 'SET':
865
- if (currentSubStmntWords[currentSubStmntWords.length - 1].token.trim().toUpperCase() == 'SET') {
823
+ if (currentSubStmntWords.at(-1).token.trim().toUpperCase() == 'SET') {
866
824
  let updtStmnt = currentStmnt.subStatements.find(x => x.key == 'UPDATE');
867
825
  if (updtStmnt && updtStmnt.statement.words.length > 1) {
868
- // this.currents.table = updtStmnt.statement.sqlTables[updtStmnt.statement.sqlTables.length - 1];
869
826
  return autocompleteContext.columnWhere;
870
827
  }
871
828
  else {
872
829
  return autocompleteContext.variable;
873
830
  }
874
831
  }
832
+ else if (currentSubStmntWords.at(-1).token.trim().endsWith(',')) {
833
+ return autocompleteContext.columnWhere;
834
+ }
835
+ else if (currentSubStmntWords.at(-1).token.trim() == '=') {
836
+ return autocompleteContext.columnWhereAndVariables;
837
+ }
875
838
  else {
876
- if (currentSubStmntWords[currentSubStmntWords.length - 1].token.trim().endsWith(',')) {
877
- return autocompleteContext.columnWhere;
878
- }
879
- else if (currentSubStmntWords[currentSubStmntWords.length - 1].token.trim() == '=') {
880
- return autocompleteContext.columnWhereAndVariables;
881
- }
882
- else {
883
- return autocompleteContext.assignmentOperator;
884
- }
839
+ return autocompleteContext.assignmentOperator;
885
840
  }
886
- break;
887
841
  }
888
842
  }
889
843
  }
@@ -892,7 +846,7 @@ class SqlProvider {
892
846
  }
893
847
  evaluateAutocompleteContext(contextInfo, statement, skipAs = false, defaultAutoCtx = null, contextDelegate = null) {
894
848
  const lastToken = statement?.words?.length
895
- ? (statement.words[statement.words.length - 1].token || '').trim()
849
+ ? (statement.words.at(-1).token || '').trim()
896
850
  : '';
897
851
  const lastDotIndex = lastToken.lastIndexOf('.');
898
852
  if (lastDotIndex >= 0) {
@@ -907,18 +861,14 @@ class SqlProvider {
907
861
  return defaultAutoCtx;
908
862
  }
909
863
  }
864
+ else if (statement.sqlTables.length > 0) {
865
+ return autocompleteContext.columnWhereRestricted;
866
+ }
867
+ else if (!skipAs) {
868
+ return autocompleteContext.table;
869
+ }
910
870
  else {
911
- if (statement.sqlTables.length > 0) {
912
- return autocompleteContext.columnWhereRestricted;
913
- }
914
- else {
915
- if (!skipAs) {
916
- return autocompleteContext.table;
917
- }
918
- else {
919
- return autocompleteContext.tableNoAs;
920
- }
921
- }
871
+ return autocompleteContext.tableNoAs;
922
872
  }
923
873
  }
924
874
  else {
@@ -957,7 +907,7 @@ class SqlProvider {
957
907
  * @returns Context specifico WHERE.
958
908
  */
959
909
  evaluateAutocompleteWhereContext(currents, currentStatementWords, whereSubStatemnt) {
960
- let lastToken = currentStatementWords[currentStatementWords.length - 1].trim().toUpperCase();
910
+ let lastToken = currentStatementWords.at(-1).trim().toUpperCase();
961
911
  if (lastToken == 'AND' || lastToken == 'WHERE') {
962
912
  return autocompleteContext.columnWhere;
963
913
  }
@@ -1003,7 +953,6 @@ class SqlProvider {
1003
953
  }
1004
954
  let subStatement;
1005
955
  let nestedStatements = this.getNestedStatements(statement);
1006
- let z = nestedStatements[0];
1007
956
  statementObj.statement = this.removeNestedStatements(statement, nestedStatements);
1008
957
  let previousWords = statement.split(' ').filter(x => x.length > 0).map((x, splitIndx) => {
1009
958
  return {
@@ -1023,8 +972,7 @@ class SqlProvider {
1023
972
  const elementObj = sanitizedPreviousWords[indx];
1024
973
  let element = elementObj.token;
1025
974
  let indxOffset = 0;
1026
- for (let nestedIndex = 0; nestedIndex < nestedStatements.length; nestedIndex++) {
1027
- nested = nestedStatements[nestedIndex];
975
+ for (nested of nestedStatements) {
1028
976
  if (nested.length > 1 && elementObj.tokenIndx >= nested.index && elementObj.tokenIndx <= nested.index + nested[1].length) {
1029
977
  this.parseStatementRecursive(nested[1], indx, subStatement);
1030
978
  let firstWordOutsideNested = sanitizedPreviousWords.find(x => x.tokenIndx > nested.index + nested[1].length);
@@ -1035,7 +983,7 @@ class SqlProvider {
1035
983
  indx = indxOffset;
1036
984
  continue;
1037
985
  }
1038
- if (sqlKeywords.indexOf(element.toUpperCase()) >= 0) {
986
+ if (sqlKeywords.includes(element.toUpperCase())) {
1039
987
  currentStatementTag = element;
1040
988
  subStatement = new Statement(element, Object.keys(statementObj.subStatements).length + 1);
1041
989
  subStatement.words.push(elementObj);
@@ -1102,7 +1050,7 @@ class SqlProvider {
1102
1050
  }
1103
1051
  return col;
1104
1052
  });
1105
- if (!this.currents.globalTables.find(x => x.table.toUpperCase() == table.table.toUpperCase())) {
1053
+ if (!this.currents.globalTables.some(x => x.table.toUpperCase() == table.table.toUpperCase())) {
1106
1054
  this.currents.globalTables.push(table);
1107
1055
  }
1108
1056
  return true;
@@ -1116,12 +1064,12 @@ class SqlProvider {
1116
1064
  * @returns `true` se e stata aggiunta una dichiarazione.
1117
1065
  */
1118
1066
  populateDeclarations(statement, found) {
1119
- if (statement.indexOf('@') >= 0) {
1067
+ if (statement.includes('@')) {
1120
1068
  let decStr = statement.trim().toUpperCase().split(' ');
1121
1069
  if (decStr.length >= 3) {
1122
1070
  let dec = { paramName: decStr[1], paramtype: decStr[2], usertype: null };
1123
1071
  let type;
1124
- if (decStr[2].indexOf('.') >= 0) {
1072
+ if (decStr[2].includes('.')) {
1125
1073
  type = this.userDefTypes.find(x => x.table.toUpperCase() == decStr[2].split('.')[1] && x.schema.toUpperCase() == decStr[2].split('.')[0]);
1126
1074
  }
1127
1075
  else {
@@ -1130,7 +1078,7 @@ class SqlProvider {
1130
1078
  if (type) {
1131
1079
  dec.usertype = type;
1132
1080
  }
1133
- if (!this.currents.declarations.find(x => x.paramName.toUpperCase() == dec.paramName.toUpperCase())) {
1081
+ if (!this.currents.declarations.some(x => x.paramName.toUpperCase() == dec.paramName.toUpperCase())) {
1134
1082
  this.currents.declarations.push(dec);
1135
1083
  }
1136
1084
  found = true;
@@ -1148,12 +1096,12 @@ class SqlProvider {
1148
1096
  populateCurrentColumns(element, stmntIndx, statementObj, subStatement) {
1149
1097
  let selStmnt = statementObj.subStatements.find(x => x.key == 'SELECT');
1150
1098
  if (selStmnt) {
1151
- let columns = selStmnt.statement.statement.replace('SELECT', '').trim().toUpperCase().split(',').filter(x => x).map(x => {
1099
+ let columns = selStmnt.statement.statement.replace('SELECT', '').trim().toUpperCase().split(',').filter(Boolean).map(x => {
1152
1100
  let col = null;
1153
1101
  x = x.trim();
1154
1102
  let ownerTbl;
1155
1103
  let isAlias = false;
1156
- if (x.indexOf('.') >= 0) {
1104
+ if (x.includes('.')) {
1157
1105
  let schema = x.split('.')[0].replace('[', '').replace(']', '').replace('(', '').replace(')', '').toUpperCase();
1158
1106
  let ownerSchema = this.schemas.find(s => s.schema.toUpperCase() === schema);
1159
1107
  if (!ownerSchema) {
@@ -1205,19 +1153,19 @@ class SqlProvider {
1205
1153
  }
1206
1154
  }
1207
1155
  return col;
1208
- }).filter(x => x);
1156
+ }).filter(Boolean);
1209
1157
  columns.forEach(x => {
1210
1158
  let normalizedColumn = x?.column?.column?.toUpperCase();
1211
1159
  if (!normalizedColumn) {
1212
1160
  return;
1213
1161
  }
1214
1162
  if (statementObj) {
1215
- if (!statementObj.sqlColumns.find(c => c?.column?.column?.toUpperCase() == normalizedColumn)) {
1163
+ if (!statementObj.sqlColumns.some(c => c?.column?.column?.toUpperCase() == normalizedColumn)) {
1216
1164
  statementObj.sqlColumns.push(x);
1217
1165
  }
1218
1166
  }
1219
1167
  if (subStatement) {
1220
- if (!subStatement.sqlColumns.find(c => c?.column?.column?.toUpperCase() == normalizedColumn)) {
1168
+ if (!subStatement.sqlColumns.some(c => c?.column?.column?.toUpperCase() == normalizedColumn)) {
1221
1169
  subStatement.sqlColumns.push(x);
1222
1170
  }
1223
1171
  }
@@ -1279,7 +1227,7 @@ class SqlProvider {
1279
1227
  populateCurrentSchemaTables(element, stmntIndx, found, statementObj, subStatement) {
1280
1228
  let tblStr = element.trim().toUpperCase().split(' ');
1281
1229
  if (tblStr.length > 0 && tblStr[0].split('.').length > 1) {
1282
- let identifierParts = tblStr[0].replace('[', '').replace(']', '').split('.').filter(x => x);
1230
+ let identifierParts = tblStr[0].replace('[', '').replace(']', '').split('.').filter(Boolean);
1283
1231
  let schemaName = '';
1284
1232
  let tableName = '';
1285
1233
  let dbName = '';
@@ -1331,11 +1279,11 @@ class SqlProvider {
1331
1279
  let aliasCandidate = identifierParts[0] || '';
1332
1280
  let matchTbl = statementObj.sqlTables.find(x => x.usedAlias.toUpperCase() === aliasCandidate.toUpperCase());
1333
1281
  if (matchTbl) {
1334
- if (!subStatement.sqlTables.find(x => x.table.table.toUpperCase() == matchTbl.table.table.toUpperCase() && x.table.schema.toUpperCase() == matchTbl.table.schema.toUpperCase())) {
1282
+ if (!subStatement.sqlTables.some(x => x.table.table.toUpperCase() == matchTbl.table.table.toUpperCase() && x.table.schema.toUpperCase() == matchTbl.table.schema.toUpperCase())) {
1335
1283
  subStatement.sqlTables.push({ table: matchTbl.table, usedAlias: matchTbl.usedAlias });
1336
1284
  }
1337
1285
  let matchSchema = statementObj.sqlModels.find(x => matchTbl.table.schema.toUpperCase() === x.schema.toUpperCase());
1338
- if (matchSchema && !subStatement.sqlModels.find(x => matchTbl.table.schema.toUpperCase() === x.schema.toUpperCase())) {
1286
+ if (matchSchema && !subStatement.sqlModels.some(x => matchTbl.table.schema.toUpperCase() === x.schema.toUpperCase())) {
1339
1287
  subStatement.sqlModels.push(matchSchema);
1340
1288
  }
1341
1289
  }
@@ -1465,7 +1413,7 @@ class SqlProvider {
1465
1413
  }
1466
1414
  ].filter(x => {
1467
1415
  if (currentStatement) {
1468
- if (currentStatement.subStatements.find(s => x.label.indexOf('JOIN') < 0 && x.label == s.key.toUpperCase())) {
1416
+ if (currentStatement.subStatements.some(s => !x.label.includes('JOIN') && x.label == s.key.toUpperCase())) {
1469
1417
  return false;
1470
1418
  }
1471
1419
  }
@@ -1502,7 +1450,7 @@ class SqlProvider {
1502
1450
  });
1503
1451
  }
1504
1452
  ci = ci.concat(selectFields.filter(x => {
1505
- if (context == autocompleteContext.columnSelect && currentStatement.sqlColumns.find(c => c?.column?.column?.toUpperCase() == x.column.toUpperCase())) {
1453
+ if (context == autocompleteContext.columnSelect && currentStatement.sqlColumns.some(c => c?.column?.column?.toUpperCase() == x.column.toUpperCase())) {
1506
1454
  return false;
1507
1455
  }
1508
1456
  return true;
@@ -1515,7 +1463,7 @@ class SqlProvider {
1515
1463
  .replace('(', '')
1516
1464
  .replace(')', '')
1517
1465
  .split('.')
1518
- .filter(y => y)
1466
+ .filter(Boolean)
1519
1467
  .map(y => y.trim().toUpperCase());
1520
1468
  if (!scaffoldedOnly && restrictedParts.length >= 3) {
1521
1469
  let dbFilter = restrictedParts[0];
@@ -1526,7 +1474,7 @@ class SqlProvider {
1526
1474
  && x.table.toUpperCase() === tableFilter
1527
1475
  && (!dbFilter || colDb === dbFilter);
1528
1476
  }
1529
- if (restrictedParts.length >= 1 && restrictedToken.indexOf('.') >= 0) {
1477
+ if (restrictedParts.length >= 1 && restrictedToken.includes('.')) {
1530
1478
  let aliasFilter = restrictedParts[0];
1531
1479
  return (x.tableAlias || '').toUpperCase() === aliasFilter;
1532
1480
  }
@@ -1538,8 +1486,8 @@ class SqlProvider {
1538
1486
  return true;
1539
1487
  }).map(x => {
1540
1488
  let restrictedToken = (currentSubStatement?.words?.[currentSubStatement.words.length - 1]?.token || '').trim();
1541
- let isAliasQualifiedCompletion = context == autocompleteContext.columnWhereRestricted && restrictedToken.indexOf('.') >= 0;
1542
- let aliasStmnts = currentStatement.subStatements.filter(s => s.key == 'FROM' || s.key.indexOf('JOIN') >= 0 || s.key == 'ON');
1489
+ let isAliasQualifiedCompletion = context == autocompleteContext.columnWhereRestricted && restrictedToken.includes('.');
1490
+ let aliasStmnts = currentStatement.subStatements.filter(s => s.key == 'FROM' || s.key.includes('JOIN') || s.key == 'ON');
1543
1491
  let aliasStmnt = aliasStmnts.find(y => y.statement.sqlTables.length > 0 &&
1544
1492
  y.statement.sqlTables[0].table.schema.toUpperCase() == x.schema.toUpperCase() &&
1545
1493
  y.statement.sqlTables[0].table.table.toUpperCase() == x.table.toUpperCase());
@@ -1554,11 +1502,13 @@ class SqlProvider {
1554
1502
  else if (aliasStmnt) {
1555
1503
  str = `${aliasStmnt.statement.sqlTables[0].usedAlias}.${x.column}`;
1556
1504
  }
1557
- let longDescr = `${x.column} (${x.type}, ${x.isNullable ? 'null' : 'not null'})${x.columnDescription ? ` - ${x.columnDescription}` : ''}`;
1505
+ const columnDescriptionSuffix = x.columnDescription ? ` - ${x.columnDescription}` : '';
1506
+ let longDescr = `${x.column} (${x.type}, ${x.isNullable ? 'null' : 'not null'})${columnDescriptionSuffix}`;
1507
+ let nonPkeyKind = (x.parentRelation) ? monaco.languages.CompletionItemKind.Reference : monaco.languages.CompletionItemKind.Field;
1558
1508
  return {
1559
1509
  documentation: longDescr,
1560
1510
  insertText: str,
1561
- kind: x.isPkey ? monaco.languages.CompletionItemKind.Keyword : (x.parentRelation) ? monaco.languages.CompletionItemKind.Reference : monaco.languages.CompletionItemKind.Field,
1511
+ kind: x.isPkey ? monaco.languages.CompletionItemKind.Keyword : nonPkeyKind,
1562
1512
  label: longDescr,
1563
1513
  range: range
1564
1514
  };
@@ -1587,21 +1537,6 @@ class SqlProvider {
1587
1537
  break;
1588
1538
  case autocompleteContext.comparisonOperator:
1589
1539
  ci = comparisonOperators.filter(x => {
1590
- // if (this.currents.column && this.currents.column.type) {
1591
- // var sqlType = sqlTypes.find(x => x.name.toUpperCase() == this.currents.column.type.toUpperCase());
1592
- // if (sqlType) {
1593
- // switch (true) {
1594
- // case sqlType.isString:
1595
- // return ['=', '<>', '!=', '!', 'NOT', 'LIKE', 'IN', 'IS', 'IS NOT NULL'].indexOf(x) >= 0;
1596
- // case sqlType.isNumber:
1597
- // return ['=', '<>', '<', '<=', '>', '>=', '!=', '!', 'NOT', 'BETWEEN', 'IN', 'IS', 'IS NOT NULL'].indexOf(x) >= 0;
1598
- // case sqlType.isBool:
1599
- // return ['=', '<>', '!=', '!', 'NOT', 'IS', 'IS NOT NULL'].indexOf(x) >= 0;
1600
- // default:
1601
- // return true;
1602
- // }
1603
- // }
1604
- // }
1605
1540
  return true;
1606
1541
  }).map(x => {
1607
1542
  return {
@@ -1659,17 +1594,17 @@ class SqlProvider {
1659
1594
  break;
1660
1595
  case autocompleteContext.table:
1661
1596
  case autocompleteContext.tableNoAs:
1662
- case autocompleteContext.tableJoin:
1597
+ case autocompleteContext.tableJoin: {
1663
1598
  let rawScopedToken = (currentSubStatement?.words?.[currentSubStatement.words.length - 1]?.token || '').trim();
1664
- let currentSchema = currentStatement.sqlModels[currentStatement.sqlModels.length - 1]?.schema;
1599
+ let currentSchema = currentStatement.sqlModels.at(-1)?.schema;
1665
1600
  let scopedParts = rawScopedToken
1666
1601
  .replace('[', '')
1667
1602
  .replace(']', '')
1668
1603
  .replace('(', '')
1669
1604
  .replace(')', '')
1670
1605
  .split('.')
1671
- .filter(x => x);
1672
- let isDbScopedSchema = !scaffoldedOnly && rawScopedToken.indexOf('.') >= 0;
1606
+ .filter(Boolean);
1607
+ let isDbScopedSchema = !scaffoldedOnly && rawScopedToken.includes('.');
1673
1608
  if (context == autocompleteContext.tableJoin) {
1674
1609
  currentStatement.sqlTables.forEach(tbl => {
1675
1610
  this.parseTblRelations(currentStatement, tbl, ci, range, currentSchema);
@@ -1739,13 +1674,10 @@ class SqlProvider {
1739
1674
  let txtLine = originalText.split('\n')[range.startLineNumber - 1];
1740
1675
  let qualifiedSchema = scopedModel ? this.getModelSchemaName(scopedModel) : x.schema;
1741
1676
  let startCol = txtLine.toUpperCase().indexOf(`${qualifiedSchema.toUpperCase()}.`);
1742
- let tokenHasQualifier = rawScopedToken.indexOf('.') >= 0;
1743
- let insertTxt = (!x.alias || context == autocompleteContext.tableNoAs) ?
1744
- (tokenHasQualifier
1745
- ? x.table
1746
- : `${context != autocompleteContext.tableNoAs ? `${qualifiedSchema}.` : ''}${x.table}`)
1747
- :
1748
- ``;
1677
+ let tokenHasQualifier = rawScopedToken.includes('.');
1678
+ let schemaPrefix = context != autocompleteContext.tableNoAs ? `${qualifiedSchema}.` : '';
1679
+ let qualifiedInsert = tokenHasQualifier ? x.table : `${schemaPrefix}${x.table}`;
1680
+ let insertTxt = (!x.alias || context == autocompleteContext.tableNoAs) ? qualifiedInsert : ``;
1749
1681
  return {
1750
1682
  documentation: x.table,
1751
1683
  insertText: insertTxt,
@@ -1764,16 +1696,19 @@ class SqlProvider {
1764
1696
  };
1765
1697
  }
1766
1698
  catch (error) {
1699
+ // Malformed table suggestion entry — skip this completion item
1700
+ // (return null) instead of breaking the whole autocomplete list.
1767
1701
  debugger;
1768
1702
  return null;
1769
1703
  }
1770
1704
  });
1771
1705
  }
1772
1706
  break;
1773
- case autocompleteContext.declaration:
1707
+ }
1708
+ case autocompleteContext.declaration: {
1774
1709
  let paramName = '@Param';
1775
1710
  let paramIndx = 1;
1776
- while (this.currents.declarations.find(x => x.paramName.toUpperCase() === `${paramName}${paramIndx.toString()}`.toUpperCase())) {
1711
+ while (this.currents.declarations.some(x => x.paramName.toUpperCase() === `${paramName}${paramIndx.toString()}`.toUpperCase())) {
1777
1712
  paramIndx++;
1778
1713
  }
1779
1714
  paramName = `@Param${paramIndx}`;
@@ -1787,13 +1722,19 @@ class SqlProvider {
1787
1722
  }
1788
1723
  ];
1789
1724
  break;
1725
+ }
1790
1726
  case autocompleteContext.sqlType:
1791
1727
  ci = sqlTypes.map(x => {
1728
+ let sizeHint = '';
1729
+ if (x.isString && x.name.toUpperCase().includes("VAR")) {
1730
+ sizeHint = '(100)';
1731
+ }
1732
+ else if (x.isNumber && x.name.toUpperCase() == "DECIMAL") {
1733
+ sizeHint = '(18, 2)';
1734
+ }
1792
1735
  return {
1793
1736
  documentation: x.name,
1794
- insertText: `${x.name} ${x.isString && x.name.toUpperCase().indexOf("VAR") >= 0 ? '(100)' :
1795
- x.isNumber && x.name.toUpperCase() == "DECIMAL" ? '(18, 2)' :
1796
- ''}= null;\n`,
1737
+ insertText: `${x.name} ${sizeHint}= null;\n`,
1797
1738
  kind: monaco.languages.CompletionItemKind.TypeParameter,
1798
1739
  label: x.name,
1799
1740
  range: range
@@ -1843,7 +1784,7 @@ class SqlProvider {
1843
1784
  return modelAny.database;
1844
1785
  }
1845
1786
  let schema = model.schema || '';
1846
- if (schema.indexOf('.') >= 0) {
1787
+ if (schema.includes('.')) {
1847
1788
  return schema.split('.')[0];
1848
1789
  }
1849
1790
  return null;
@@ -1858,7 +1799,7 @@ class SqlProvider {
1858
1799
  return '';
1859
1800
  }
1860
1801
  let schema = model.schema || '';
1861
- if (schema.indexOf('.') >= 0) {
1802
+ if (schema.includes('.')) {
1862
1803
  return schema.split('.').slice(1).join('.');
1863
1804
  }
1864
1805
  return schema;
@@ -1907,7 +1848,7 @@ class SqlProvider {
1907
1848
  if (rel) {
1908
1849
  relations.push(rel);
1909
1850
  }
1910
- if (col.parentRelation && col.parentRelation.tableFK.toUpperCase() == tbl.table.table.toUpperCase() && col.parentRelation.schemaFK.toUpperCase() == tbl.table.schema.toUpperCase() && (!schemaFilter || col.parentRelation.schemaPK.toUpperCase() == schemaFilter.toUpperCase())) {
1851
+ if (col.parentRelation?.tableFK.toUpperCase() == tbl.table.table.toUpperCase() && col.parentRelation.schemaFK.toUpperCase() == tbl.table.schema.toUpperCase() && (!schemaFilter || col.parentRelation.schemaPK.toUpperCase() == schemaFilter.toUpperCase())) {
1911
1852
  relations.push(col.parentRelation);
1912
1853
  }
1913
1854
  });
@@ -1919,19 +1860,21 @@ class SqlProvider {
1919
1860
  let aliasTblFK;
1920
1861
  if (rel.schemaFK == tbl.table.schema && rel.tableFK == tbl.table.table) {
1921
1862
  aliasTblPK = tblPK.alias ? tblPK.alias : `${tblPK.schema}.${tblPK.table}`;
1922
- aliasTblFK = tbl.usedAlias ? tbl.usedAlias : (tblFK.alias ? tblFK.alias : `${tblFK.schema}.${tblFK.table}`);
1863
+ const fkFallbackAlias = tblFK.alias ? tblFK.alias : `${tblFK.schema}.${tblFK.table}`;
1864
+ aliasTblFK = tbl.usedAlias ? tbl.usedAlias : fkFallbackAlias;
1923
1865
  joinSuggestion = `\t${rel.schemaPK}.${rel.tablePK} AS ${aliasTblPK} ON \n\t${aliasTblFK}.${rel.columnFK} = \n\t${aliasTblPK}.${rel.columnPK}`;
1924
1866
  }
1925
1867
  else {
1926
- aliasTblPK = tbl.usedAlias ? tbl.usedAlias : (tblPK.alias ? tblPK.alias : `${tblPK.schema}.${tblPK.table}`);
1868
+ const pkFallbackAlias = tblPK.alias ? tblPK.alias : `${tblPK.schema}.${tblPK.table}`;
1869
+ aliasTblPK = tbl.usedAlias ? tbl.usedAlias : pkFallbackAlias;
1927
1870
  aliasTblFK = tblFK.alias ? tblFK.alias : `${tblFK.schema}.${tblFK.table}`;
1928
1871
  joinSuggestion = `\t${rel.schemaFK}.${rel.tableFK} AS ${aliasTblFK} ON \n\t${aliasTblPK}.${rel.columnPK} = \n\t${aliasTblFK}.${rel.columnFK}`;
1929
1872
  }
1930
1873
  ci.push({
1931
- documentation: joinSuggestion.replace(/(\r\n|\n|\r|\t)/gm, ' '),
1874
+ documentation: joinSuggestion.replaceAll(/(\r\n|\n|\r|\t)/gm, ' '),
1932
1875
  insertText: `\n${joinSuggestion}`,
1933
1876
  kind: monaco.languages.CompletionItemKind.Reference,
1934
- label: joinSuggestion.replace(/(\r\n|\n|\r|\t)/gm, ' '),
1877
+ label: joinSuggestion.replaceAll(/(\r\n|\n|\r|\t)/gm, ' '),
1935
1878
  range: range
1936
1879
  });
1937
1880
  });
@@ -1946,10 +1889,9 @@ class SqlProvider {
1946
1889
  let tbl;
1947
1890
  this.schemas.forEach(schema => {
1948
1891
  schema.tables.forEach(table => {
1949
- if (table.alias && table.alias.toUpperCase() === alias.toUpperCase()) {
1892
+ if (table.alias?.toUpperCase() === alias.toUpperCase()) {
1950
1893
  tbl = table;
1951
1894
  tbl.schemaObj = schema;
1952
- return;
1953
1895
  }
1954
1896
  });
1955
1897
  if (tbl) {
@@ -1991,12 +1933,12 @@ let DragDropInteractionEmitter$1 = class DragDropInteractionEmitter extends Emit
1991
1933
  let getDbPrefixFor = (schemaName, tableName, preferredDbName) => {
1992
1934
  let owner = providerSchemas.find(m => {
1993
1935
  if (preferredDbName) {
1994
- let mDb = (m.database || ((m.schema || '').indexOf('.') >= 0 ? (m.schema || '').split('.')[0] : '') || '').toUpperCase();
1936
+ let mDb = (m.database || ((m.schema || '').includes('.') ? (m.schema || '').split('.')[0] : '') || '').toUpperCase();
1995
1937
  if (mDb !== preferredDbName.toUpperCase()) {
1996
1938
  return false;
1997
1939
  }
1998
1940
  }
1999
- let mSchema = (m.schema || '').indexOf('.') >= 0 ? (m.schema || '').split('.').slice(1).join('.') : (m.schema || '');
1941
+ let mSchema = (m.schema || '').includes('.') ? (m.schema || '').split('.').slice(1).join('.') : (m.schema || '');
2000
1942
  let schemaMatch = mSchema.toUpperCase() === (schemaName || '').toUpperCase();
2001
1943
  if (!schemaMatch) {
2002
1944
  return false;
@@ -2009,13 +1951,13 @@ let DragDropInteractionEmitter$1 = class DragDropInteractionEmitter extends Emit
2009
1951
  if (!owner) {
2010
1952
  return '';
2011
1953
  }
2012
- let db = owner.database || ((owner.schema || '').indexOf('.') >= 0 ? (owner.schema || '').split('.')[0] : '');
1954
+ let db = owner.database || ((owner.schema || '').includes('.') ? (owner.schema || '').split('.')[0] : '');
2013
1955
  return db ? `${db}.` : '';
2014
1956
  };
2015
1957
  if (dataItem.sqlModel) {
2016
1958
  let modelAny = dataItem.sqlModel;
2017
- let modelDb = modelAny.database || ((dataItem.sqlModel.schema || '').indexOf('.') >= 0 ? (dataItem.sqlModel.schema || '').split('.')[0] : '');
2018
- let modelSchema = (dataItem.sqlModel.schema || '').indexOf('.') >= 0
1959
+ let modelDb = modelAny.database || ((dataItem.sqlModel.schema || '').includes('.') ? (dataItem.sqlModel.schema || '').split('.')[0] : '');
1960
+ let modelSchema = (dataItem.sqlModel.schema || '').includes('.')
2019
1961
  ? (dataItem.sqlModel.schema || '').split('.').slice(1).join('.')
2020
1962
  : (dataItem.sqlModel.schema || '');
2021
1963
  callback(modelDb ? `${modelDb}.${modelSchema}.` : `${modelSchema}.`);
@@ -2037,7 +1979,7 @@ let DragDropInteractionEmitter$1 = class DragDropInteractionEmitter extends Emit
2037
1979
  }
2038
1980
  else if (dataItem.sqlColumn) {
2039
1981
  let suggestions = self.sqlProvider.getAutocompleteSuggestions(self.editor.getValue(), self.position);
2040
- let colSugg = suggestions.suggestions.find(x => x.insertText.indexOf(dataItem.sqlColumn.column) >= 0);
1982
+ let colSugg = suggestions.suggestions.find(x => x.insertText.includes(dataItem.sqlColumn.column));
2041
1983
  if (colSugg) {
2042
1984
  callback(colSugg.insertText);
2043
1985
  }
@@ -2049,8 +1991,8 @@ let DragDropInteractionEmitter$1 = class DragDropInteractionEmitter extends Emit
2049
1991
  }
2050
1992
  else if (dataItem.sqlRelation) {
2051
1993
  let suggestions = self.sqlProvider.getAutocompleteSuggestions(self.editor.getValue(), self.position);
2052
- if (suggestions && suggestions.suggestions) {
2053
- let relSugg = suggestions.suggestions.find(x => x.insertText.indexOf(`${dataItem.sqlRelation.schemaPK}.${dataItem.sqlRelation.tablePK}`) >= 0);
1994
+ if (suggestions?.suggestions) {
1995
+ let relSugg = suggestions.suggestions.find(x => x.insertText.includes(`${dataItem.sqlRelation.schemaPK}.${dataItem.sqlRelation.tablePK}`));
2054
1996
  if (relSugg) {
2055
1997
  callback(relSugg.insertText);
2056
1998
  }
@@ -2070,10 +2012,6 @@ let DragDropInteractionEmitter$1 = class DragDropInteractionEmitter extends Emit
2070
2012
  },
2071
2013
  position: event.position
2072
2014
  };
2073
- // IMMUTABLE !!!!
2074
- // event.event.dataTransfer.clearData();
2075
- // event.event.dataTransfer.items.clear();
2076
- // event.event.dataTransfer.setData('text/plain', 'pippo');
2077
2015
  this.editor._contributions.onBeforeInteractionEvent();
2078
2016
  super.fire(de);
2079
2017
  }
@@ -2090,9 +2028,6 @@ let ContextMenuInteractionEmitter$1 = class ContextMenuInteractionEmitter extend
2090
2028
  fire(event) {
2091
2029
  event.event.preventDefault();
2092
2030
  debugger;
2093
- // event.event.stopPropagation();
2094
- // this.editor._contributions.onBeforeInteractionEvent();
2095
- // super.fire(event);
2096
2031
  }
2097
2032
  };
2098
2033
  class ContextInfo {
@@ -2253,9 +2188,6 @@ class EditorOptions {
2253
2188
  }
2254
2189
  }
2255
2190
 
2256
- // import { editor } from 'monaco-editor';
2257
- // import { LinkedList } from 'monaco-editor/esm/vs/base/common/linkedList';
2258
- // import { MenuId, MenuRegistry } from 'monaco-editor/esm/vs/platform/actions/common/actions';
2259
2191
  /**
2260
2192
  * Stub ambient delle classi rxjs core iniettato in Monaco come extra-lib.
2261
2193
  *
@@ -2335,8 +2267,6 @@ class TSProvider {
2335
2267
  this.editor = editor;
2336
2268
  this.editor['_onDropIntoEditor'] = this.editor['_register'](new DragDropInteractionEmitter(this.editor['_contributions'], this.editor['_deliveryQueue'], this.editor, this));
2337
2269
  this.editor['onDropIntoEditor'] = this.editor['_onDropIntoEditor'].event;
2338
- // this._onContextMenu = this._register(new InteractionEmitter(this._contributions, this._deliveryQueue));
2339
- // this.onContextMenu = this._onContextMenu.event;
2340
2270
  this.editor['_onContextMenu'] = this.editor['_register'](new ContextMenuInteractionEmitter(this.editor['_contributions'], this.editor['_deliveryQueue'], this.editor, this));
2341
2271
  this.editor['onContextMenu'] = this.editor['_onContextMenu'].event;
2342
2272
  }
@@ -2354,6 +2284,15 @@ class TSProvider {
2354
2284
  let self = this;
2355
2285
  let extraLibs = [];
2356
2286
  let libs = [];
2287
+ // Snippet custom dal chiamante (customEditorConfig.snippets, mappa
2288
+ // label -> testo): si SOMMANO ai base perche' il menu contestuale
2289
+ // "Snippets" e' l'unico canale di inserimento guidato — es. il
2290
+ // workflow-designer inietta voci per-nodo che compilano
2291
+ // `wtoolbox.getWorkflowRouteNodePayload('<nodeId>')` con l'id reale.
2292
+ // Mappa d'istanza (un TSProvider per editor): nessun effetto altrove.
2293
+ if (formFieldOptions?.snippets && typeof formFieldOptions.snippets === 'object') {
2294
+ Object.assign(this.snippets, formFieldOptions.snippets);
2295
+ }
2357
2296
  let contextMenuItems = [
2358
2297
  {
2359
2298
  label: 'Snippets', icon: 'pi pi-receipt',
@@ -2370,10 +2309,8 @@ class TSProvider {
2370
2309
  });
2371
2310
  this.editorOptions.contextMenuItems = contextMenuItems;
2372
2311
  this.editorOptions.onNodeClick = (event, dataItem) => {
2373
- // debugger;
2374
2312
  };
2375
2313
  this.editorOptions.onInit = (editor) => {
2376
- // debugger;
2377
2314
  this.editor = editor;
2378
2315
  };
2379
2316
  this.editorOptions.onNodeDragStart = (event, dataItem) => {
@@ -2382,7 +2319,6 @@ class TSProvider {
2382
2319
  event.dataTransfer.setData("text/plain", JSON.stringify(dataItem));
2383
2320
  };
2384
2321
  this.editorOptions.onNodeDragEnd = (event, dataItem) => {
2385
- // debugger;
2386
2322
  };
2387
2323
  let compilerOptions = {
2388
2324
  target: monaco.languages.typescript.ScriptTarget.ES2016,
@@ -2414,16 +2350,6 @@ class TSProvider {
2414
2350
  noSyntaxValidation: false,
2415
2351
  diagnosticCodesToIgnore: [1108, 1375, 1378],
2416
2352
  });
2417
- // //esportare i tipi usando angular.json (riduci i file esportati alle cartelle ...)
2418
- // // "assets": [
2419
- // // ....
2420
- // // {
2421
- // // "glob": "**/*",
2422
- // // "input": "node_modules/@skylab/easygrid/lib",
2423
- // // "output": "assets/"
2424
- // // },
2425
- // // ....
2426
- // libs.push(this.http.get("assets/models/easygrid.server.d.ts", { responseType: 'text' }));
2427
2353
  let headers = new HttpHeaders({
2428
2354
  'Cache-Control': 'no-cache, no-store, must-revalidate, post-check=0, pre- check=0',
2429
2355
  'Pragma': 'no-cache',
@@ -2432,7 +2358,7 @@ class TSProvider {
2432
2358
  libs = MetadataProviderService.baseLibs.map(lib => {
2433
2359
  return this.http.get(lib, { headers: headers, responseType: 'text' });
2434
2360
  });
2435
- if (formFieldOptions.extraLibs && formFieldOptions.extraLibs.length) {
2361
+ if (formFieldOptions.extraLibs?.length) {
2436
2362
  libs.concat(formFieldOptions.extraLibs.map(lib => {
2437
2363
  return this.http.get(lib, { headers: headers, responseType: 'text' });
2438
2364
  }));
@@ -2441,15 +2367,15 @@ class TSProvider {
2441
2367
  if (codeContext) {
2442
2368
  let routeIdContextField = field.extras.customEditorConfig?.routeContextField;
2443
2369
  let columnContextField = field.extras.customEditorConfig?.columnContextField;
2444
- if (codeContext.indexOf('record: ') >= 0 && routeIdContextField) {
2445
- let routeId = record[routeIdContextField]?.value; // this.metaInfo.tableMetadata.md_route_name.replaceAll(' ', '_');
2370
+ if (codeContext.includes('record: ') && routeIdContextField) {
2371
+ let routeId = record[routeIdContextField]?.value;
2446
2372
  if (routeId) {
2447
2373
  let metas = await metaSrv.getMetadatiById(routeId);
2448
2374
  let currentColumnMeta = null;
2449
2375
  if (columnContextField) {
2450
2376
  currentColumnMeta = metas.find(m => m.mc_id == record[columnContextField].value);
2451
2377
  }
2452
- if (metas && metas.length) {
2378
+ if (metas?.length) {
2453
2379
  let routeName = metas[0]._Metadati_Tabelle.md_route_name.replaceAll(' ', '_');
2454
2380
  let classProperties = '';
2455
2381
  let classPropsArray = [];
@@ -2464,7 +2390,7 @@ class TSProvider {
2464
2390
  let lookupMetas = await metaSrv.getMetadati(lookupRoute);
2465
2391
  let nestedClassProperties = '';
2466
2392
  let nestedClassPropsArray = [];
2467
- if (lookupMetas && lookupMetas.length) {
2393
+ if (lookupMetas?.length) {
2468
2394
  lookupRoute = lookupRoute.replaceAll(' ', '_');
2469
2395
  for (let cLookup of lookupMetas) {
2470
2396
  nestedClassPropsArray.push(`${cLookup.mc_nome_colonna}: ${MetadataProviderService.getTSTypeFromMetaColumn(cLookup)};`);
@@ -2481,7 +2407,7 @@ class TSProvider {
2481
2407
  }
2482
2408
  // recursive function to get the type of the nested lookup objects
2483
2409
  // ...
2484
- if (codeContext.indexOf('record: any') >= 0) {
2410
+ if (codeContext.includes('record: any')) {
2485
2411
  classPropsArray.push(`${c.mc_nome_colonna}: ${MetadataProviderService.getTSTypeFromMetaColumn(c)};`);
2486
2412
  }
2487
2413
  else {
@@ -2498,13 +2424,13 @@ class TSProvider {
2498
2424
  };
2499
2425
  constructor();`);
2500
2426
  })));
2501
- if (codeContext.indexOf('record: any') >= 0) {
2427
+ if (codeContext.includes('record: any')) {
2502
2428
  codeContext = codeContext.replace('record: any', `record: ${routeName}`);
2503
2429
  }
2504
2430
  else {
2505
2431
  codeContext = codeContext.replace('record: {[key: string]: BehaviorSubject<any>}', `record: {${compositeTypeDef}}`);
2506
2432
  }
2507
- if (currentColumnMeta && currentColumnMeta.mc_ui_column_type == 'lookupByID' && codeContext.indexOf('let newValue: any;') >= 0) {
2433
+ if (currentColumnMeta?.mc_ui_column_type == 'lookupByID' && codeContext.includes('let newValue: any;')) {
2508
2434
  codeContext = codeContext.replace('let newValue: any;', `let newValue: ${currentColumnMeta.mc_ui_lookup_entity_name};`);
2509
2435
  }
2510
2436
  }
@@ -2519,7 +2445,7 @@ class TSProvider {
2519
2445
  let lines = data.split('\n');
2520
2446
  // da migliorare con regex !!!
2521
2447
  let parsedLines = lines.filter(x => {
2522
- return x.indexOf('import ') < 0; // && x.indexOf('export interface ') < 0
2448
+ return !x.includes('import '); // && x.indexOf('export interface ') < 0
2523
2449
  }).map((line) => {
2524
2450
  return line.replace('export declare', 'declare').replace('export interface', 'declare interface').replace('export class', 'declare class');
2525
2451
  });
@@ -2568,33 +2494,13 @@ class DragDropInteractionEmitter extends Emitter {
2568
2494
  callback(`${dataItem.sqlTable.schema}.${dataItem.sqlTable.table}`);
2569
2495
  }
2570
2496
  if (dataItem.parentTable) {
2571
- // let suggestions = self.sqlProvider.getAutocompleteSuggestions(self.editor.getValue(), self.position);
2572
- // let colSugg = suggestions.suggestions.find(x => x.label == '<All columns>');
2573
- // if (colSugg) {
2574
- // callback(colSugg.insertText);
2575
- // } else {
2576
- // callback(dataItem.parentTable.columns.map(x => x.column).join(','));
2577
- // }
2497
+ // intentionally empty: parentTable drops have no plain-text representation
2578
2498
  }
2579
2499
  if (dataItem.sqlColumn) {
2580
- // let suggestions = self.sqlProvider.getAutocompleteSuggestions(self.editor.getValue(), self.position);
2581
- // let colSugg = suggestions.suggestions.find(x => x.insertText.indexOf(dataItem.sqlColumn.column) >= 0);
2582
- // if (colSugg) {
2583
- // callback(colSugg.insertText);
2584
- // } else {
2585
- // callback(`${dataItem.sqlColumn.schema}.${dataItem.sqlColumn.table}.${dataItem.sqlColumn.column}`);
2586
- // }
2500
+ // intentionally empty: sqlColumn drops have no plain-text representation
2587
2501
  }
2588
2502
  if (dataItem.sqlRelation) {
2589
- // let suggestions = self.sqlProvider.getAutocompleteSuggestions(self.editor.getValue(), self.position);
2590
- // if (suggestions && suggestions.suggestions) {
2591
- // let relSugg = suggestions.suggestions.find(x => x.insertText.indexOf(`${dataItem.sqlRelation.schemaPK}.${dataItem.sqlRelation.tablePK}`) >= 0);
2592
- // if (relSugg) {
2593
- // callback(relSugg.insertText);
2594
- // } else {
2595
- // callback(`${dataItem.sqlRelation.schemaPK}.${dataItem.sqlRelation.tablePK} ON ${dataItem.sqlRelation.schemaFK}.${dataItem.sqlRelation.tableFK}.${dataItem.sqlRelation.columnFK} = ${dataItem.sqlRelation.schemaPK}.${dataItem.sqlRelation.tablePK}.${dataItem.sqlRelation.columnPK}`);
2596
- // }
2597
- // }
2503
+ // intentionally empty: sqlRelation drops have no plain-text representation
2598
2504
  }
2599
2505
  }
2600
2506
  }
@@ -2604,10 +2510,6 @@ class DragDropInteractionEmitter extends Emitter {
2604
2510
  },
2605
2511
  position: event.position
2606
2512
  };
2607
- // IMMUTABLE !!!!
2608
- // event.event.dataTransfer.clearData();
2609
- // event.event.dataTransfer.items.clear();
2610
- // event.event.dataTransfer.setData('text/plain', 'pippo');
2611
2513
  this.editor._contributions.onBeforeInteractionEvent();
2612
2514
  super.fire(de);
2613
2515
  }
@@ -2624,12 +2526,191 @@ class ContextMenuInteractionEmitter extends Emitter {
2624
2526
  fire(event) {
2625
2527
  event.event.preventDefault();
2626
2528
  this.tsProvider.contextMenuEvent = event;
2627
- // event.event.stopPropagation();
2628
- // this.editor._contributions.onBeforeInteractionEvent();
2629
- // super.fire(event);
2630
2529
  }
2631
2530
  }
2632
2531
 
2532
+ /**
2533
+ * Property-editor "a struttura" guidato da JSON SCHEMA — vista alternativa
2534
+ * (toggle) del code-editor in modalita' json: aggiunta/rimozione di
2535
+ * nodi/sottonodi TIPIZZATI in base allo schema, senza scrivere JSON a mano.
2536
+ *
2537
+ * Copertura schema v1 (subset pragmatico dei casi usati dagli schemi WUIC,
2538
+ * es. customEditorConfig/props_bag/scene3d shader effect):
2539
+ * - object con `properties` (+`required`): righe per le proprieta' presenti,
2540
+ * dropdown "aggiungi" per quelle mancanti, rimozione per le non-required;
2541
+ * - string (input testo; color picker se pattern hex #rrggbb; select se enum);
2542
+ * - number/integer (input numerico con min/max dallo schema);
2543
+ * - boolean (checkbox); const (badge readonly);
2544
+ * - array di number a lunghezza fissa (minItems=maxItems, es. direzioni xyz)
2545
+ * e array generici (item add/remove col tipo di `items`).
2546
+ *
2547
+ * Il valore viene MUTATO su una copia locale e riemesso integralmente a ogni
2548
+ * modifica (`valueChange`): il code-editor lo serializza nel model Monaco e
2549
+ * nel record, cosi' le due viste restano sempre allineate.
2550
+ */
2551
+ class JsonSchemaTreeEditorComponent {
2552
+ /** JSON schema radice (draft-07 style: type/properties/required/enum/const/items). */
2553
+ schema = null;
2554
+ /** Valore corrente (oggetto JS gia' parsato). Lavora su una copia profonda. */
2555
+ value = null;
2556
+ /** Emesso a ogni mutazione con l'intero valore aggiornato. */
2557
+ valueChange = new EventEmitter();
2558
+ /** Copia locale mutabile del valore. */
2559
+ model = {};
2560
+ ngOnChanges() {
2561
+ try {
2562
+ this.model = this.value != null ? JSON.parse(JSON.stringify(this.value)) : {};
2563
+ }
2564
+ catch {
2565
+ this.model = {};
2566
+ }
2567
+ }
2568
+ emit() {
2569
+ this.valueChange.emit(JSON.parse(JSON.stringify(this.model)));
2570
+ }
2571
+ // --- Introspezione schema -------------------------------------------------
2572
+ /** Righe (proprieta' PRESENTI nel valore) per un nodo object. */
2573
+ rows(schema, obj) {
2574
+ const props = schema?.properties || {};
2575
+ const required = Array.isArray(schema?.required) ? schema.required : [];
2576
+ return Object.keys(props)
2577
+ .filter((key) => obj != null && Object.hasOwn(obj, key))
2578
+ .map((key) => ({
2579
+ key,
2580
+ schema: props[key],
2581
+ kind: this.kindOf(props[key]),
2582
+ required: required.includes(key)
2583
+ }));
2584
+ }
2585
+ /** Proprieta' dello schema NON ancora presenti nel valore (per il dropdown "aggiungi"). */
2586
+ addable(schema, obj) {
2587
+ const props = schema?.properties || {};
2588
+ return Object.keys(props).filter((key) => !(obj != null && Object.hasOwn(obj, key)));
2589
+ }
2590
+ /** Classifica il tipo di editor per una property schema. */
2591
+ kindOf(propSchema) {
2592
+ if (!propSchema) {
2593
+ return 'text';
2594
+ }
2595
+ if (propSchema.const !== undefined) {
2596
+ return 'const';
2597
+ }
2598
+ if (Array.isArray(propSchema.enum)) {
2599
+ return 'enum';
2600
+ }
2601
+ const type = propSchema.type;
2602
+ if (type === 'boolean') {
2603
+ return 'boolean';
2604
+ }
2605
+ if (type === 'number' || type === 'integer') {
2606
+ return 'number';
2607
+ }
2608
+ if (type === 'object') {
2609
+ return 'object';
2610
+ }
2611
+ if (type === 'array') {
2612
+ const fixed = Number(propSchema.minItems) > 0 && propSchema.minItems === propSchema.maxItems
2613
+ && (propSchema.items?.type === 'number' || propSchema.items?.type === 'integer');
2614
+ return fixed ? 'vector' : 'array';
2615
+ }
2616
+ if (type === 'string' && typeof propSchema.pattern === 'string' && propSchema.pattern.includes('#[0-9a-fA-F]{6}')) {
2617
+ return 'color';
2618
+ }
2619
+ return 'text';
2620
+ }
2621
+ /** Valore di default tipizzato per una property aggiunta dalla struttura. */
2622
+ defaultFor(propSchema) {
2623
+ if (!propSchema) {
2624
+ return '';
2625
+ }
2626
+ if (propSchema.default !== undefined) {
2627
+ return JSON.parse(JSON.stringify(propSchema.default));
2628
+ }
2629
+ if (propSchema.const !== undefined) {
2630
+ return propSchema.const;
2631
+ }
2632
+ if (Array.isArray(propSchema.enum)) {
2633
+ return propSchema.enum[0];
2634
+ }
2635
+ const type = propSchema.type;
2636
+ if (type === 'boolean') {
2637
+ return false;
2638
+ }
2639
+ if (type === 'number' || type === 'integer') {
2640
+ return typeof propSchema.minimum === 'number' ? propSchema.minimum : 0;
2641
+ }
2642
+ if (type === 'array') {
2643
+ const n = Number(propSchema.minItems) || 0;
2644
+ return Array.from({ length: n }, () => this.defaultFor(propSchema.items));
2645
+ }
2646
+ if (type === 'object') {
2647
+ const child = {};
2648
+ const required = Array.isArray(propSchema.required) ? propSchema.required : [];
2649
+ for (const key of required) {
2650
+ child[key] = this.defaultFor(propSchema.properties?.[key]);
2651
+ }
2652
+ return child;
2653
+ }
2654
+ if (this.kindOf(propSchema) === 'color') {
2655
+ return '#ffffff';
2656
+ }
2657
+ return '';
2658
+ }
2659
+ // --- Mutazioni ------------------------------------------------------------
2660
+ setProp(obj, key, value) {
2661
+ obj[key] = value;
2662
+ this.emit();
2663
+ }
2664
+ setNumberProp(obj, key, raw) {
2665
+ const parsed = Number(raw);
2666
+ obj[key] = Number.isFinite(parsed) ? parsed : 0;
2667
+ this.emit();
2668
+ }
2669
+ addProp(obj, key, propSchema, selectEl) {
2670
+ if (!key) {
2671
+ return;
2672
+ }
2673
+ obj[key] = this.defaultFor(propSchema);
2674
+ if (selectEl) {
2675
+ selectEl.value = '';
2676
+ }
2677
+ this.emit();
2678
+ }
2679
+ removeProp(obj, key) {
2680
+ delete obj[key];
2681
+ this.emit();
2682
+ }
2683
+ setVectorItem(arr, index, raw) {
2684
+ const parsed = Number(raw);
2685
+ arr[index] = Number.isFinite(parsed) ? parsed : 0;
2686
+ this.emit();
2687
+ }
2688
+ addArrayItem(arr, itemSchema) {
2689
+ arr.push(this.defaultFor(itemSchema));
2690
+ this.emit();
2691
+ }
2692
+ removeArrayItem(arr, index) {
2693
+ arr.splice(index, 1);
2694
+ this.emit();
2695
+ }
2696
+ /** Etichetta breve per gli hint (description dello schema, troncata). */
2697
+ hint(propSchema) {
2698
+ return String(propSchema?.description || '');
2699
+ }
2700
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: JsonSchemaTreeEditorComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2701
+ 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"] }] });
2702
+ }
2703
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: JsonSchemaTreeEditorComponent, decorators: [{
2704
+ type: Component,
2705
+ 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"] }]
2706
+ }], propDecorators: { schema: [{
2707
+ type: Input
2708
+ }], value: [{
2709
+ type: Input
2710
+ }], valueChange: [{
2711
+ type: Output
2712
+ }] } });
2713
+
2633
2714
  const WUIC_COMMON_INPUTS = [
2634
2715
  'record',
2635
2716
  'field',
@@ -2718,11 +2799,11 @@ class HtmlProvider {
2718
2799
  { label: 'div', snippet: '<div>$0</div>', documentation: 'Container element' },
2719
2800
  { label: 'section', snippet: '<section>$0</section>', documentation: 'Sectioning content' },
2720
2801
  { label: 'article', snippet: '<article>$0</article>', documentation: 'Independent content block' },
2721
- { label: 'a', snippet: '<a href=\"$1\">$0</a>', documentation: 'Anchor link' },
2722
- { label: 'img', snippet: '<img src=\"$1\" alt=\"$2\" />', documentation: 'Image with alt text' },
2802
+ { label: 'a', snippet: '<a href="$1">$0</a>', documentation: 'Anchor link' },
2803
+ { label: 'img', snippet: '<img src="$1" alt="$2" />', documentation: 'Image with alt text' },
2723
2804
  { label: 'table', snippet: '<table>\\n <thead>\\n <tr><th>$1</th></tr>\\n </thead>\\n <tbody>\\n <tr><td>$0</td></tr>\\n </tbody>\\n</table>', documentation: 'Basic table template' },
2724
2805
  { label: 'ul', snippet: '<ul>\\n <li>$0</li>\\n</ul>', documentation: 'Unordered list' },
2725
- { label: 'form', snippet: '<form>\\n <label for=\"$1\">$2</label>\\n <input id=\"$1\" name=\"$1\" />\\n</form>', documentation: 'Simple form template' }
2806
+ { label: 'form', snippet: '<form>\\n <label for="$1">$2</label>\\n <input id="$1" name="$1" />\\n</form>', documentation: 'Simple form template' }
2726
2807
  ];
2727
2808
  constructor(editorOptions, componentSelectors = [], componentBindings = {}) {
2728
2809
  this.editorOptions = editorOptions;
@@ -2836,7 +2917,7 @@ class HtmlProvider {
2836
2917
  message: `Possible malformed tag '${firstToken}': missing '<' at start.`
2837
2918
  });
2838
2919
  }
2839
- const inlineEventMatch = line.match(/\son[a-z]+\s*=/i);
2920
+ const inlineEventMatch = /\son[a-z]+\s*=/i.exec(line);
2840
2921
  if (inlineEventMatch?.index != null) {
2841
2922
  const startColumn = inlineEventMatch.index + 2;
2842
2923
  markers.push({
@@ -2848,7 +2929,7 @@ class HtmlProvider {
2848
2929
  message: 'Inline on* event handler detected.'
2849
2930
  });
2850
2931
  }
2851
- const jsUrlMatch = line.match(/\b(?:href|src)\s*=\s*["']?\s*javascript:/i);
2932
+ const jsUrlMatch = /\b(?:href|src)\s*=\s*["']?\s*javascript:/i.exec(line);
2852
2933
  if (jsUrlMatch?.index != null) {
2853
2934
  const startColumn = jsUrlMatch.index + 1;
2854
2935
  markers.push({
@@ -2882,7 +2963,6 @@ class HtmlProvider {
2882
2963
  while ((match = tagRegex.exec(content)) !== null) {
2883
2964
  const full = match[0];
2884
2965
  const tag = (match[1] || '').toLowerCase();
2885
- const attrs = match[2] || '';
2886
2966
  const isClosing = full.startsWith('</');
2887
2967
  const isSelfClosing = /\/\s*>$/.test(full) || voidTags.has(tag);
2888
2968
  if (!isClosing && !isSelfClosing) {
@@ -2890,8 +2970,8 @@ class HtmlProvider {
2890
2970
  continue;
2891
2971
  }
2892
2972
  if (isClosing) {
2893
- const last = stack[stack.length - 1];
2894
- if (last && last.tag === tag) {
2973
+ const last = stack.at(-1);
2974
+ if (last?.tag === tag) {
2895
2975
  stack.pop();
2896
2976
  }
2897
2977
  else {
@@ -2982,12 +3062,12 @@ class HtmlProvider {
2982
3062
  pushMarker(tagOffset + 1 + bad.index, bad[0].length, monaco.MarkerSeverity.Error, 'Malformed Angular property binding. Use [prop]="...".');
2983
3063
  }
2984
3064
  // Broken event binding: (event=...
2985
- const malformedEvent = /\([^\)\s=><"'`]*\s*=/g;
3065
+ const malformedEvent = /\([^)\s=><"'`]*\s*=/g;
2986
3066
  while ((bad = malformedEvent.exec(attrs)) !== null) {
2987
3067
  pushMarker(tagOffset + 1 + bad.index, bad[0].length, monaco.MarkerSeverity.Error, 'Malformed Angular event binding. Use (event)="...".');
2988
3068
  }
2989
3069
  // Broken two-way binding: [(model=...
2990
- const malformedTwoWay = /\[\([^\)\]]+\s*=/g;
3070
+ const malformedTwoWay = /\[\([^)\]]+\s*=/g;
2991
3071
  while ((bad = malformedTwoWay.exec(attrs)) !== null) {
2992
3072
  pushMarker(tagOffset + 1 + bad.index, bad[0].length, monaco.MarkerSeverity.Error, 'Malformed Angular two-way binding. Use [(prop)]="...".');
2993
3073
  }
@@ -3065,7 +3145,7 @@ class HtmlProvider {
3065
3145
  }));
3066
3146
  suggestions.unshift(...wuicSuggestions);
3067
3147
  }
3068
- if (openTagContext && openTagContext.tagName.startsWith('wuic-')) {
3148
+ if (openTagContext?.tagName.startsWith('wuic-')) {
3069
3149
  const bindingSuggestions = this.buildAngularBindingSuggestions(openTagContext.tagName, range);
3070
3150
  suggestions.unshift(...bindingSuggestions);
3071
3151
  }
@@ -3074,7 +3154,7 @@ class HtmlProvider {
3074
3154
  });
3075
3155
  }
3076
3156
  getOpenTagContext(linePrefix) {
3077
- const match = linePrefix.match(/<([\w-]+)\b([^<>]*)$/);
3157
+ const match = /<([\w-]+)\b([^<>]*)$/.exec(linePrefix);
3078
3158
  if (!match) {
3079
3159
  return null;
3080
3160
  }
@@ -3165,13 +3245,13 @@ class HtmlProvider {
3165
3245
  return '';
3166
3246
  }
3167
3247
  const normalized = input
3168
- .replace(/>\s+</g, '><')
3169
- .replace(/\r\n/g, '\n')
3248
+ .replaceAll(/>\s+</g, '><')
3249
+ .replaceAll('\r\n', '\n')
3170
3250
  .trim();
3171
3251
  const withLineBreaks = normalized
3172
- .replace(/></g, '>\n<')
3173
- .replace(/(<\/(div|section|article|main|aside|header|footer|nav|ul|ol|li|table|thead|tbody|tfoot|tr|td|th|form|fieldset|p|h[1-6]|pre|blockquote)>)/gi, '$1\n')
3174
- .replace(/(<(div|section|article|main|aside|header|footer|nav|ul|ol|li|table|thead|tbody|tfoot|tr|td|th|form|fieldset|p|h[1-6]|pre|blockquote)(\s[^>]*)?>)/gi, '\n$1')
3252
+ .replaceAll('><', '>\n<')
3253
+ .replaceAll(/(<\/(div|section|article|main|aside|header|footer|nav|ul|ol|li|table|thead|tbody|tfoot|tr|td|th|form|fieldset|p|h[1-6]|pre|blockquote)>)/gi, '$1\n')
3254
+ .replaceAll(/(<(div|section|article|main|aside|header|footer|nav|ul|ol|li|table|thead|tbody|tfoot|tr|td|th|form|fieldset|p|h[1-6]|pre|blockquote)(\s[^>]*)?>)/gi, '\n$1')
3175
3255
  .split('\n')
3176
3256
  .map((line) => line.trim())
3177
3257
  .filter((line) => line.length > 0);
@@ -3183,12 +3263,12 @@ class HtmlProvider {
3183
3263
  const voidTags = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
3184
3264
  for (const rawLine of withLineBreaks) {
3185
3265
  const line = rawLine.trim();
3186
- const closeMatch = line.match(closingTag);
3266
+ const closeMatch = closingTag.exec(line);
3187
3267
  if (closeMatch) {
3188
3268
  indentLevel = Math.max(0, indentLevel - 1);
3189
3269
  }
3190
3270
  lines.push(`${' '.repeat(indentLevel)}${line}`);
3191
- const openMatch = line.match(openingTag);
3271
+ const openMatch = openingTag.exec(line);
3192
3272
  const isSelf = selfClosing.test(line);
3193
3273
  if (openMatch && !isSelf && !voidTags.has(openMatch[1].toLowerCase()) && !line.includes(`</${openMatch[1]}>`)) {
3194
3274
  indentLevel += 1;
@@ -3251,7 +3331,6 @@ const WUIC_COMPONENT_SELECTORS = [
3251
3331
  'wuic-workflow-runner'
3252
3332
  ];
3253
3333
 
3254
- // import { TreeItemDragStartEvent, TreeItemDragEvent, TreeItemDropEvent, DropPosition, TreeItemAddRemoveArgs, TreeItem, NodeClickEvent } from '@progress/kendo-angular-treeview';
3255
3334
  class CodeEditorComponent {
3256
3335
  monacoLoaderService;
3257
3336
  http;
@@ -3303,11 +3382,24 @@ class CodeEditorComponent {
3303
3382
  * Proprieta di stato del componente per editor model value, usata dalla logica interna e dal template.
3304
3383
  */
3305
3384
  editorModelValue = '';
3385
+ /**
3386
+ * Toggle "Struttura" per il json: se true (via @Input o
3387
+ * `customEditorConfig.jsonTreeToggle`) la toolbar espone il passaggio
3388
+ * Codice <-> property-editor treeview guidato dallo schema JSON
3389
+ * ({@link JsonSchemaTreeEditorComponent}). Le due viste restano allineate:
3390
+ * ogni modifica nella struttura riscrive model Monaco e record.
3391
+ */
3392
+ jsonTreeToggle = false;
3393
+ /** true quando e' attiva la vista struttura (Monaco nascosto ma vivo). */
3394
+ treeViewActive = false;
3395
+ /** Schema JSON radice per la vista struttura (primo schema configurato). */
3396
+ jsonTreeSchema = null;
3397
+ /** Valore parsato passato alla vista struttura. */
3398
+ treeValue = null;
3306
3399
  /**
3307
3400
  * Proprieta di stato del componente per sample code, usata dalla logica interna e dal template.
3308
3401
  */
3309
3402
  sampleCode = '';
3310
- // originalCode = 'function x() { // TODO }';
3311
3403
  /**
3312
3404
  * Flag di stato che governa il comportamento UI/logico relativo a fullscreen.
3313
3405
  */
@@ -3420,6 +3512,16 @@ class CodeEditorComponent {
3420
3512
  * (che e' tree-shaken nei build prod).
3421
3513
  */
3422
3514
  hostElementRef = inject(ElementRef, { optional: true });
3515
+ /**
3516
+ * NgZone + ChangeDetectorRef via `inject()` (stesso idioma di hostElementRef,
3517
+ * per non toccare il costruttore a 7 argomenti posizionali). Servono al
3518
+ * subscribe di `isMonacoLoaded$`: il loader ngx-monaco emette dal callback di
3519
+ * script-load (FUORI da NgZone) e la continuation async del subscribe resta
3520
+ * fuori zona → `this.render = true` non triggera change detection e il
3521
+ * template `<ngx-monaco-editor>` non monta mai (editor mai creato).
3522
+ */
3523
+ ngZone = inject(NgZone);
3524
+ cdRef = inject(ChangeDetectorRef);
3423
3525
  t(resource, fallback) {
3424
3526
  const translated = WtoolboxService.translationService?.instant?.(resource);
3425
3527
  return translated && translated !== resource ? translated : fallback;
@@ -3496,8 +3598,6 @@ class CodeEditorComponent {
3496
3598
  async suggest($event, ctx) {
3497
3599
  $event.stopPropagation();
3498
3600
  $event.preventDefault();
3499
- // var resp = await WtoolboxService.promptDialog('Suggest', [{ name: 'prompt', caption: 'prompt', type: 'text' }]);
3500
- // debugger;
3501
3601
  const nextValue = String(this.field.mc_suggest_value_callback__fn(this.record, this.field, this.metaInfo, WtoolboxService) ?? '');
3502
3602
  this.editorModelValue = nextValue;
3503
3603
  this.record[this.field.mc_nome_colonna].next(nextValue);
@@ -3524,11 +3624,13 @@ class CodeEditorComponent {
3524
3624
  // component instance on host element for tests that need direct access
3525
3625
  // (toggle-monaco contract check, etc.).
3526
3626
  try {
3527
- (this.hostElementRef?.nativeElement).__wuicCmp = this;
3627
+ if (this.hostElementRef?.nativeElement) {
3628
+ this.hostElementRef.nativeElement.__wuicCmp = this;
3629
+ }
3528
3630
  }
3529
3631
  catch { /* defensive */ }
3530
3632
  let formFieldOptions = {};
3531
- if (this.field && this.field.extras.customEditorConfig) {
3633
+ if (this.field?.extras.customEditorConfig) {
3532
3634
  try {
3533
3635
  formFieldOptions = this.field.extras.customEditorConfig;
3534
3636
  }
@@ -3536,7 +3638,7 @@ class CodeEditorComponent {
3536
3638
  console.error(`customEditorConfig for field ${this.field.mc_nome_colonna} error: ${e}`);
3537
3639
  }
3538
3640
  }
3539
- this.editorOptions = { ...this.editorOptions, ...(formFieldOptions.editorOptions || {}) };
3641
+ this.editorOptions = { ...this.editorOptions, ...(formFieldOptions.editorOptions) };
3540
3642
  const configuredLanguage = String(formFieldOptions.editorOptions?.language || '').trim().toLowerCase();
3541
3643
  if (configuredLanguage === 'json' || configuredLanguage === 'typescript' || configuredLanguage === 'sql' || configuredLanguage === 'csharp' || configuredLanguage === 'html') {
3542
3644
  this.editorOptions.language = configuredLanguage;
@@ -3547,7 +3649,7 @@ class CodeEditorComponent {
3547
3649
  this.editorOptions.wordWrap = this.editorOptions.wordWrap || 'on';
3548
3650
  this.editorOptions.wrappingIndent = this.editorOptions.wrappingIndent || 'same';
3549
3651
  this.editorOptions.suggest = {
3550
- ...(this.editorOptions.suggest || {}),
3652
+ ...(this.editorOptions.suggest),
3551
3653
  showStatusBar: false,
3552
3654
  preview: false,
3553
3655
  previewMode: 'subwordSmart',
@@ -3559,14 +3661,6 @@ class CodeEditorComponent {
3559
3661
  }
3560
3662
  this.bindRecordValue();
3561
3663
  this.refreshHtmlPreview();
3562
- // if (this.editorOptions.language === 'sql') {
3563
- // this.sampleCode = '';
3564
- // } else if (this.editorOptions.language === 'typescript') {
3565
- // this.sampleCode = 'function x() {\nconsole.log("Hello world!");\n}';
3566
- // } else if (this.editorOptions.language === 'json') {
3567
- // this.sampleCode = '{\n\n}';
3568
- // }
3569
- // this.sampleCode = formFieldOptions.sampleCode || this.sampleCode;
3570
3664
  this.monacoLoaderService.isMonacoLoaded$.pipe(filter(isLoaded => isLoaded), take(1)).subscribe(async () => {
3571
3665
  if (this.editorOptions.language === 'sql') {
3572
3666
  this.sqlProvider = new SqlProvider(this.http, this.editorOptions);
@@ -3578,6 +3672,10 @@ class CodeEditorComponent {
3578
3672
  await this.tsProvider.registerTSProvider(formFieldOptions, this.field, this.codeContext, this.record, this.metaSrv, this.userInfo);
3579
3673
  }
3580
3674
  else if (this.editorOptions.language === 'json') {
3675
+ // Vista "Struttura" (property-editor treeview da schema): abilitabile
3676
+ // via @Input jsonTreeToggle o `customEditorConfig.jsonTreeToggle`.
3677
+ this.jsonTreeToggle = this.jsonTreeToggle || formFieldOptions.jsonTreeToggle === true;
3678
+ this.jsonTreeSchema = (formFieldOptions.schemas?.[0])?.schema || null;
3581
3679
  // https://json-schema.org/learn/getting-started-step-by-step
3582
3680
  // string.
3583
3681
  // number.
@@ -3612,7 +3710,16 @@ class CodeEditorComponent {
3612
3710
  this.htmlProvider = new HtmlProvider(this.editorOptions, WUIC_COMPONENT_SELECTORS, WUIC_COMPONENT_BINDINGS);
3613
3711
  this.htmlProvider.registerHtmlProvider();
3614
3712
  }
3615
- this.render = true;
3713
+ // FIX (2026-07-22): rientra in NgZone e forza CD. La emit di
3714
+ // isMonacoLoaded$ arriva dal callback script-load di ngx-monaco (fuori
3715
+ // zona) e gli `await` sopra mantengono la continuation fuori zona:
3716
+ // senza run()+detectChanges il flag non rirenderizza il template e
3717
+ // Monaco non viene mai istanziato (test toggle-monaco: render=false /
3718
+ // ngxCount=0 deterministico).
3719
+ this.ngZone.run(() => {
3720
+ this.render = true;
3721
+ this.cdRef.detectChanges();
3722
+ });
3616
3723
  });
3617
3724
  }
3618
3725
  /**
@@ -3631,7 +3738,7 @@ class CodeEditorComponent {
3631
3738
  wordWrap: this.editorOptions.wordWrap || 'on',
3632
3739
  wrappingIndent: this.editorOptions.wrappingIndent || 'same',
3633
3740
  suggest: {
3634
- ...(this.editorOptions.suggest || {}),
3741
+ ...(this.editorOptions.suggest),
3635
3742
  showStatusBar: false,
3636
3743
  preview: false,
3637
3744
  previewMode: 'subwordSmart',
@@ -3660,7 +3767,9 @@ class CodeEditorComponent {
3660
3767
  */
3661
3768
  ngOnDestroy() {
3662
3769
  try {
3663
- delete (this.hostElementRef?.nativeElement).__wuicCmp;
3770
+ if (this.hostElementRef?.nativeElement) {
3771
+ delete this.hostElementRef.nativeElement.__wuicCmp;
3772
+ }
3664
3773
  }
3665
3774
  catch { /* defensive */ }
3666
3775
  if (this.layoutRaf !== null) {
@@ -3701,7 +3810,7 @@ class CodeEditorComponent {
3701
3810
  const hosts = [];
3702
3811
  let current = start?.parentElement || null;
3703
3812
  while (current) {
3704
- const style = window.getComputedStyle(current);
3813
+ const style = globalThis.getComputedStyle(current);
3705
3814
  const overflowY = style.overflowY || '';
3706
3815
  const isScrollableY = (overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'overlay')
3707
3816
  && current.scrollHeight > current.clientHeight;
@@ -3772,6 +3881,59 @@ class CodeEditorComponent {
3772
3881
  this.skipNextAutoFormat = true;
3773
3882
  this.editor.getAction('editor.action.formatDocument')?.run().catch(() => undefined);
3774
3883
  }
3884
+ /**
3885
+ * Toggle Codice <-> Struttura (json): attivando la struttura il testo
3886
+ * corrente viene parsato (JSON invalido -> toast e resta il codice);
3887
+ * Monaco resta VIVO ma nascosto, cosi' il rientro e' istantaneo.
3888
+ */
3889
+ toggleJsonTree($event) {
3890
+ $event?.stopPropagation?.();
3891
+ $event?.preventDefault?.();
3892
+ if (!this.isJsonEditor || !this.jsonTreeToggle) {
3893
+ return;
3894
+ }
3895
+ if (this.treeViewActive) {
3896
+ this.treeViewActive = false;
3897
+ this.scheduleEditorLayout();
3898
+ return;
3899
+ }
3900
+ const raw = String(this.editor?.getValue?.() ?? this.editorModelValue ?? '');
3901
+ let parsed = {};
3902
+ if (raw.trim()) {
3903
+ try {
3904
+ parsed = JSON.parse(raw);
3905
+ }
3906
+ catch {
3907
+ WtoolboxService.messageNotificationService.add({
3908
+ severity: 'error',
3909
+ summary: 'json_format_error',
3910
+ detail: this.t('json_format_error_detail', 'JSON non valido: impossibile formattare.')
3911
+ });
3912
+ return;
3913
+ }
3914
+ }
3915
+ if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
3916
+ WtoolboxService.messageNotificationService.add({
3917
+ severity: 'warn',
3918
+ summary: 'json_tree_root_object',
3919
+ detail: this.t('json_tree_root_object_detail', 'La vista struttura richiede un oggetto JSON alla radice.')
3920
+ });
3921
+ return;
3922
+ }
3923
+ this.treeValue = parsed;
3924
+ this.treeViewActive = true;
3925
+ }
3926
+ /**
3927
+ * Modifica dalla vista struttura: riscrive il JSON formattato nel model
3928
+ * Monaco e nel record (stesso percorso di formatJsonNow), cosi' le due
3929
+ * viste e il valore persistito restano allineati.
3930
+ */
3931
+ onTreeValueChange(value) {
3932
+ const pretty = JSON.stringify(value ?? {}, null, 2);
3933
+ this.editorModelValue = pretty;
3934
+ this.editor?.setValue(pretty);
3935
+ this.record?.[this.field.mc_nome_colonna]?.next(pretty);
3936
+ }
3775
3937
  /**
3776
3938
  * Gestisce la logica operativa di `formatJsonNow` orchestrando parse/stringify JSON e sync nel model editor.
3777
3939
  * @param $event Evento UI o payload evento che innesca il flusso del metodo.
@@ -3873,7 +4035,7 @@ class CodeEditorComponent {
3873
4035
  const replacement = doc.createElement('div');
3874
4036
  const ngIfAttr = node.getAttribute('*ngif') || node.getAttribute('*ngIf') || '';
3875
4037
  const captionMatch = /getMetaColumn\(\s*['"]([^'"]+)['"]\s*\)/i.exec(ngIfAttr);
3876
- if (captionMatch && captionMatch[1]) {
4038
+ if (captionMatch?.[1]) {
3877
4039
  replacement.setAttribute('data-wuic-caption', captionMatch[1]);
3878
4040
  }
3879
4041
  Array.from(node.attributes).forEach((attr) => replacement.setAttribute(attr.name, attr.value));
@@ -3947,7 +4109,7 @@ class CodeEditorComponent {
3947
4109
  }
3948
4110
  const ngIfAttr = current.getAttribute('*ngif') || current.getAttribute('*ngIf') || '';
3949
4111
  const match = /getMetaColumn\(\s*['"]([^'"]+)['"]\s*\)/i.exec(ngIfAttr);
3950
- if (match && match[1]) {
4112
+ if (match?.[1]) {
3951
4113
  return match[1];
3952
4114
  }
3953
4115
  current = current.parentElement;
@@ -3969,13 +4131,13 @@ class CodeEditorComponent {
3969
4131
  children: this.mapToPrimeTreeNodes(node?.items || [])
3970
4132
  }));
3971
4133
  }
3972
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CodeEditorComponent, deps: [{ token: i1.MonacoEditorLoaderService }, { token: i1$1.HttpClient }, { token: MetadataProviderService }, { token: UserInfoService }, { token: DataProviderService }, { token: WtoolboxService }, { token: i1$2.DomSanitizer }], target: i0.ɵɵFactoryTarget.Component });
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"] }] });
4134
+ 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 });
4135
+ 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;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: 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"] }, { kind: "component", type: JsonSchemaTreeEditorComponent, selector: "wuic-json-schema-tree-editor", inputs: ["schema", "value"], outputs: ["valueChange"] }] });
3974
4136
  }
3975
4137
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImport: i0, type: CodeEditorComponent, decorators: [{
3976
4138
  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$1.HttpClient }, { type: MetadataProviderService }, { type: UserInfoService }, { type: DataProviderService }, { type: WtoolboxService }, { type: i1$2.DomSanitizer }], propDecorators: { style: [{
4139
+ 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;background:#fffc}\n"] }]
4140
+ }], ctorParameters: () => [{ type: i1$1.MonacoEditorLoaderService }, { type: i1$2.HttpClient }, { type: MetadataProviderService }, { type: UserInfoService }, { type: DataProviderService }, { type: WtoolboxService }, { type: i1$3.DomSanitizer }], propDecorators: { style: [{
3979
4141
  type: HostBinding,
3980
4142
  args: ['style']
3981
4143
  }], contextMenuAnchor: [{
@@ -3993,7 +4155,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.2.9", ngImpor
3993
4155
  }], ctxs: [{
3994
4156
  type: ViewChild,
3995
4157
  args: ['ctxs']
4158
+ }], jsonTreeToggle: [{
4159
+ type: Input
3996
4160
  }] } });
3997
4161
 
3998
4162
  export { CodeEditorComponent };
3999
- //# sourceMappingURL=wuic-framework-lib-code-editor.component-CLMDvOWs.mjs.map
4163
+ //# sourceMappingURL=wuic-framework-lib-code-editor.component-N6HMl2mf.mjs.map