@sd-angular/core 19.0.0-beta.13 → 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 +464 -24
- 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 +57 -49
- package/sd-angular-core-19.0.0-beta.14.tgz +0 -0
- package/sd-angular-core-19.0.0-beta.13.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
|
});
|
|
@@ -501,6 +501,52 @@ class VariablePlugin extends Plugin {
|
|
|
501
501
|
class TableFitPlugin extends Plugin {
|
|
502
502
|
init() {
|
|
503
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
|
+
};
|
|
504
550
|
// Can thiệp vào quá trình convert từ View (HTML Paste) sang Model
|
|
505
551
|
editor.conversion.for('upcast').add(dispatcher => {
|
|
506
552
|
dispatcher.on('element:table', (evt, data, conversionApi) => {
|
|
@@ -514,7 +560,8 @@ class TableFitPlugin extends Plugin {
|
|
|
514
560
|
for (const item of modelRange.getItems()) {
|
|
515
561
|
if (item.is('element', 'table')) {
|
|
516
562
|
editor.model.change(writer => {
|
|
517
|
-
writer
|
|
563
|
+
applyTableDefaults(writer, item);
|
|
564
|
+
applyCellBorders(writer, item);
|
|
518
565
|
});
|
|
519
566
|
}
|
|
520
567
|
}
|
|
@@ -524,6 +571,52 @@ class TableFitPlugin extends Plugin {
|
|
|
524
571
|
}, { priority: 'low' });
|
|
525
572
|
// Chạy sau cùng để ghi đè các logic mặc định
|
|
526
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
|
+
});
|
|
527
620
|
// Lắng nghe lệnh insertTable để can thiệp ngay sau khi bảng được tạo
|
|
528
621
|
const insertTableCommand = editor.commands.get('insertTable');
|
|
529
622
|
if (insertTableCommand) {
|
|
@@ -540,11 +633,20 @@ class TableFitPlugin extends Plugin {
|
|
|
540
633
|
const tableElement = position.findAncestor('table');
|
|
541
634
|
if (tableElement) {
|
|
542
635
|
// Ép width 100% cho bảng mới vẽ
|
|
543
|
-
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);
|
|
544
642
|
}
|
|
545
643
|
});
|
|
546
644
|
});
|
|
547
645
|
}
|
|
646
|
+
listenAndApplyOnExecute('insertTableRowAbove');
|
|
647
|
+
listenAndApplyOnExecute('insertTableRowBelow');
|
|
648
|
+
listenAndApplyOnExecute('insertTableColumnLeft');
|
|
649
|
+
listenAndApplyOnExecute('insertTableColumnRight');
|
|
548
650
|
}
|
|
549
651
|
}
|
|
550
652
|
|
|
@@ -592,6 +694,243 @@ class Base64UploadAdapter {
|
|
|
592
694
|
}
|
|
593
695
|
}
|
|
594
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
|
+
|
|
595
934
|
// Icon khổ dọc (Mặc định cũ)
|
|
596
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>';
|
|
597
936
|
// Icon khổ ngang (Mới)
|
|
@@ -855,6 +1194,18 @@ function normalize(content) {
|
|
|
855
1194
|
return normalized;
|
|
856
1195
|
}
|
|
857
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
|
+
|
|
858
1209
|
class SdDocumentBuilder {
|
|
859
1210
|
option;
|
|
860
1211
|
disabled = false;
|
|
@@ -909,13 +1260,18 @@ class SdDocumentBuilder {
|
|
|
909
1260
|
ImageCaption,
|
|
910
1261
|
ImageResize,
|
|
911
1262
|
ImageStyle,
|
|
1263
|
+
ImageBlock,
|
|
912
1264
|
// Custom Plugin
|
|
913
1265
|
HeadingPlugin,
|
|
914
1266
|
CommentPlugin,
|
|
915
1267
|
VariablePlugin,
|
|
916
1268
|
TableFitPlugin,
|
|
917
|
-
|
|
1269
|
+
Indent,
|
|
1270
|
+
IndentBlock,
|
|
918
1271
|
PageOrientationPlugin,
|
|
1272
|
+
ImageUploadPlugin,
|
|
1273
|
+
ImageCustomPlugin,
|
|
1274
|
+
HighlightRangePlugin,
|
|
919
1275
|
],
|
|
920
1276
|
toolbar: {
|
|
921
1277
|
items: [
|
|
@@ -950,7 +1306,18 @@ class SdDocumentBuilder {
|
|
|
950
1306
|
shouldNotGroupWhenFull: true,
|
|
951
1307
|
},
|
|
952
1308
|
image: {
|
|
953
|
-
|
|
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
|
+
],
|
|
954
1321
|
},
|
|
955
1322
|
fontSize: {
|
|
956
1323
|
options: this.#fontSizeOptions,
|
|
@@ -976,13 +1343,29 @@ class SdDocumentBuilder {
|
|
|
976
1343
|
contentToolbar: ['tableColumn', 'tableRow', 'mergeTableCells', '|', 'tableProperties', 'tableCellProperties'],
|
|
977
1344
|
tableProperties: {
|
|
978
1345
|
borderColors: this.#sharedColors,
|
|
1346
|
+
backgroundColors: this.#sharedColors,
|
|
979
1347
|
colorPicker: this.#colorPickerConfig,
|
|
1348
|
+
defaultProperties: {
|
|
1349
|
+
borderStyle: 'solid',
|
|
1350
|
+
borderWidth: '1px',
|
|
1351
|
+
borderColor: '#ccc',
|
|
1352
|
+
},
|
|
980
1353
|
},
|
|
981
1354
|
tableCellProperties: {
|
|
982
1355
|
borderColors: this.#sharedColors,
|
|
1356
|
+
backgroundColors: this.#sharedColors,
|
|
983
1357
|
colorPicker: this.#colorPickerConfig,
|
|
1358
|
+
defaultProperties: {
|
|
1359
|
+
borderStyle: 'solid',
|
|
1360
|
+
borderWidth: '1px',
|
|
1361
|
+
borderColor: '#ccc',
|
|
1362
|
+
},
|
|
984
1363
|
},
|
|
985
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
|
+
},
|
|
986
1369
|
// Quan trọng: Cho phép paste style từ Word nhưng bỏ qua margin/padding
|
|
987
1370
|
htmlSupport: {
|
|
988
1371
|
allow: [
|
|
@@ -1034,6 +1417,27 @@ class SdDocumentBuilder {
|
|
|
1034
1417
|
const content = editor.getData();
|
|
1035
1418
|
this.#contentChangeSubject.next(content);
|
|
1036
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
|
+
}
|
|
1037
1441
|
this.#updateState();
|
|
1038
1442
|
}
|
|
1039
1443
|
setContent = (html) => {
|
|
@@ -1248,21 +1652,28 @@ class SdDocumentBuilder {
|
|
|
1248
1652
|
all: () => {
|
|
1249
1653
|
if (!this.#editor)
|
|
1250
1654
|
return [];
|
|
1251
|
-
const
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
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
|
+
}
|
|
1263
1674
|
}
|
|
1264
|
-
}
|
|
1265
|
-
return
|
|
1675
|
+
});
|
|
1676
|
+
return Array.from(commentsMap.values());
|
|
1266
1677
|
},
|
|
1267
1678
|
/**
|
|
1268
1679
|
* Thêm comment vào vùng text đang được chọn
|
|
@@ -1270,7 +1681,11 @@ class SdDocumentBuilder {
|
|
|
1270
1681
|
* @param data - Dữ liệu extra data
|
|
1271
1682
|
* @returns SdDocumentBuilderComment hoặc null nếu không có text được chọn
|
|
1272
1683
|
*/
|
|
1273
|
-
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 ?? {};
|
|
1274
1689
|
if (!this.#editor)
|
|
1275
1690
|
return null;
|
|
1276
1691
|
const model = this.#editor.model;
|
|
@@ -1283,7 +1698,7 @@ class SdDocumentBuilder {
|
|
|
1283
1698
|
return null;
|
|
1284
1699
|
}
|
|
1285
1700
|
// 4. Tạo ID unique cho marker
|
|
1286
|
-
const markerId = `comment:${Date.now()}`;
|
|
1701
|
+
const markerId = markerIdExternal ? `comment:${markerIdExternal}` : `comment:${Date.now()}`;
|
|
1287
1702
|
// 5. Tạo marker trong model
|
|
1288
1703
|
model.change(writer => {
|
|
1289
1704
|
writer.addMarker(markerId, {
|
|
@@ -1561,12 +1976,37 @@ class SdDocumentBuilder {
|
|
|
1561
1976
|
const blob = new Blob(['\ufeff', fullHtml], { type: 'application/msword' });
|
|
1562
1977
|
SdUtilities.downloadBlob(blob, fileName);
|
|
1563
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
|
+
};
|
|
1564
2004
|
static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdDocumentBuilder, deps: [], target: i0.ɵɵFactoryTarget.Component });
|
|
1565
|
-
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"] }] });
|
|
1566
2006
|
}
|
|
1567
2007
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.2.17", ngImport: i0, type: SdDocumentBuilder, decorators: [{
|
|
1568
2008
|
type: Component,
|
|
1569
|
-
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"] }]
|
|
1570
2010
|
}], propDecorators: { option: [{
|
|
1571
2011
|
type: Input,
|
|
1572
2012
|
args: [{ required: true }]
|