@libs-ui/components-preview-text-data 0.2.350-1 → 0.2.351-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/esm2022/preview-text-data.component.mjs +210 -131
- package/esm2022/preview-text-data.define.mjs +103 -3
- package/fesm2022/libs-ui-components-preview-text-data.mjs +312 -133
- package/fesm2022/libs-ui-components-preview-text-data.mjs.map +1 -1
- package/package.json +5 -5
- package/preview-text-data.component.d.ts +54 -16
- package/preview-text-data.define.d.ts +62 -4
|
@@ -1,31 +1,20 @@
|
|
|
1
1
|
import * as i0 from '@angular/core';
|
|
2
|
-
import { signal, computed, input, model, output, viewChild,
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { html } from '@codemirror/lang-html';
|
|
7
|
-
import { java } from '@codemirror/lang-java';
|
|
8
|
-
import { javascript } from '@codemirror/lang-javascript';
|
|
9
|
-
import { json } from '@codemirror/lang-json';
|
|
10
|
-
import { markdown } from '@codemirror/lang-markdown';
|
|
11
|
-
import { php } from '@codemirror/lang-php';
|
|
12
|
-
import { python } from '@codemirror/lang-python';
|
|
13
|
-
import { sql } from '@codemirror/lang-sql';
|
|
14
|
-
import { xml } from '@codemirror/lang-xml';
|
|
15
|
-
import { yaml } from '@codemirror/lang-yaml';
|
|
16
|
-
import { StreamLanguage } from '@codemirror/language';
|
|
17
|
-
import { linter, lintGutter } from '@codemirror/lint';
|
|
18
|
-
import { Compartment, EditorState } from '@codemirror/state';
|
|
19
|
-
import { lineNumbers } from '@codemirror/view';
|
|
2
|
+
import { signal, inject, DestroyRef, computed, input, model, output, viewChild, effect, ChangeDetectionStrategy, Component } from '@angular/core';
|
|
3
|
+
import { lintGutter, linter } from '@codemirror/lint';
|
|
4
|
+
import { Compartment } from '@codemirror/state';
|
|
5
|
+
import { EditorView, lineNumbers } from '@codemirror/view';
|
|
20
6
|
import { LibsUiComponentsButtonsButtonComponent } from '@libs-ui/components-buttons-button';
|
|
21
7
|
import { LibsUiComponentsDropdownComponent } from '@libs-ui/components-dropdown';
|
|
22
8
|
import { LibsUiNotificationService } from '@libs-ui/services-notification';
|
|
23
9
|
import { UtilsHttpParamsRequest, get } from '@libs-ui/utils';
|
|
24
|
-
import {
|
|
25
|
-
import { Parser } from 'node-sql-parser';
|
|
10
|
+
import { basicSetup } from 'codemirror6';
|
|
26
11
|
import { returnListObject } from '@libs-ui/services-http-request';
|
|
27
12
|
|
|
28
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Danh sách các ngôn ngữ được hỗ trợ
|
|
15
|
+
* Sử dụng const array để tránh tạo mới mỗi lần truy cập
|
|
16
|
+
*/
|
|
17
|
+
const optionsLangData = [
|
|
29
18
|
{ id: 'text', label: 'Plain Text' },
|
|
30
19
|
{ id: 'javascript', label: 'JavaScript/TypeScript' },
|
|
31
20
|
{ id: 'html', label: 'HTML' },
|
|
@@ -45,7 +34,7 @@ const httpRequestConfigGetOptionsLang = () => {
|
|
|
45
34
|
return {
|
|
46
35
|
type: 'text',
|
|
47
36
|
httpRequestData: signal({
|
|
48
|
-
objectInstance: returnListObject(
|
|
37
|
+
objectInstance: returnListObject([...optionsLangData]),
|
|
49
38
|
functionName: 'list',
|
|
50
39
|
argumentsValue: [new UtilsHttpParamsRequest({ fromObject: { page: 1, per_page: 40 } })],
|
|
51
40
|
}),
|
|
@@ -55,146 +44,311 @@ const httpRequestConfigGetOptionsLang = () => {
|
|
|
55
44
|
}),
|
|
56
45
|
};
|
|
57
46
|
};
|
|
47
|
+
const languageRegistry = {
|
|
48
|
+
javascript: {
|
|
49
|
+
loader: async () => {
|
|
50
|
+
const { javascript } = await import('@codemirror/lang-javascript');
|
|
51
|
+
return javascript({ jsx: true, typescript: true });
|
|
52
|
+
},
|
|
53
|
+
linter: async (component) => component.createJsLinter(),
|
|
54
|
+
},
|
|
55
|
+
html: {
|
|
56
|
+
loader: async () => {
|
|
57
|
+
const { html } = await import('@codemirror/lang-html');
|
|
58
|
+
return html();
|
|
59
|
+
},
|
|
60
|
+
},
|
|
61
|
+
css: {
|
|
62
|
+
loader: async () => {
|
|
63
|
+
const { css } = await import('@codemirror/lang-css');
|
|
64
|
+
return css();
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
markdown: {
|
|
68
|
+
loader: async () => {
|
|
69
|
+
const { markdown } = await import('@codemirror/lang-markdown');
|
|
70
|
+
return markdown();
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
json: {
|
|
74
|
+
loader: async () => {
|
|
75
|
+
const { json } = await import('@codemirror/lang-json');
|
|
76
|
+
return json();
|
|
77
|
+
},
|
|
78
|
+
linter: async (component) => component.createJsonLinter(),
|
|
79
|
+
},
|
|
80
|
+
sql: {
|
|
81
|
+
loader: async () => {
|
|
82
|
+
const { sql } = await import('@codemirror/lang-sql');
|
|
83
|
+
return sql();
|
|
84
|
+
},
|
|
85
|
+
linter: async (component) => component.createSqlLinter(),
|
|
86
|
+
},
|
|
87
|
+
xml: {
|
|
88
|
+
loader: async () => {
|
|
89
|
+
const { xml } = await import('@codemirror/lang-xml');
|
|
90
|
+
return xml();
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
yaml: {
|
|
94
|
+
loader: async () => {
|
|
95
|
+
const { yaml } = await import('@codemirror/lang-yaml');
|
|
96
|
+
return yaml();
|
|
97
|
+
},
|
|
98
|
+
},
|
|
99
|
+
python: {
|
|
100
|
+
loader: async () => {
|
|
101
|
+
const { python } = await import('@codemirror/lang-python');
|
|
102
|
+
return python();
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
java: {
|
|
106
|
+
loader: async () => {
|
|
107
|
+
const { java } = await import('@codemirror/lang-java');
|
|
108
|
+
return java();
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
cpp: {
|
|
112
|
+
loader: async () => {
|
|
113
|
+
const { cpp } = await import('@codemirror/lang-cpp');
|
|
114
|
+
return cpp();
|
|
115
|
+
},
|
|
116
|
+
},
|
|
117
|
+
php: {
|
|
118
|
+
loader: async () => {
|
|
119
|
+
const { php } = await import('@codemirror/lang-php');
|
|
120
|
+
return php();
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
go: {
|
|
124
|
+
loader: async () => {
|
|
125
|
+
const { go } = await import('@codemirror/lang-go');
|
|
126
|
+
return go();
|
|
127
|
+
},
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
/**
|
|
131
|
+
* Tạo default language extension cho plain text
|
|
132
|
+
* Sử dụng khi ngôn ngữ không được hỗ trợ
|
|
133
|
+
*/
|
|
134
|
+
const createDefaultLanguage = async () => {
|
|
135
|
+
const { StreamLanguage } = await import('@codemirror/language');
|
|
136
|
+
return StreamLanguage.define({
|
|
137
|
+
token(stream) {
|
|
138
|
+
stream.skipToEnd();
|
|
139
|
+
return null;
|
|
140
|
+
},
|
|
141
|
+
});
|
|
142
|
+
};
|
|
58
143
|
|
|
59
|
-
/* eslint-disable @typescript-eslint/no-explicit-any */
|
|
60
|
-
const sqlParser = new Parser();
|
|
61
144
|
class LibsUiComponentsPreviewTextDataComponent {
|
|
145
|
+
// ==========================================================================
|
|
146
|
+
// PRIVATE PROPERTIES
|
|
147
|
+
// ==========================================================================
|
|
62
148
|
editorViewInstance;
|
|
63
149
|
wrapCompartment = new Compartment();
|
|
64
150
|
languageCompartment = new Compartment();
|
|
65
151
|
lineNumberCompartment = new Compartment();
|
|
152
|
+
linterCompartment = new Compartment();
|
|
153
|
+
/** Cache để tránh load lại language đã load */
|
|
154
|
+
languageCache = new Map();
|
|
155
|
+
/** Flag để tránh update editor khi đang khởi tạo */
|
|
156
|
+
isInitialized = false;
|
|
157
|
+
// ==========================================================================
|
|
158
|
+
// INJECTED SERVICES
|
|
159
|
+
// ==========================================================================
|
|
160
|
+
notificationService = inject(LibsUiNotificationService);
|
|
161
|
+
destroyRef = inject(DestroyRef);
|
|
162
|
+
// ==========================================================================
|
|
163
|
+
// PROTECTED SIGNALS
|
|
164
|
+
// ==========================================================================
|
|
66
165
|
isWrap = signal(true);
|
|
67
166
|
configLoadDataIsHttpConfig = httpRequestConfigGetOptionsLang();
|
|
68
|
-
labelLang = computed(() =>
|
|
69
|
-
|
|
167
|
+
labelLang = computed(() => optionsLangData.find((item) => item.id === this.langSelected())?.label);
|
|
168
|
+
// ==========================================================================
|
|
169
|
+
// INPUTS
|
|
170
|
+
// ==========================================================================
|
|
171
|
+
content = input('', {
|
|
172
|
+
transform: (value) => value ?? '',
|
|
173
|
+
});
|
|
70
174
|
langSelected = model.required();
|
|
71
|
-
editable = input(false, {
|
|
72
|
-
|
|
175
|
+
editable = input(false, {
|
|
176
|
+
transform: (value) => value ?? false,
|
|
177
|
+
});
|
|
178
|
+
hiddenAction = input(false, {
|
|
179
|
+
transform: (value) => value ?? false,
|
|
180
|
+
});
|
|
73
181
|
lintIgnorePatterns = input(['Cannot use import statement outside a module', 'Unexpected token export', 'import ', '@angular/core'], {
|
|
74
182
|
transform: (value) => value ?? ['Cannot use import statement outside a module', 'Unexpected token export', 'import ', '@angular/core'],
|
|
75
183
|
});
|
|
76
|
-
background = input('#f8f9fa', {
|
|
184
|
+
background = input('#f8f9fa', {
|
|
185
|
+
transform: (value) => value ?? '#f8f9fa',
|
|
186
|
+
});
|
|
187
|
+
// ==========================================================================
|
|
188
|
+
// OUTPUTS
|
|
189
|
+
// ==========================================================================
|
|
77
190
|
outChange = output();
|
|
78
191
|
syntaxErrors = output();
|
|
192
|
+
// ==========================================================================
|
|
193
|
+
// VIEW CHILDREN
|
|
194
|
+
// ==========================================================================
|
|
79
195
|
containerPreview = viewChild.required('containerPreview');
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
196
|
+
// ==========================================================================
|
|
197
|
+
// CONSTRUCTOR - Setup effects
|
|
198
|
+
// ==========================================================================
|
|
199
|
+
constructor() {
|
|
200
|
+
// Effect để sync content từ input vào editor
|
|
201
|
+
effect(() => {
|
|
202
|
+
const newContent = this.content();
|
|
203
|
+
if (this.isInitialized && this.editorViewInstance) {
|
|
204
|
+
const currentContent = this.editorViewInstance.state.doc.toString();
|
|
205
|
+
if (newContent !== currentContent) {
|
|
206
|
+
this.editorViewInstance.dispatch({
|
|
207
|
+
changes: {
|
|
208
|
+
from: 0,
|
|
209
|
+
to: currentContent.length,
|
|
210
|
+
insert: newContent,
|
|
211
|
+
},
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
});
|
|
216
|
+
// Cleanup khi component bị destroy
|
|
217
|
+
this.destroyRef.onDestroy(() => {
|
|
218
|
+
this.editorViewInstance?.destroy();
|
|
219
|
+
this.languageCache.clear();
|
|
220
|
+
});
|
|
83
221
|
}
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
222
|
+
// ==========================================================================
|
|
223
|
+
// LIFECYCLE HOOKS
|
|
224
|
+
// ==========================================================================
|
|
225
|
+
async ngAfterViewInit() {
|
|
226
|
+
await this.initializeEditor();
|
|
227
|
+
this.isInitialized = true;
|
|
228
|
+
}
|
|
229
|
+
// ==========================================================================
|
|
230
|
+
// PRIVATE METHODS - Editor initialization
|
|
231
|
+
// ==========================================================================
|
|
232
|
+
/**
|
|
233
|
+
* Khởi tạo editor với các extensions cơ bản
|
|
234
|
+
* Language được load async để tối ưu bundle size
|
|
235
|
+
*/
|
|
236
|
+
async initializeEditor() {
|
|
237
|
+
const languageExtension = await this.loadLanguageExtension(this.langSelected());
|
|
238
|
+
const linterExtension = await this.loadLinterExtension(this.langSelected());
|
|
239
|
+
this.editorViewInstance = new EditorView({
|
|
240
|
+
doc: this.content(),
|
|
241
|
+
parent: this.containerPreview().nativeElement,
|
|
242
|
+
extensions: this.createExtensions(languageExtension, linterExtension),
|
|
90
243
|
});
|
|
91
|
-
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Tạo danh sách extensions cho editor
|
|
247
|
+
*/
|
|
248
|
+
createExtensions(languageExtension, linterExtension) {
|
|
249
|
+
return [
|
|
250
|
+
basicSetup,
|
|
251
|
+
this.languageCompartment.of(languageExtension),
|
|
252
|
+
this.linterCompartment.of(linterExtension),
|
|
253
|
+
this.createLightTheme(),
|
|
254
|
+
EditorView.editable.of(this.editable()),
|
|
255
|
+
this.wrapCompartment.of(EditorView.lineWrapping),
|
|
256
|
+
this.lineNumberCompartment.of(lineNumbers()),
|
|
257
|
+
lintGutter(),
|
|
258
|
+
this.createBracketTheme(),
|
|
259
|
+
this.createUpdateListener(),
|
|
260
|
+
];
|
|
261
|
+
}
|
|
262
|
+
/**
|
|
263
|
+
* Load language extension với caching
|
|
264
|
+
* Mỗi language chỉ được load 1 lần
|
|
265
|
+
*/
|
|
266
|
+
async loadLanguageExtension(lang) {
|
|
92
267
|
const lowerLang = lang.toLowerCase();
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
lintFunction = this.jsLinterFn();
|
|
97
|
-
break;
|
|
98
|
-
case 'html':
|
|
99
|
-
formatByLangFunction = html();
|
|
100
|
-
break;
|
|
101
|
-
case 'css':
|
|
102
|
-
formatByLangFunction = css();
|
|
103
|
-
break;
|
|
104
|
-
case 'markdown':
|
|
105
|
-
formatByLangFunction = markdown();
|
|
106
|
-
break;
|
|
107
|
-
case 'json':
|
|
108
|
-
formatByLangFunction = json();
|
|
109
|
-
lintFunction = this.jsonLinterFn();
|
|
110
|
-
break;
|
|
111
|
-
case 'sql':
|
|
112
|
-
formatByLangFunction = sql();
|
|
113
|
-
lintFunction = this.sqlLinterFn();
|
|
114
|
-
break;
|
|
115
|
-
case 'xml':
|
|
116
|
-
formatByLangFunction = xml();
|
|
117
|
-
break;
|
|
118
|
-
case 'yaml':
|
|
119
|
-
formatByLangFunction = yaml();
|
|
120
|
-
break;
|
|
121
|
-
case 'python':
|
|
122
|
-
formatByLangFunction = python();
|
|
123
|
-
break;
|
|
124
|
-
case 'java':
|
|
125
|
-
formatByLangFunction = java();
|
|
126
|
-
break;
|
|
127
|
-
case 'cpp':
|
|
128
|
-
formatByLangFunction = cpp();
|
|
129
|
-
break;
|
|
130
|
-
case 'php':
|
|
131
|
-
formatByLangFunction = php();
|
|
132
|
-
break;
|
|
133
|
-
case 'go':
|
|
134
|
-
formatByLangFunction = go();
|
|
135
|
-
break;
|
|
268
|
+
const cached = this.languageCache.get(lowerLang);
|
|
269
|
+
if (cached) {
|
|
270
|
+
return cached;
|
|
136
271
|
}
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
this.lightTheme(),
|
|
142
|
-
EditorView.editable.of(this.editable()),
|
|
143
|
-
this.wrapCompartment.of(EditorView.lineWrapping),
|
|
144
|
-
this.lineNumberCompartment.of(lineNumbers()),
|
|
145
|
-
lintGutter(),
|
|
146
|
-
this.customBracketTheme(),
|
|
147
|
-
lintFunction,
|
|
148
|
-
EditorView.updateListener.of((update) => {
|
|
149
|
-
if (update.docChanged && this.editable()) {
|
|
150
|
-
const newValue = update.state.doc.toString();
|
|
151
|
-
this.outChange.emit({
|
|
152
|
-
content: newValue,
|
|
153
|
-
isWrap: this.isWrap(),
|
|
154
|
-
language: this.langSelected(),
|
|
155
|
-
contextChange: 'content',
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
}),
|
|
159
|
-
],
|
|
160
|
-
};
|
|
272
|
+
const registryItem = languageRegistry[lowerLang];
|
|
273
|
+
const extension = registryItem ? await registryItem.loader() : await createDefaultLanguage();
|
|
274
|
+
this.languageCache.set(lowerLang, extension);
|
|
275
|
+
return extension;
|
|
161
276
|
}
|
|
162
|
-
|
|
277
|
+
/**
|
|
278
|
+
* Load linter extension nếu có
|
|
279
|
+
*/
|
|
280
|
+
async loadLinterExtension(lang) {
|
|
281
|
+
const lowerLang = lang.toLowerCase();
|
|
282
|
+
const registryItem = languageRegistry[lowerLang];
|
|
283
|
+
if (registryItem?.linter) {
|
|
284
|
+
return registryItem.linter(this);
|
|
285
|
+
}
|
|
286
|
+
return linter(() => []);
|
|
287
|
+
}
|
|
288
|
+
// ==========================================================================
|
|
289
|
+
// PRIVATE METHODS - Theme configuration
|
|
290
|
+
// ==========================================================================
|
|
291
|
+
createLightTheme() {
|
|
163
292
|
return EditorView.theme({
|
|
164
293
|
'&': { backgroundColor: this.background(), color: '#333' },
|
|
165
294
|
'.cm-content': { caretColor: '#111' },
|
|
166
295
|
'.cm-activeLine': { backgroundColor: '#f0f0f0' },
|
|
167
296
|
});
|
|
168
297
|
}
|
|
169
|
-
|
|
298
|
+
createBracketTheme() {
|
|
170
299
|
return EditorView.theme({
|
|
171
300
|
'.cm-matchingBracket': {
|
|
172
|
-
backgroundColor: 'rgba(100, 200, 255, 0.15)',
|
|
301
|
+
backgroundColor: 'rgba(100, 200, 255, 0.15)',
|
|
173
302
|
border: '1px solid rgba(100, 200, 255, 0.4)',
|
|
174
303
|
borderRadius: '3px',
|
|
175
304
|
transition: 'all 0.2s ease',
|
|
176
305
|
},
|
|
177
306
|
'.cm-nonmatchingBracket': {
|
|
178
|
-
backgroundColor: 'rgba(255, 100, 100, 0.15)',
|
|
307
|
+
backgroundColor: 'rgba(255, 100, 100, 0.15)',
|
|
179
308
|
border: '1px solid rgba(255, 100, 100, 0.3)',
|
|
180
309
|
borderRadius: '3px',
|
|
181
310
|
},
|
|
182
311
|
});
|
|
183
312
|
}
|
|
184
|
-
|
|
313
|
+
// ==========================================================================
|
|
314
|
+
// PRIVATE METHODS - Update listener
|
|
315
|
+
// ==========================================================================
|
|
316
|
+
createUpdateListener() {
|
|
317
|
+
return EditorView.updateListener.of((update) => {
|
|
318
|
+
if (update.docChanged && this.editable()) {
|
|
319
|
+
const newValue = update.state.doc.toString();
|
|
320
|
+
this.outChange.emit({
|
|
321
|
+
content: newValue,
|
|
322
|
+
isWrap: this.isWrap(),
|
|
323
|
+
language: this.langSelected(),
|
|
324
|
+
contextChange: 'content',
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
});
|
|
328
|
+
}
|
|
329
|
+
// ==========================================================================
|
|
330
|
+
// PUBLIC METHODS - Linter factories (được gọi từ registry)
|
|
331
|
+
// ==========================================================================
|
|
332
|
+
/**
|
|
333
|
+
* Tạo JavaScript linter
|
|
334
|
+
* Sử dụng Function constructor để validate syntax
|
|
335
|
+
*/
|
|
336
|
+
createJsLinter() {
|
|
185
337
|
return linter((view) => {
|
|
186
338
|
const text = view.state.doc.toString();
|
|
187
339
|
const diagnostics = [];
|
|
188
340
|
try {
|
|
189
|
-
new Function(text);
|
|
341
|
+
new Function(text);
|
|
190
342
|
}
|
|
191
343
|
catch (err) {
|
|
192
|
-
|
|
344
|
+
const message = get(err, 'message', '');
|
|
345
|
+
const shouldIgnore = this.lintIgnorePatterns().some((pattern) => message.includes(pattern));
|
|
346
|
+
if (!shouldIgnore) {
|
|
193
347
|
diagnostics.push({
|
|
194
348
|
from: 0,
|
|
195
349
|
to: text.length,
|
|
196
350
|
severity: 'error',
|
|
197
|
-
message
|
|
351
|
+
message,
|
|
198
352
|
});
|
|
199
353
|
this.syntaxErrors.emit(diagnostics);
|
|
200
354
|
}
|
|
@@ -202,7 +356,11 @@ class LibsUiComponentsPreviewTextDataComponent {
|
|
|
202
356
|
return diagnostics;
|
|
203
357
|
});
|
|
204
358
|
}
|
|
205
|
-
|
|
359
|
+
/**
|
|
360
|
+
* Tạo JSON linter
|
|
361
|
+
* Sử dụng JSON.parse để validate
|
|
362
|
+
*/
|
|
363
|
+
createJsonLinter() {
|
|
206
364
|
return linter((view) => {
|
|
207
365
|
const text = view.state.doc.toString();
|
|
208
366
|
const diagnostics = [];
|
|
@@ -221,11 +379,18 @@ class LibsUiComponentsPreviewTextDataComponent {
|
|
|
221
379
|
return diagnostics;
|
|
222
380
|
});
|
|
223
381
|
}
|
|
224
|
-
|
|
225
|
-
|
|
382
|
+
/**
|
|
383
|
+
* Tạo SQL linter
|
|
384
|
+
* Lazy load node-sql-parser chỉ khi cần
|
|
385
|
+
*/
|
|
386
|
+
createSqlLinter() {
|
|
387
|
+
return linter(async (view) => {
|
|
226
388
|
const text = view.state.doc.toString();
|
|
227
389
|
const diagnostics = [];
|
|
228
390
|
try {
|
|
391
|
+
// Lazy load SQL parser chỉ khi thực sự cần
|
|
392
|
+
const { Parser } = await import('node-sql-parser');
|
|
393
|
+
const sqlParser = new Parser();
|
|
229
394
|
sqlParser.astify(text);
|
|
230
395
|
}
|
|
231
396
|
catch (err) {
|
|
@@ -240,36 +405,50 @@ class LibsUiComponentsPreviewTextDataComponent {
|
|
|
240
405
|
return diagnostics;
|
|
241
406
|
});
|
|
242
407
|
}
|
|
408
|
+
// ==========================================================================
|
|
409
|
+
// PROTECTED METHODS - Event handlers
|
|
410
|
+
// ==========================================================================
|
|
243
411
|
handlerCopy() {
|
|
244
412
|
navigator.clipboard.writeText(this.content() || '');
|
|
245
413
|
this.notificationService.showCompTypeTextInfo('Sao chép thành công');
|
|
246
414
|
}
|
|
247
415
|
handlerLineWrap() {
|
|
416
|
+
console.log('handlerLineWrap', this.isWrap());
|
|
417
|
+
// Lấy nội dung mới nhất từ editor sau khi đã xóa newlines
|
|
418
|
+
const currentContent = this.editorViewInstance?.state.doc.toString() || '';
|
|
419
|
+
const updatedContent = this.isWrap() && currentContent ? currentContent.replace(/\n/g, ' ') : this.content();
|
|
248
420
|
this.isWrap.update((val) => !val);
|
|
421
|
+
console.log('updatedContent', this.isWrap());
|
|
422
|
+
console.log('currentContent', currentContent);
|
|
423
|
+
console.log('updatedContent', updatedContent);
|
|
424
|
+
if (currentContent !== updatedContent) {
|
|
425
|
+
this.editorViewInstance?.dispatch({
|
|
426
|
+
changes: { from: 0, to: currentContent.length, insert: updatedContent },
|
|
427
|
+
});
|
|
428
|
+
}
|
|
429
|
+
// Batch cả 2 dispatch thành 1 để tối ưu performance
|
|
249
430
|
this.editorViewInstance?.dispatch({
|
|
250
|
-
effects: this.wrapCompartment.reconfigure(this.isWrap() ? EditorView.lineWrapping : []),
|
|
251
|
-
});
|
|
252
|
-
this.editorViewInstance?.dispatch({
|
|
253
|
-
effects: this.lineNumberCompartment.reconfigure(this.isWrap() ? lineNumbers() : [] // 👈 nếu tắt thì remove extension
|
|
254
|
-
),
|
|
431
|
+
effects: [this.wrapCompartment.reconfigure(this.isWrap() ? EditorView.lineWrapping : []), this.lineNumberCompartment.reconfigure(this.isWrap() ? lineNumbers() : [])],
|
|
255
432
|
});
|
|
256
433
|
this.outChange.emit({
|
|
257
|
-
content:
|
|
434
|
+
content: updatedContent,
|
|
258
435
|
isWrap: this.isWrap(),
|
|
259
436
|
language: this.langSelected(),
|
|
260
437
|
contextChange: 'isWrap',
|
|
261
438
|
});
|
|
262
439
|
}
|
|
263
|
-
handlerSelectKey(data) {
|
|
264
|
-
if (!data
|
|
440
|
+
async handlerSelectKey(data) {
|
|
441
|
+
if (!data?.key) {
|
|
265
442
|
return;
|
|
266
443
|
}
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
444
|
+
const newLang = data.key;
|
|
445
|
+
this.langSelected.set(newLang);
|
|
446
|
+
// Load language và linter mới
|
|
447
|
+
const [languageExtension, linterExtension] = await Promise.all([this.loadLanguageExtension(newLang), this.loadLinterExtension(newLang)]);
|
|
448
|
+
// Reconfigure thay vì tạo mới state để giữ lại document content
|
|
449
|
+
this.editorViewInstance?.dispatch({
|
|
450
|
+
effects: [this.languageCompartment.reconfigure(languageExtension), this.linterCompartment.reconfigure(linterExtension)],
|
|
451
|
+
});
|
|
273
452
|
this.outChange.emit({
|
|
274
453
|
content: this.content(),
|
|
275
454
|
isWrap: this.isWrap(),
|
|
@@ -283,11 +462,11 @@ class LibsUiComponentsPreviewTextDataComponent {
|
|
|
283
462
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: LibsUiComponentsPreviewTextDataComponent, decorators: [{
|
|
284
463
|
type: Component,
|
|
285
464
|
args: [{ selector: 'libs_ui-components-preview_text_data', standalone: true, changeDetection: ChangeDetectionStrategy.OnPush, imports: [LibsUiComponentsDropdownComponent, LibsUiComponentsButtonsButtonComponent], template: "<div\n class=\"libs-ui-preview-data-container flex flex-col w-full h-auto rounded-[8px] libs-ui-border-general px-[8px]\"\n [style.--background-color]=\"background()\"\n [class.pt-[8px]]=\"!hiddenAction()\">\n @if (!hiddenAction()) {\n <div class=\"flex items-center content-between color-[#6a7383]\">\n <libs_ui-components-dropdown\n classInclude=\"w-[200px]\"\n [listConfig]=\"configLoadDataIsHttpConfig\"\n [listMaxItemShow]=\"5\"\n [isNgContent]=\"true\"\n [readonly]=\"!editable()\"\n [listHasButtonUnSelectOption]=\"false\"\n (outSelectKey)=\"handlerSelectKey($event)\">\n <libs_ui-components-buttons-button\n [type]=\"'button-link-third'\"\n [label]=\"labelLang() || ''\"\n [sizeButton]=\"'small'\"\n [classIconRight]=\"editable() ? 'libs-ui-icon-move-right rotate-90' : ''\"\n [classInclude]=\"'!p-[0px]' + (editable() ? '' : '!pointer-events-none !cursor-default hover:!text-[#6A7383]')\" />\n </libs_ui-components-dropdown>\n <div class=\"flex items-center\">\n <libs_ui-components-buttons-button\n [type]=\"'button-link-third'\"\n [label]=\"isWrap() ? 'i18n_remove_line_wrap' : 'i18n_line_wrap'\"\n [sizeButton]=\"'small'\"\n [classIconLeft]=\"isWrap() ? 'libs-ui-icon-unwrap' : 'libs-ui-icon-wrap'\"\n [classInclude]=\"'mo-lib-p-0px mo-lib-mr-16px'\"\n (outClick)=\"handlerLineWrap()\" />\n <libs_ui-components-buttons-button\n [type]=\"'button-link-third'\"\n [label]=\"'i18n_copy'\"\n [sizeButton]=\"'small'\"\n [classIconLeft]=\"'libs-ui-icon-copy'\"\n [classInclude]=\"'mo-lib-p-0px'\"\n (outClick)=\"handlerCopy()\" />\n </div>\n </div>\n }\n <div #containerPreview></div>\n</div>\n", styles: [":host ::ng-deep .libs-ui-preview-data-container{background-color:var(--background-color)!important}:host ::ng-deep .libs-ui-preview-data-container .cm-line{white-space:pre-wrap}:host ::ng-deep .libs-ui-preview-data-container .cm-lintRange-error{background-color:#ff323233;border-bottom:2px solid red}:host ::ng-deep .libs-ui-preview-data-container .cm-lintRange-warning{background-color:#ffc80026}:host ::ng-deep .libs-ui-preview-data-container .cm-tooltip-lint{background:#fff8f8;color:#d32f2f;border:1px solid #f44336;padding:8px 10px;font-size:13px;font-family:Inter,sans-serif;border-radius:6px;box-shadow:0 2px 8px #ff000026}:host ::ng-deep .libs-ui-preview-data-container .cm-focused{outline:none!important}:host ::ng-deep .libs-ui-preview-data-container .cm-gutters{background-color:var(--background-color)!important}\n"] }]
|
|
286
|
-
}] });
|
|
465
|
+
}], ctorParameters: () => [] });
|
|
287
466
|
|
|
288
467
|
/**
|
|
289
468
|
* Generated bundle index. Do not edit.
|
|
290
469
|
*/
|
|
291
470
|
|
|
292
|
-
export { LibsUiComponentsPreviewTextDataComponent, httpRequestConfigGetOptionsLang,
|
|
471
|
+
export { LibsUiComponentsPreviewTextDataComponent, createDefaultLanguage, httpRequestConfigGetOptionsLang, languageRegistry, optionsLangData };
|
|
293
472
|
//# sourceMappingURL=libs-ui-components-preview-text-data.mjs.map
|