-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
/
table.ts
155 lines (129 loc) · 4.61 KB
/
table.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/**
* @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @module style/integrations/table
*/
import { Plugin } from 'ckeditor5/src/core';
import type { Element } from 'ckeditor5/src/engine';
import type { TableUtils } from '@ckeditor/ckeditor5-table';
import type { DataFilter } from '@ckeditor/ckeditor5-html-support';
import StyleUtils, {
type BlockStyleDefinition,
type StyleUtilsGetAffectedBlocksEvent,
type StyleUtilsIsEnabledForBlockEvent,
type StyleUtilsConfigureGHSDataFilterEvent
} from '../styleutils';
export default class TableStyleSupport extends Plugin {
private _tableUtils!: TableUtils;
private _styleUtils!: StyleUtils;
/**
* @inheritDoc
*/
public static get pluginName(): 'TableStyleSupport' {
return 'TableStyleSupport';
}
/**
* @inheritDoc
*/
public static get requires() {
return [ StyleUtils ] as const;
}
/**
* @inheritDoc
*/
public init(): void {
const editor = this.editor;
if ( !editor.plugins.has( 'TableEditing' ) ) {
return;
}
this._styleUtils = editor.plugins.get( StyleUtils );
this._tableUtils = this.editor.plugins.get( 'TableUtils' );
this.listenTo<StyleUtilsIsEnabledForBlockEvent>( this._styleUtils, 'isStyleEnabledForBlock', ( evt, [ definition, block ] ) => {
if ( this._isApplicable( definition, block ) ) {
evt.return = this._isStyleEnabledForBlock( definition, block );
evt.stop();
}
}, { priority: 'high' } );
this.listenTo<StyleUtilsGetAffectedBlocksEvent>( this._styleUtils, 'getAffectedBlocks', ( evt, [ definition, block ] ) => {
if ( this._isApplicable( definition, block ) ) {
evt.return = this._getAffectedBlocks( definition, block );
evt.stop();
}
}, { priority: 'high' } );
this.listenTo<StyleUtilsConfigureGHSDataFilterEvent>(
this._styleUtils,
'configureGHSDataFilter',
( evt, [ { block } ] ) => {
const ghsDataFilter: DataFilter = this.editor.plugins.get( 'DataFilter' );
ghsDataFilter.loadAllowedConfig(
block
.filter( definition => definition.element == 'figcaption' )
.map( definition => ( { name: 'caption', classes: definition.classes } ) )
);
}
);
}
/**
* Checks if this plugin's custom logic should be applied for defintion-block pair.
*
* @param definition Style definition that is being considered.
* @param block Block element to check if should be styled.
* @returns True if the defintion-block pair meet the plugin criteria, false otherwise.
*/
private _isApplicable( definition: BlockStyleDefinition, block: Element ): boolean {
if ( [ 'td', 'th' ].includes( definition.element ) ) {
return block.name == 'tableCell';
}
if ( [ 'thead', 'tbody' ].includes( definition.element ) ) {
return block.name == 'table';
}
return false;
}
/**
* Checks if the style definition should be applied to selected block.
*
* @param definition Style definition that is being considered.
* @param block Block element to check if should be styled.
* @returns True if the block should be style with the style description, false otherwise.
*/
private _isStyleEnabledForBlock( definition: BlockStyleDefinition, block: Element ): boolean {
if ( [ 'td', 'th' ].includes( definition.element ) ) {
const location = this._tableUtils.getCellLocation( block )!;
const tableRow = block.parent!;
const table = tableRow.parent as Element;
const headingRows = table.getAttribute( 'headingRows' ) as number || 0;
const headingColumns = table.getAttribute( 'headingColumns' ) as number || 0;
const isHeadingCell = location.row < headingRows || location.column < headingColumns;
if ( definition.element == 'th' ) {
return isHeadingCell;
} else {
return !isHeadingCell;
}
}
if ( [ 'thead', 'tbody' ].includes( definition.element ) ) {
const headingRows = block.getAttribute( 'headingRows' ) as number || 0;
if ( definition.element == 'thead' ) {
return headingRows > 0;
} else {
return headingRows < this._tableUtils.getRows( block );
}
}
/* istanbul ignore next -- @preserve */
return false;
}
/**
* Gets all blocks that the style should be applied to.
*
* @param definition Style definition that is being considered.
* @param block A block element from selection.
* @returns An array with the block that was passed as an argument if meets the criteria, null otherwise.
*/
private _getAffectedBlocks( definition: BlockStyleDefinition, block: Element ): Array<Element> | null {
if ( !this._isStyleEnabledForBlock( definition, block ) ) {
return null;
}
return [ block ];
}
}