@sd-angular/core 19.0.0-beta.12 → 19.0.0-beta.14
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/assets/scss/ckeditor5.scss +59 -2
- package/components/document-builder/src/document-builder.component.d.ts +7 -2
- package/components/document-builder/src/document-builder.model.d.ts +5 -1
- package/components/document-builder/src/plugins/highlight-range/highlight-range.plugin.d.ts +4 -0
- package/components/document-builder/src/plugins/image-custom/image-custom.plugin.d.ts +31 -0
- package/components/document-builder/src/plugins/index.d.ts +1 -0
- package/components/index.d.ts +1 -0
- package/components/mini-editor/index.d.ts +2 -0
- package/components/mini-editor/src/mini-editor.component.d.ts +90 -0
- package/components/mini-editor/src/mini-editor.model.d.ts +42 -0
- package/components/view/index.d.ts +1 -0
- package/components/view/src/view.component.d.ts +14 -0
- package/directives/index.d.ts +1 -0
- package/directives/src/sd-href.directive.d.ts +9 -0
- package/fesm2022/sd-angular-core-components-document-builder.mjs +479 -48
- package/fesm2022/sd-angular-core-components-document-builder.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components-mini-editor.mjs +326 -0
- package/fesm2022/sd-angular-core-components-mini-editor.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components-view.mjs +88 -0
- package/fesm2022/sd-angular-core-components-view.mjs.map +1 -0
- package/fesm2022/sd-angular-core-components-workflow.mjs +16 -26
- package/fesm2022/sd-angular-core-components-workflow.mjs.map +1 -1
- package/fesm2022/sd-angular-core-components.mjs +1 -0
- package/fesm2022/sd-angular-core-components.mjs.map +1 -1
- package/fesm2022/sd-angular-core-directives.mjs +51 -2
- package/fesm2022/sd-angular-core-directives.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-radio.mjs +3 -2
- package/fesm2022/sd-angular-core-forms-radio.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-select.mjs +5 -3
- package/fesm2022/sd-angular-core-forms-select.mjs.map +1 -1
- package/fesm2022/sd-angular-core-forms-textarea.mjs +2 -2
- package/fesm2022/sd-angular-core-forms-textarea.mjs.map +1 -1
- package/fesm2022/sd-angular-core-modules-layout.mjs +52 -17
- package/fesm2022/sd-angular-core-modules-layout.mjs.map +1 -1
- package/fesm2022/sd-angular-core-modules-oidc.mjs +0 -2
- package/fesm2022/sd-angular-core-modules-oidc.mjs.map +1 -1
- package/modules/layout/components/sidebar-v1/components/sidebar/sidebar.component.d.ts +1 -0
- package/modules/layout/components/sidebar-v1/components/user/user.component.d.ts +5 -2
- package/modules/layout/configurations/layout.configuration.d.ts +3 -0
- package/modules/layout/services/storage/storage.service.d.ts +1 -0
- package/package.json +32 -24
- package/sd-angular-core-19.0.0-beta.14.tgz +0 -0
- package/sd-angular-core-19.0.0-beta.12.tgz +0 -0
|
@@ -3,7 +3,7 @@ import { EventEmitter, Output, Input, Component } from '@angular/core';
|
|
|
3
3
|
import { CommonModule } from '@angular/common';
|
|
4
4
|
import * as i1 from '@ckeditor/ckeditor5-angular';
|
|
5
5
|
import { CKEditorModule } from '@ckeditor/ckeditor5-angular';
|
|
6
|
-
import { Plugin, ButtonView, ClassicEditor, Essentials, Paragraph, Bold, Italic, Underline, FontSize, FontColor, FontBackgroundColor, Alignment, Widget, toWidget, GeneralHtmlSupport, FontFamily, Heading, List, Table, TableToolbar, TableProperties, TableCellProperties, TableColumnResize, PasteFromOffice, PageBreak, Undo, Subscript, Superscript, Image, ImageUpload, ImageToolbar, ImageCaption, ImageResize, ImageStyle } from 'ckeditor5';
|
|
6
|
+
import { Plugin, ButtonView, ClassicEditor, Essentials, Paragraph, Bold, Italic, Underline, FontSize, FontColor, FontBackgroundColor, Alignment, Widget, toWidget, GeneralHtmlSupport, FontFamily, Heading, List, Table, TableToolbar, TableProperties, TableCellProperties, TableColumnResize, PasteFromOffice, PageBreak, Undo, Subscript, Superscript, Image, ImageUpload, ImageToolbar, ImageCaption, ImageResize, ImageStyle, ImageBlock, Indent, IndentBlock } from 'ckeditor5';
|
|
7
7
|
import { Subscription, Subject, throttleTime } from 'rxjs';
|
|
8
8
|
import { SdResolveMaybeAsync, hslToHex, rgbToHex, SdUtilities } from '@sd-angular/core/utilities';
|
|
9
9
|
import { v4 } from 'uuid';
|
|
@@ -200,7 +200,7 @@ class CommentPlugin extends Plugin {
|
|
|
200
200
|
// BẮN EVENT RA NGOÀI - KHÔNG TỰ ADD MARKER
|
|
201
201
|
// Angular component sẽ xử lý logic (mở modal, validation, etc.)
|
|
202
202
|
// và gọi lại hàm addComment() nếu cần
|
|
203
|
-
option.onAddComment(range);
|
|
203
|
+
option.onAddComment({ range, selectedText });
|
|
204
204
|
});
|
|
205
205
|
return view;
|
|
206
206
|
});
|
|
@@ -253,8 +253,8 @@ class VariablePlugin extends Plugin {
|
|
|
253
253
|
isObject: true,
|
|
254
254
|
allowAttributes: ['id', 'uuid', 'value', 'display'],
|
|
255
255
|
});
|
|
256
|
-
//
|
|
257
|
-
conversion.for('
|
|
256
|
+
// 2. Model -> HTML
|
|
257
|
+
conversion.for('downcast').elementToElement({
|
|
258
258
|
model: 'variable',
|
|
259
259
|
view: (modelItem, { writer: viewWriter }) => {
|
|
260
260
|
const id = modelItem.getAttribute('id');
|
|
@@ -273,31 +273,22 @@ class VariablePlugin extends Plugin {
|
|
|
273
273
|
return toWidget(widgetElement, viewWriter);
|
|
274
274
|
},
|
|
275
275
|
});
|
|
276
|
-
//
|
|
277
|
-
conversion.for('dataDowncast').elementToElement({
|
|
278
|
-
model: 'variable',
|
|
279
|
-
view: (modelItem, { writer: viewWriter }) => {
|
|
280
|
-
const id = modelItem.getAttribute('id');
|
|
281
|
-
const uuid = modelItem.getAttribute('uuid');
|
|
282
|
-
const display = modelItem.getAttribute('display');
|
|
283
|
-
const value = modelItem.getAttribute('value');
|
|
284
|
-
const widgetElement = viewWriter.createContainerElement('span', {
|
|
285
|
-
class: 'variable-widget',
|
|
286
|
-
'data-id': id,
|
|
287
|
-
'data-uuid': uuid,
|
|
288
|
-
'data-value': value,
|
|
289
|
-
'data-display': display,
|
|
290
|
-
});
|
|
291
|
-
const innerText = viewWriter.createText(`{{${display}}}`);
|
|
292
|
-
viewWriter.insert(viewWriter.createPositionAt(widgetElement, 0), innerText);
|
|
293
|
-
return widgetElement;
|
|
294
|
-
},
|
|
295
|
-
});
|
|
296
|
-
// 3. HTML -> model của CDK
|
|
276
|
+
// 3. HTML -> Model
|
|
297
277
|
conversion.for('upcast').elementToElement({
|
|
278
|
+
// NOTE: Khi bổ sung thêm attribute vào element variable, dev nên bổ sung thêm "[atribute]: true" vào view
|
|
279
|
+
// Để:
|
|
280
|
+
// - Nếu lọc chính xác sẽ không sinh ra thẻ span thừa bọc ngoài
|
|
281
|
+
// - Nếu chưa bổ sung thì sẽ sinh ra thẻ <span> bọc ngoài kèm [atribute] chưa lọc
|
|
298
282
|
view: {
|
|
299
283
|
name: 'span',
|
|
300
|
-
classes: 'variable-widget',
|
|
284
|
+
classes: 'variable-widget ck-widget',
|
|
285
|
+
attributes: {
|
|
286
|
+
'data-id': true,
|
|
287
|
+
'data-uuid': true,
|
|
288
|
+
'data-value': true,
|
|
289
|
+
'data-display': true,
|
|
290
|
+
contenteditable: true,
|
|
291
|
+
},
|
|
301
292
|
},
|
|
302
293
|
model: (viewElement, { writer: modelWriter }) => {
|
|
303
294
|
return modelWriter.createElement('variable', {
|
|
@@ -510,6 +501,52 @@ class VariablePlugin extends Plugin {
|
|
|
510
501
|
class TableFitPlugin extends Plugin {
|
|
511
502
|
init() {
|
|
512
503
|
const editor = this.editor;
|
|
504
|
+
const applyTableDefaults = (writer, tableElement) => {
|
|
505
|
+
if (!tableElement)
|
|
506
|
+
return;
|
|
507
|
+
// Always force table width to 100% on paste/insert
|
|
508
|
+
writer.setAttribute('tableWidth', '100%', tableElement);
|
|
509
|
+
};
|
|
510
|
+
const applyCellBorders = (writer, tableElement) => {
|
|
511
|
+
if (!tableElement)
|
|
512
|
+
return;
|
|
513
|
+
for (const row of tableElement.getChildren()) {
|
|
514
|
+
for (const cell of row.getChildren()) {
|
|
515
|
+
const hasBorderColor = cell.getAttribute('tableCellBorderColor');
|
|
516
|
+
const hasBorderStyle = cell.getAttribute('tableCellBorderStyle');
|
|
517
|
+
const hasBorderWidth = cell.getAttribute('tableCellBorderWidth');
|
|
518
|
+
const hasPadding = cell.getAttribute('tableCellPadding');
|
|
519
|
+
if (!hasBorderColor) {
|
|
520
|
+
writer.setAttribute('tableCellBorderColor', '#000000', cell);
|
|
521
|
+
}
|
|
522
|
+
if (!hasBorderStyle) {
|
|
523
|
+
writer.setAttribute('tableCellBorderStyle', 'solid', cell);
|
|
524
|
+
}
|
|
525
|
+
if (!hasBorderWidth) {
|
|
526
|
+
writer.setAttribute('tableCellBorderWidth', '1pt', cell);
|
|
527
|
+
}
|
|
528
|
+
if (!hasPadding) {
|
|
529
|
+
writer.setAttribute('tableCellPadding', '0.4em', cell);
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
};
|
|
534
|
+
const listenAndApplyOnExecute = (commandName) => {
|
|
535
|
+
const cmd = editor.commands.get(commandName);
|
|
536
|
+
if (!cmd)
|
|
537
|
+
return;
|
|
538
|
+
this.listenTo(cmd, 'execute', () => {
|
|
539
|
+
editor.model.change(writer => {
|
|
540
|
+
const selection = editor.model.document.selection;
|
|
541
|
+
const position = selection.getFirstPosition();
|
|
542
|
+
if (!position)
|
|
543
|
+
return;
|
|
544
|
+
const tableElement = position.findAncestor('table');
|
|
545
|
+
applyTableDefaults(writer, tableElement);
|
|
546
|
+
applyCellBorders(writer, tableElement);
|
|
547
|
+
});
|
|
548
|
+
});
|
|
549
|
+
};
|
|
513
550
|
// Can thiệp vào quá trình convert từ View (HTML Paste) sang Model
|
|
514
551
|
editor.conversion.for('upcast').add(dispatcher => {
|
|
515
552
|
dispatcher.on('element:table', (evt, data, conversionApi) => {
|
|
@@ -523,7 +560,8 @@ class TableFitPlugin extends Plugin {
|
|
|
523
560
|
for (const item of modelRange.getItems()) {
|
|
524
561
|
if (item.is('element', 'table')) {
|
|
525
562
|
editor.model.change(writer => {
|
|
526
|
-
writer
|
|
563
|
+
applyTableDefaults(writer, item);
|
|
564
|
+
applyCellBorders(writer, item);
|
|
527
565
|
});
|
|
528
566
|
}
|
|
529
567
|
}
|
|
@@ -533,6 +571,52 @@ class TableFitPlugin extends Plugin {
|
|
|
533
571
|
}, { priority: 'low' });
|
|
534
572
|
// Chạy sau cùng để ghi đè các logic mặc định
|
|
535
573
|
});
|
|
574
|
+
const findInnerTable = (viewElement) => {
|
|
575
|
+
if (!viewElement)
|
|
576
|
+
return null;
|
|
577
|
+
if (viewElement.name === 'table')
|
|
578
|
+
return viewElement;
|
|
579
|
+
for (const child of viewElement.getChildren()) {
|
|
580
|
+
if (child.name === 'table')
|
|
581
|
+
return child;
|
|
582
|
+
const found = findInnerTable(child);
|
|
583
|
+
if (found)
|
|
584
|
+
return found;
|
|
585
|
+
}
|
|
586
|
+
return null;
|
|
587
|
+
};
|
|
588
|
+
editor.conversion.for('downcast').add(dispatcher => {
|
|
589
|
+
// Handle when tableWidth attribute changes
|
|
590
|
+
dispatcher.on('attribute:tableWidth:table', (evt, data, conversionApi) => {
|
|
591
|
+
const viewWriter = conversionApi.writer;
|
|
592
|
+
const viewElement = conversionApi.mapper.toViewElement(data.item);
|
|
593
|
+
if (!viewElement)
|
|
594
|
+
return;
|
|
595
|
+
const innerTable = findInnerTable(viewElement);
|
|
596
|
+
if (!innerTable)
|
|
597
|
+
return;
|
|
598
|
+
viewWriter.setStyle('border-collapse', 'collapse', innerTable);
|
|
599
|
+
viewWriter.setStyle('margin', '0', innerTable);
|
|
600
|
+
viewWriter.setStyle('width', '100%', innerTable);
|
|
601
|
+
// Set width on the wrapper container (ck-widget) as well
|
|
602
|
+
viewWriter.setStyle('width', '100%', viewElement);
|
|
603
|
+
});
|
|
604
|
+
// Handle when table is first inserted
|
|
605
|
+
dispatcher.on('insert:table', (evt, data, conversionApi) => {
|
|
606
|
+
const viewWriter = conversionApi.writer;
|
|
607
|
+
const viewElement = conversionApi.mapper.toViewElement(data.item);
|
|
608
|
+
if (!viewElement)
|
|
609
|
+
return;
|
|
610
|
+
const innerTable = findInnerTable(viewElement);
|
|
611
|
+
if (!innerTable)
|
|
612
|
+
return;
|
|
613
|
+
viewWriter.setStyle('border-collapse', 'collapse', innerTable);
|
|
614
|
+
viewWriter.setStyle('margin', '0', innerTable);
|
|
615
|
+
viewWriter.setStyle('width', '100%', innerTable);
|
|
616
|
+
// Set width on the wrapper container (ck-widget) as well
|
|
617
|
+
viewWriter.setStyle('width', '100%', viewElement);
|
|
618
|
+
});
|
|
619
|
+
});
|
|
536
620
|
// Lắng nghe lệnh insertTable để can thiệp ngay sau khi bảng được tạo
|
|
537
621
|
const insertTableCommand = editor.commands.get('insertTable');
|
|
538
622
|
if (insertTableCommand) {
|
|
@@ -549,11 +633,20 @@ class TableFitPlugin extends Plugin {
|
|
|
549
633
|
const tableElement = position.findAncestor('table');
|
|
550
634
|
if (tableElement) {
|
|
551
635
|
// Ép width 100% cho bảng mới vẽ
|
|
552
|
-
writer
|
|
636
|
+
applyTableDefaults(writer, tableElement);
|
|
637
|
+
// Apply border style 1pt solid black
|
|
638
|
+
writer.setAttribute('tableBorderColor', '#000000', tableElement);
|
|
639
|
+
writer.setAttribute('tableBorderStyle', 'solid', tableElement);
|
|
640
|
+
writer.setAttribute('tableBorderWidth', '1pt', tableElement);
|
|
641
|
+
applyCellBorders(writer, tableElement);
|
|
553
642
|
}
|
|
554
643
|
});
|
|
555
644
|
});
|
|
556
645
|
}
|
|
646
|
+
listenAndApplyOnExecute('insertTableRowAbove');
|
|
647
|
+
listenAndApplyOnExecute('insertTableRowBelow');
|
|
648
|
+
listenAndApplyOnExecute('insertTableColumnLeft');
|
|
649
|
+
listenAndApplyOnExecute('insertTableColumnRight');
|
|
557
650
|
}
|
|
558
651
|
}
|
|
559
652
|
|
|
@@ -601,6 +694,243 @@ class Base64UploadAdapter {
|
|
|
601
694
|
}
|
|
602
695
|
}
|
|
603
696
|
|
|
697
|
+
class ImageCustomPlugin extends Plugin {
|
|
698
|
+
static get pluginName() {
|
|
699
|
+
return 'ImageCustomPlugin';
|
|
700
|
+
}
|
|
701
|
+
init() {
|
|
702
|
+
const editor = this.editor;
|
|
703
|
+
// Thiết lập style mặc định là alignCenter khi chèn ảnh
|
|
704
|
+
editor.commands.get('imageUpload')?.on('execute', (evt, args) => {
|
|
705
|
+
// Đặt style mặc định sau khi ảnh được chèn
|
|
706
|
+
setTimeout(() => {
|
|
707
|
+
const selection = editor.model.document.selection;
|
|
708
|
+
const imageElement = selection.getSelectedElement();
|
|
709
|
+
if (imageElement && (imageElement.name === 'imageBlock' || imageElement.name === 'imageInline')) {
|
|
710
|
+
const currentStyle = imageElement.getAttribute('imageStyle');
|
|
711
|
+
// Chỉ đặt mặc định nếu chưa có style nào
|
|
712
|
+
if (!currentStyle) {
|
|
713
|
+
editor.model.change(writer => {
|
|
714
|
+
writer.setAttribute('imageStyle', 'alignCenter', imageElement);
|
|
715
|
+
});
|
|
716
|
+
}
|
|
717
|
+
}
|
|
718
|
+
}, 0);
|
|
719
|
+
});
|
|
720
|
+
// Downcast: Model -> View (HTML output)
|
|
721
|
+
// CKEditor 5 có 2 loại ảnh: imageBlock và imageInline
|
|
722
|
+
editor.conversion.for('downcast').add(dispatcher => {
|
|
723
|
+
// Xử lý ảnh block (được wrap trong figure)
|
|
724
|
+
dispatcher.on('insert:imageBlock', (evt, data, conversionApi) => {
|
|
725
|
+
this.handleImageInsert(evt, data, conversionApi);
|
|
726
|
+
}, { priority: 'low' });
|
|
727
|
+
// Xử lý ảnh inline
|
|
728
|
+
dispatcher.on('insert:imageInline', (evt, data, conversionApi) => {
|
|
729
|
+
this.handleImageInsert(evt, data, conversionApi);
|
|
730
|
+
}, { priority: 'low' });
|
|
731
|
+
// Xử lý thay đổi attribute cho cả 2 loại ảnh
|
|
732
|
+
['imageBlock', 'imageInline'].forEach(imageType => {
|
|
733
|
+
// Xử lý thay đổi src
|
|
734
|
+
dispatcher.on(`attribute:src:${imageType}`, (evt, data, conversionApi) => {
|
|
735
|
+
this.handleImageAttributeChange(evt, data, conversionApi);
|
|
736
|
+
}, { priority: 'low' });
|
|
737
|
+
// Xử lý thay đổi width
|
|
738
|
+
dispatcher.on(`attribute:width:${imageType}`, (evt, data, conversionApi) => {
|
|
739
|
+
this.handleImageAttributeChange(evt, data, conversionApi);
|
|
740
|
+
}, { priority: 'low' });
|
|
741
|
+
// Xử lý thay đổi height
|
|
742
|
+
dispatcher.on(`attribute:height:${imageType}`, (evt, data, conversionApi) => {
|
|
743
|
+
this.handleImageAttributeChange(evt, data, conversionApi);
|
|
744
|
+
}, { priority: 'low' });
|
|
745
|
+
// Xử lý thay đổi imageStyle (căn chỉnh) - thêm float inline style
|
|
746
|
+
dispatcher.on(`attribute:imageStyle:${imageType}`, (evt, data, conversionApi) => {
|
|
747
|
+
this.handleImageStyleChange(evt, data, conversionApi);
|
|
748
|
+
}, { priority: 'low' });
|
|
749
|
+
});
|
|
750
|
+
});
|
|
751
|
+
// Xử lý upcast (HTML paste) - xóa aspect-ratio từ HTML đầu vào
|
|
752
|
+
editor.conversion.for('upcast').add(dispatcher => {
|
|
753
|
+
dispatcher.on('element:img', (evt, data, conversionApi) => {
|
|
754
|
+
const viewItem = data.viewItem;
|
|
755
|
+
if (!viewItem)
|
|
756
|
+
return;
|
|
757
|
+
// Kiểm tra viewItem có các method cần thiết
|
|
758
|
+
if (typeof viewItem.getStyle !== 'function')
|
|
759
|
+
return;
|
|
760
|
+
// Xóa aspect-ratio từ inline styles nếu có
|
|
761
|
+
const hasAspectRatio = viewItem.getStyle('aspect-ratio');
|
|
762
|
+
if (hasAspectRatio && typeof viewItem.removeStyle === 'function') {
|
|
763
|
+
viewItem.removeStyle('aspect-ratio');
|
|
764
|
+
}
|
|
765
|
+
// Đặt custom styles nếu _styles map tồn tại
|
|
766
|
+
if (viewItem._styles && typeof viewItem._styles.set === 'function') {
|
|
767
|
+
viewItem._styles.set('margin', '0');
|
|
768
|
+
viewItem._styles.set('border', '0');
|
|
769
|
+
viewItem._styles.set('max-width', '100%');
|
|
770
|
+
viewItem._styles.set('height', 'auto');
|
|
771
|
+
}
|
|
772
|
+
}, { priority: 'high' });
|
|
773
|
+
});
|
|
774
|
+
}
|
|
775
|
+
/**
|
|
776
|
+
* Xử lý sự kiện chèn ảnh
|
|
777
|
+
*/
|
|
778
|
+
handleImageInsert(evt, data, conversionApi) {
|
|
779
|
+
const viewWriter = conversionApi.writer;
|
|
780
|
+
const viewElement = conversionApi.mapper.toViewElement(data.item);
|
|
781
|
+
if (!viewElement)
|
|
782
|
+
return;
|
|
783
|
+
// viewElement có thể là figure (cho block) hoặc img itself (cho inline)
|
|
784
|
+
// Tìm element img thực tế
|
|
785
|
+
const imgElement = this.findImgElement(viewElement);
|
|
786
|
+
if (!imgElement)
|
|
787
|
+
return;
|
|
788
|
+
this.applyCustomStyles(viewWriter, imgElement);
|
|
789
|
+
}
|
|
790
|
+
/**
|
|
791
|
+
* Xử lý sự kiện thay đổi attribute ảnh
|
|
792
|
+
*/
|
|
793
|
+
handleImageAttributeChange(evt, data, conversionApi) {
|
|
794
|
+
const viewWriter = conversionApi.writer;
|
|
795
|
+
const viewElement = conversionApi.mapper.toViewElement(data.item);
|
|
796
|
+
if (!viewElement)
|
|
797
|
+
return;
|
|
798
|
+
const imgElement = this.findImgElement(viewElement);
|
|
799
|
+
if (!imgElement)
|
|
800
|
+
return;
|
|
801
|
+
this.applyCustomStyles(viewWriter, imgElement);
|
|
802
|
+
}
|
|
803
|
+
/**
|
|
804
|
+
* Xử lý sự kiện thay đổi style ảnh - thêm float inline style cho căn chỉnh
|
|
805
|
+
*/
|
|
806
|
+
handleImageStyleChange(evt, data, conversionApi) {
|
|
807
|
+
const viewWriter = conversionApi.writer;
|
|
808
|
+
const viewElement = conversionApi.mapper.toViewElement(data.item);
|
|
809
|
+
if (!viewElement)
|
|
810
|
+
return;
|
|
811
|
+
// Tìm container ck-widget (element figure)
|
|
812
|
+
const widgetElement = this.findWidgetElement(viewElement);
|
|
813
|
+
if (!widgetElement)
|
|
814
|
+
return;
|
|
815
|
+
// Lấy giá trị imageStyle (căn chỉnh)
|
|
816
|
+
const imageStyle = data.item.getAttribute('imageStyle');
|
|
817
|
+
// Xóa các style hiện có trước
|
|
818
|
+
viewWriter.removeStyle('float', widgetElement);
|
|
819
|
+
viewWriter.removeStyle('margin', widgetElement);
|
|
820
|
+
viewWriter.removeStyle('text-align', widgetElement);
|
|
821
|
+
// Áp dụng style dựa trên căn chỉnh ảnh
|
|
822
|
+
// Các options đã cấu hình: ['inline', 'alignLeft', 'alignRight', 'alignCenter']
|
|
823
|
+
switch (imageStyle) {
|
|
824
|
+
case 'inline':
|
|
825
|
+
// Ảnh inline - không style đặc biệt, chỉ flow inline
|
|
826
|
+
break;
|
|
827
|
+
case 'alignLeft':
|
|
828
|
+
// Float trái
|
|
829
|
+
viewWriter.setStyle('float', 'left', widgetElement);
|
|
830
|
+
viewWriter.setStyle('margin', '0 16px 16px 0', widgetElement);
|
|
831
|
+
break;
|
|
832
|
+
case 'alignRight':
|
|
833
|
+
// Float phải
|
|
834
|
+
viewWriter.setStyle('float', 'right', widgetElement);
|
|
835
|
+
viewWriter.setStyle('margin', '0 0 16px 16px', widgetElement);
|
|
836
|
+
break;
|
|
837
|
+
case 'alignCenter':
|
|
838
|
+
case 'block':
|
|
839
|
+
// Căn giữa
|
|
840
|
+
viewWriter.setStyle('text-align', 'center', widgetElement);
|
|
841
|
+
viewWriter.setStyle('margin', '16px auto', widgetElement);
|
|
842
|
+
break;
|
|
843
|
+
default:
|
|
844
|
+
// Mặc định - căn giữa
|
|
845
|
+
viewWriter.setStyle('text-align', 'center', widgetElement);
|
|
846
|
+
viewWriter.setStyle('margin', '16px auto', widgetElement);
|
|
847
|
+
break;
|
|
848
|
+
}
|
|
849
|
+
// Áp dụng custom styles cơ bản cho element img
|
|
850
|
+
const imgElement = this.findImgElement(viewElement);
|
|
851
|
+
if (imgElement) {
|
|
852
|
+
this.applyCustomStyles(viewWriter, imgElement);
|
|
853
|
+
}
|
|
854
|
+
}
|
|
855
|
+
/**
|
|
856
|
+
* Áp dụng custom styles cho element ảnh
|
|
857
|
+
*/
|
|
858
|
+
applyCustomStyles(viewWriter, imgElement) {
|
|
859
|
+
// Xóa aspect-ratio nếu tồn tại
|
|
860
|
+
if (imgElement.getStyle('aspect-ratio')) {
|
|
861
|
+
viewWriter.removeStyle('aspect-ratio', imgElement);
|
|
862
|
+
}
|
|
863
|
+
// Áp dụng custom styles
|
|
864
|
+
viewWriter.setStyle('margin', '0', imgElement);
|
|
865
|
+
viewWriter.setStyle('border', '0', imgElement);
|
|
866
|
+
viewWriter.setStyle('max-width', '100%', imgElement);
|
|
867
|
+
viewWriter.setStyle('height', 'auto', imgElement);
|
|
868
|
+
}
|
|
869
|
+
/**
|
|
870
|
+
* Tìm container ck-widget (element figure)
|
|
871
|
+
* CKEditor wrap ảnh block trong <figure class="ck-widget"><img></figure>
|
|
872
|
+
*/
|
|
873
|
+
findWidgetElement(viewElement) {
|
|
874
|
+
if (!viewElement)
|
|
875
|
+
return null;
|
|
876
|
+
// Nếu đây là element figure itself
|
|
877
|
+
if (viewElement.name === 'figure') {
|
|
878
|
+
return viewElement;
|
|
879
|
+
}
|
|
880
|
+
// Cho ảnh inline, trả về element itself (span wrapper)
|
|
881
|
+
if (viewElement.name === 'span') {
|
|
882
|
+
return viewElement;
|
|
883
|
+
}
|
|
884
|
+
// Tìm ngược lên tree để tìm figure/ck-widget
|
|
885
|
+
let current = viewElement;
|
|
886
|
+
while (current) {
|
|
887
|
+
if (current.name === 'figure' || current.name === 'span') {
|
|
888
|
+
return current;
|
|
889
|
+
}
|
|
890
|
+
// Di chuyển lên parent
|
|
891
|
+
if (current.parent) {
|
|
892
|
+
current = current.parent;
|
|
893
|
+
}
|
|
894
|
+
else {
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
// Nếu không tìm thấy widget, trả về element gốc
|
|
899
|
+
return viewElement;
|
|
900
|
+
}
|
|
901
|
+
/**
|
|
902
|
+
* Tìm element img thực tế bên trong widget structure
|
|
903
|
+
* CKEditor wrap ảnh block trong <figure class="ck-widget"><img></figure>
|
|
904
|
+
*/
|
|
905
|
+
findImgElement(viewElement) {
|
|
906
|
+
if (!viewElement)
|
|
907
|
+
return null;
|
|
908
|
+
// Nếu đây là element img itself
|
|
909
|
+
if (viewElement.name === 'img') {
|
|
910
|
+
return viewElement;
|
|
911
|
+
}
|
|
912
|
+
// Cho structure widget của CKEditor, tìm đệ quy
|
|
913
|
+
// Ảnh block: figure > span > img
|
|
914
|
+
// Ảnh thường được wrap trong một container
|
|
915
|
+
const queue = [viewElement];
|
|
916
|
+
while (queue.length > 0) {
|
|
917
|
+
const current = queue.shift();
|
|
918
|
+
if (!current)
|
|
919
|
+
continue;
|
|
920
|
+
if (current.name === 'img') {
|
|
921
|
+
return current;
|
|
922
|
+
}
|
|
923
|
+
// Thêm children vào queue
|
|
924
|
+
if (current.getChildren) {
|
|
925
|
+
for (const child of current.getChildren()) {
|
|
926
|
+
queue.push(child);
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
return null;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
604
934
|
// Icon khổ dọc (Mặc định cũ)
|
|
605
935
|
const ICON_PORTRAIT = '<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M14 2H6c-1.1 0-2 .9-2 2v12c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V4c0-1.1-.9-2-2-2zm0 14H6V4h8v12z"/></svg>';
|
|
606
936
|
// Icon khổ ngang (Mới)
|
|
@@ -864,6 +1194,18 @@ function normalize(content) {
|
|
|
864
1194
|
return normalized;
|
|
865
1195
|
}
|
|
866
1196
|
|
|
1197
|
+
class HighlightRangePlugin extends Plugin {
|
|
1198
|
+
init() {
|
|
1199
|
+
const editor = this.editor;
|
|
1200
|
+
editor.conversion.for('editingDowncast').markerToHighlight({
|
|
1201
|
+
model: 'highlightRange',
|
|
1202
|
+
view: {
|
|
1203
|
+
classes: 'highlight-range',
|
|
1204
|
+
},
|
|
1205
|
+
});
|
|
1206
|
+
}
|
|
1207
|
+
}
|
|
1208
|
+
|
|
867
1209
|
class SdDocumentBuilder {
|
|
868
1210
|
option;
|
|
869
1211
|
disabled = false;
|
|
@@ -918,13 +1260,18 @@ class SdDocumentBuilder {
|
|
|
918
1260
|
ImageCaption,
|
|
919
1261
|
ImageResize,
|
|
920
1262
|
ImageStyle,
|
|
1263
|
+
ImageBlock,
|
|
921
1264
|
// Custom Plugin
|
|
922
1265
|
HeadingPlugin,
|
|
923
1266
|
CommentPlugin,
|
|
924
1267
|
VariablePlugin,
|
|
925
1268
|
TableFitPlugin,
|
|
926
|
-
|
|
1269
|
+
Indent,
|
|
1270
|
+
IndentBlock,
|
|
927
1271
|
PageOrientationPlugin,
|
|
1272
|
+
ImageUploadPlugin,
|
|
1273
|
+
ImageCustomPlugin,
|
|
1274
|
+
HighlightRangePlugin,
|
|
928
1275
|
],
|
|
929
1276
|
toolbar: {
|
|
930
1277
|
items: [
|
|
@@ -959,7 +1306,18 @@ class SdDocumentBuilder {
|
|
|
959
1306
|
shouldNotGroupWhenFull: true,
|
|
960
1307
|
},
|
|
961
1308
|
image: {
|
|
962
|
-
|
|
1309
|
+
styles: {
|
|
1310
|
+
options: ['inline', 'alignLeft', 'alignRight', 'alignCenter'],
|
|
1311
|
+
},
|
|
1312
|
+
toolbar: [
|
|
1313
|
+
'imageStyle:inline',
|
|
1314
|
+
'imageStyle:alignCenter',
|
|
1315
|
+
{
|
|
1316
|
+
name: 'imageStyle:alignDropdown',
|
|
1317
|
+
items: ['imageStyle:alignLeft', 'imageStyle:alignRight'],
|
|
1318
|
+
defaultItem: 'imageStyle:alignLeft',
|
|
1319
|
+
},
|
|
1320
|
+
],
|
|
963
1321
|
},
|
|
964
1322
|
fontSize: {
|
|
965
1323
|
options: this.#fontSizeOptions,
|
|
@@ -985,13 +1343,29 @@ class SdDocumentBuilder {
|
|
|
985
1343
|
contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells', '|', 'tableProperties', 'tableCellProperties'],
|
|
986
1344
|
tableProperties: {
|
|
987
1345
|
borderColors: this.#sharedColors,
|
|
1346
|
+
backgroundColors: this.#sharedColors,
|
|
988
1347
|
colorPicker: this.#colorPickerConfig,
|
|
1348
|
+
defaultProperties: {
|
|
1349
|
+
borderStyle: 'solid',
|
|
1350
|
+
borderWidth: '1px',
|
|
1351
|
+
borderColor: '#ccc',
|
|
1352
|
+
},
|
|
989
1353
|
},
|
|
990
1354
|
tableCellProperties: {
|
|
991
1355
|
borderColors: this.#sharedColors,
|
|
1356
|
+
backgroundColors: this.#sharedColors,
|
|
992
1357
|
colorPicker: this.#colorPickerConfig,
|
|
1358
|
+
defaultProperties: {
|
|
1359
|
+
borderStyle: 'solid',
|
|
1360
|
+
borderWidth: '1px',
|
|
1361
|
+
borderColor: '#ccc',
|
|
1362
|
+
},
|
|
993
1363
|
},
|
|
994
1364
|
},
|
|
1365
|
+
indentBlock: {
|
|
1366
|
+
offset: 48, // Đơn vị px cho mỗi mức indent (tương đương 0.5 inch)
|
|
1367
|
+
unit: 'px',
|
|
1368
|
+
},
|
|
995
1369
|
// Quan trọng: Cho phép paste style từ Word nhưng bỏ qua margin/padding
|
|
996
1370
|
htmlSupport: {
|
|
997
1371
|
allow: [
|
|
@@ -1043,6 +1417,27 @@ class SdDocumentBuilder {
|
|
|
1043
1417
|
const content = editor.getData();
|
|
1044
1418
|
this.#contentChangeSubject.next(content);
|
|
1045
1419
|
});
|
|
1420
|
+
try {
|
|
1421
|
+
// Manual keybinding cho Tab nếu cần
|
|
1422
|
+
editor.keystrokes.set('Tab', (evt, cancel) => {
|
|
1423
|
+
const command = editor.commands.get('indentBlock');
|
|
1424
|
+
if (command && command.isEnabled) {
|
|
1425
|
+
editor.execute('indentBlock');
|
|
1426
|
+
cancel();
|
|
1427
|
+
}
|
|
1428
|
+
});
|
|
1429
|
+
// Manual keybinding cho Shift+Tab
|
|
1430
|
+
editor.keystrokes.set('Shift+Tab', (evt, cancel) => {
|
|
1431
|
+
const command = editor.commands.get('outdentBlock');
|
|
1432
|
+
if (command && command.isEnabled) {
|
|
1433
|
+
editor.execute('outdentBlock');
|
|
1434
|
+
cancel();
|
|
1435
|
+
}
|
|
1436
|
+
});
|
|
1437
|
+
}
|
|
1438
|
+
catch (error) {
|
|
1439
|
+
console.warn('Error setting up indent keybindings:', error);
|
|
1440
|
+
}
|
|
1046
1441
|
this.#updateState();
|
|
1047
1442
|
}
|
|
1048
1443
|
setContent = (html) => {
|
|
@@ -1257,21 +1652,28 @@ class SdDocumentBuilder {
|
|
|
1257
1652
|
all: () => {
|
|
1258
1653
|
if (!this.#editor)
|
|
1259
1654
|
return [];
|
|
1260
|
-
const
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1655
|
+
const editableElement = this.#editor.ui.view.editable.element;
|
|
1656
|
+
if (!editableElement)
|
|
1657
|
+
return [];
|
|
1658
|
+
const commentMarkers = editableElement.querySelectorAll('.ck-comment-marker[data-comment-id^="comment:"]') || [];
|
|
1659
|
+
const commentsMap = new Map();
|
|
1660
|
+
commentMarkers.forEach(el => {
|
|
1661
|
+
const markerId = el.getAttribute('data-comment-id');
|
|
1662
|
+
if (markerId) {
|
|
1663
|
+
const existing = commentsMap.get(markerId);
|
|
1664
|
+
const text = el.textContent || '';
|
|
1665
|
+
if (existing) {
|
|
1666
|
+
existing.selectedText += text;
|
|
1667
|
+
}
|
|
1668
|
+
else {
|
|
1669
|
+
commentsMap.set(markerId, {
|
|
1670
|
+
markerId,
|
|
1671
|
+
selectedText: text,
|
|
1672
|
+
});
|
|
1673
|
+
}
|
|
1272
1674
|
}
|
|
1273
|
-
}
|
|
1274
|
-
return
|
|
1675
|
+
});
|
|
1676
|
+
return Array.from(commentsMap.values());
|
|
1275
1677
|
},
|
|
1276
1678
|
/**
|
|
1277
1679
|
* Thêm comment vào vùng text đang được chọn
|
|
@@ -1279,7 +1681,11 @@ class SdDocumentBuilder {
|
|
|
1279
1681
|
* @param data - Dữ liệu extra data
|
|
1280
1682
|
* @returns SdDocumentBuilderComment hoặc null nếu không có text được chọn
|
|
1281
1683
|
*/
|
|
1282
|
-
add: (range, comment,
|
|
1684
|
+
add: (range, comment, args) => {
|
|
1685
|
+
// markerIdExternal khi truyền từ bên ngoài vào sẽ có thể là Date.now() hoặc uuidv4().
|
|
1686
|
+
// Miễn là đảm bảo markerIdExternal là unique.
|
|
1687
|
+
// Phục vụ cho case gọi API comment thành công thì mới sinh ra markerId.
|
|
1688
|
+
const { markerIdExternal, data } = args ?? {};
|
|
1283
1689
|
if (!this.#editor)
|
|
1284
1690
|
return null;
|
|
1285
1691
|
const model = this.#editor.model;
|
|
@@ -1292,7 +1698,7 @@ class SdDocumentBuilder {
|
|
|
1292
1698
|
return null;
|
|
1293
1699
|
}
|
|
1294
1700
|
// 4. Tạo ID unique cho marker
|
|
1295
|
-
const markerId = `comment:${Date.now()}`;
|
|
1701
|
+
const markerId = markerIdExternal ? `comment:${markerIdExternal}` : `comment:${Date.now()}`;
|
|
1296
1702
|
// 5. Tạo marker trong model
|
|
1297
1703
|
model.change(writer => {
|
|
1298
1704
|
writer.addMarker(markerId, {
|
|
@@ -1570,12 +1976,37 @@ class SdDocumentBuilder {
|
|
|
1570
1976
|
const blob = new Blob(['\ufeff', fullHtml], { type: 'application/msword' });
|
|
1571
1977
|
SdUtilities.downloadBlob(blob, fileName);
|
|
1572
1978
|
}
|
|
1979
|
+
hightSelectRange = (range) => {
|
|
1980
|
+
if (!range)
|
|
1981
|
+
return;
|
|
1982
|
+
const editor = this.#editor;
|
|
1983
|
+
editor.model.change(writer => {
|
|
1984
|
+
// Xóa marker cũ (nếu có)
|
|
1985
|
+
if (editor.model.markers.has('highlightRange')) {
|
|
1986
|
+
writer.removeMarker('highlightRange');
|
|
1987
|
+
}
|
|
1988
|
+
// Tạo marker mới
|
|
1989
|
+
writer.addMarker('highlightRange', {
|
|
1990
|
+
usingOperation: false, // Không lưu vào lịch sử Undo/Redo
|
|
1991
|
+
affectsData: false, // Không ảnh hưởng đến data lấy ra (getData)
|
|
1992
|
+
range: range,
|
|
1993
|
+
});
|
|
1994
|
+
});
|
|
1995
|
+
};
|
|
1996
|
+
removeHighlightSeclectRange = () => {
|
|
1997
|
+
const editor = this.#editor;
|
|
1998
|
+
editor.model.change(writer => {
|
|
1999
|
+
if (editor.model.markers.has('highlightRange')) {
|
|
2000
|
+
writer.removeMarker('highlightRange');
|
|
2001
|
+
}
|
|
2002
|
+
});
|
|
2003
|
+
};
|
|
1573
2004
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdDocumentBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1574
|
-
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: SdDocumentBuilder, isStandalone: true, selector: "sd-document-builder", inputs: { option: "option", _disabled: ["disabled", "_disabled"] }, outputs: { contentChange: "contentChange" }, ngImport: i0, template: "<div class=\"builder-container\">\n <ckeditor\n style=\"width: 100%\"\n [editor]=\"Editor\" \n [config]=\"config\" \n (ready)=\"onReady($event)\"\n [disabled]=\"disabled\">\n </ckeditor>\n</div>", styles: ["@charset \"UTF-8\"
|
|
2005
|
+
static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "19.2.17", type: SdDocumentBuilder, isStandalone: true, selector: "sd-document-builder", inputs: { option: "option", _disabled: ["disabled", "_disabled"] }, outputs: { contentChange: "contentChange" }, ngImport: i0, template: "<div class=\"builder-container\">\n <ckeditor\n style=\"width: 100%\"\n [editor]=\"Editor\" \n [config]=\"config\" \n (ready)=\"onReady($event)\"\n [disabled]=\"disabled\">\n </ckeditor>\n</div>", styles: ["@charset \"UTF-8\";.builder-container{background-color:#f3f4f6;height:100%;overflow-y:auto;width:100%;display:flex;flex-direction:column;align-items:center}:host{display:inline-block}:host ::ng-deep .ck-editor{display:flex;flex-direction:column;align-items:center;width:100%;--ck-content-font-family: \"Times New Roman\", serif !important;--ck-content-font-size: 13pt;--ck-content-line-height: 1.5}:host ::ng-deep .ck-editor__top,:host ::ng-deep .ck-editor__main{border:none!important;box-shadow:none!important}:host ::ng-deep .ck-editor__top{position:sticky;top:0;z-index:100;width:100%;min-width:600px;margin-bottom:10px}:host ::ng-deep .ck-editor__top .ck-sticky-panel__content{border:none!important}:host ::ng-deep .ck-editor__top .ck-toolbar{background:#fff!important;box-shadow:0 4px 6px -1px #0000001a!important;padding:8px!important}:host ::ng-deep .ck-editor__top .ck-toolbar .ck-toolbar__items{display:flex;justify-content:center;flex-wrap:wrap;align-items:center}:host ::ng-deep .ck-content{background-color:#fff;width:210mm;min-height:1123px;padding:20mm!important;box-sizing:border-box!important;box-shadow:0 10px 15px -3px #0000001a}:host ::ng-deep .ck-content h1,:host ::ng-deep .ck-content h2,:host ::ng-deep .ck-content h3,:host ::ng-deep .ck-content h4,:host ::ng-deep .ck-content h5,:host ::ng-deep .ck-content h6{font-weight:400}:host ::ng-deep .ck-content.landscape{width:297mm}:host ::ng-deep .ck-content>*{max-width:100%!important;box-sizing:border-box!important}:host ::ng-deep .ck-content p{margin-bottom:var(--ck-spacing-large);text-indent:0}:host ::ng-deep .ck-content ul,:host ::ng-deep .ck-content ol{padding-left:20px!important;margin-left:0!important}\n", ":host ::ng-deep .ck-heading-highlight{background-color:#fef08a}\n", ":host ::ng-deep .ck-comment-marker{background-color:#ffeb3b80;border-bottom:2px solid #fbc02d;transition:background-color .2s;cursor:pointer}:host ::ng-deep .ck-comment-marker:hover{background-color:#ffeb3bcc}:host ::ng-deep .ck-comment-marker.active-highlight{background-color:#ffeb3b;outline:2px dashed #f57f17}\n", "@charset \"UTF-8\";::ng-deep .ck-clipboard-drop-target-line{display:none!important}:host ::ng-deep .variable-widget{background-color:#e3f2fd;color:#1976d2;border:1px solid #90caf9!important;border-radius:4px;padding:2px 6px;font-weight:600;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;font-size:10px;-webkit-user-select:none;user-select:none;display:inline-block;margin:0 4px;vertical-align:middle;font-size:0;cursor:default}:host ::ng-deep .variable-widget:before{content:attr(data-display);font-size:10px}:host ::ng-deep .variable-widget:hover{background-color:#bbdefb;box-shadow:0 1px 2px #0000001a}:host ::ng-deep .variable-widget.ck-widget_selected{outline:2px solid #2196f3;background-color:#bbdefb}:host ::ng-deep .ck.ck-content .ck-widget,:host ::ng-deep .ck.ck-content .ck-widget:hover,:host ::ng-deep .ck.ck-content .ck-widget:focus,:host ::ng-deep .ck.ck-content .ck-widget.ck-widget_selected,:host ::ng-deep .ck.ck-content .ck-widget.ck-widget_selected:hover{outline:none!important;box-shadow:none!important}\n", "", ":host ::ng-deep .highlight-range{background-color:#ffeb3b80;border-bottom:2px solid #fbc02d;transition:background-color .2s;cursor:pointer}\n"], dependencies: [{ kind: "ngmodule", type: CommonModule }, { kind: "ngmodule", type: CKEditorModule }, { kind: "component", type: i1.CKEditorComponent, selector: "ckeditor", inputs: ["editor", "config", "data", "tagName", "watchdog", "editorWatchdogConfig", "disableWatchdog", "disableTwoWayDataBinding", "disabled"], outputs: ["ready", "change", "blur", "focus", "error"] }] });
|
|
1575
2006
|
}
|
|
1576
2007
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdDocumentBuilder, decorators: [{
|
|
1577
2008
|
type: Component,
|
|
1578
|
-
args: [{ selector: 'sd-document-builder', standalone: true, imports: [CommonModule, CKEditorModule], template: "<div class=\"builder-container\">\n <ckeditor\n style=\"width: 100%\"\n [editor]=\"Editor\" \n [config]=\"config\" \n (ready)=\"onReady($event)\"\n [disabled]=\"disabled\">\n </ckeditor>\n</div>", styles: ["@charset \"UTF-8\"
|
|
2009
|
+
args: [{ selector: 'sd-document-builder', standalone: true, imports: [CommonModule, CKEditorModule], template: "<div class=\"builder-container\">\n <ckeditor\n style=\"width: 100%\"\n [editor]=\"Editor\" \n [config]=\"config\" \n (ready)=\"onReady($event)\"\n [disabled]=\"disabled\">\n </ckeditor>\n</div>", styles: ["@charset \"UTF-8\";.builder-container{background-color:#f3f4f6;height:100%;overflow-y:auto;width:100%;display:flex;flex-direction:column;align-items:center}:host{display:inline-block}:host ::ng-deep .ck-editor{display:flex;flex-direction:column;align-items:center;width:100%;--ck-content-font-family: \"Times New Roman\", serif !important;--ck-content-font-size: 13pt;--ck-content-line-height: 1.5}:host ::ng-deep .ck-editor__top,:host ::ng-deep .ck-editor__main{border:none!important;box-shadow:none!important}:host ::ng-deep .ck-editor__top{position:sticky;top:0;z-index:100;width:100%;min-width:600px;margin-bottom:10px}:host ::ng-deep .ck-editor__top .ck-sticky-panel__content{border:none!important}:host ::ng-deep .ck-editor__top .ck-toolbar{background:#fff!important;box-shadow:0 4px 6px -1px #0000001a!important;padding:8px!important}:host ::ng-deep .ck-editor__top .ck-toolbar .ck-toolbar__items{display:flex;justify-content:center;flex-wrap:wrap;align-items:center}:host ::ng-deep .ck-content{background-color:#fff;width:210mm;min-height:1123px;padding:20mm!important;box-sizing:border-box!important;box-shadow:0 10px 15px -3px #0000001a}:host ::ng-deep .ck-content h1,:host ::ng-deep .ck-content h2,:host ::ng-deep .ck-content h3,:host ::ng-deep .ck-content h4,:host ::ng-deep .ck-content h5,:host ::ng-deep .ck-content h6{font-weight:400}:host ::ng-deep .ck-content.landscape{width:297mm}:host ::ng-deep .ck-content>*{max-width:100%!important;box-sizing:border-box!important}:host ::ng-deep .ck-content p{margin-bottom:var(--ck-spacing-large);text-indent:0}:host ::ng-deep .ck-content ul,:host ::ng-deep .ck-content ol{padding-left:20px!important;margin-left:0!important}\n", ":host ::ng-deep .ck-heading-highlight{background-color:#fef08a}\n", ":host ::ng-deep .ck-comment-marker{background-color:#ffeb3b80;border-bottom:2px solid #fbc02d;transition:background-color .2s;cursor:pointer}:host ::ng-deep .ck-comment-marker:hover{background-color:#ffeb3bcc}:host ::ng-deep .ck-comment-marker.active-highlight{background-color:#ffeb3b;outline:2px dashed #f57f17}\n", "@charset \"UTF-8\";::ng-deep .ck-clipboard-drop-target-line{display:none!important}:host ::ng-deep .variable-widget{background-color:#e3f2fd;color:#1976d2;border:1px solid #90caf9!important;border-radius:4px;padding:2px 6px;font-weight:600;font-family:Segoe UI,Tahoma,Geneva,Verdana,sans-serif;font-size:10px;-webkit-user-select:none;user-select:none;display:inline-block;margin:0 4px;vertical-align:middle;font-size:0;cursor:default}:host ::ng-deep .variable-widget:before{content:attr(data-display);font-size:10px}:host ::ng-deep .variable-widget:hover{background-color:#bbdefb;box-shadow:0 1px 2px #0000001a}:host ::ng-deep .variable-widget.ck-widget_selected{outline:2px solid #2196f3;background-color:#bbdefb}:host ::ng-deep .ck.ck-content .ck-widget,:host ::ng-deep .ck.ck-content .ck-widget:hover,:host ::ng-deep .ck.ck-content .ck-widget:focus,:host ::ng-deep .ck.ck-content .ck-widget.ck-widget_selected,:host ::ng-deep .ck.ck-content .ck-widget.ck-widget_selected:hover{outline:none!important;box-shadow:none!important}\n", ":host ::ng-deep .highlight-range{background-color:#ffeb3b80;border-bottom:2px solid #fbc02d;transition:background-color .2s;cursor:pointer}\n"] }]
|
|
1579
2010
|
}], propDecorators: { option: [{
|
|
1580
2011
|
type: Input,
|
|
1581
2012
|
args: [{ required: true }]
|