• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

ckeditor / ckeditor5 / 6f7c4ea6-49ab-4ae8-85cc-c93a702378a1

09 Jul 2024 09:52AM UTC coverage: 100.0%. Remained the same
6f7c4ea6-49ab-4ae8-85cc-c93a702378a1

push

circleci

web-flow
Merge stable into master

13840 of 13840 branches covered (100.0%)

Branch coverage included in aggregate %.

36579 of 36579 relevant lines covered (100.0%)

11225.02 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

100.0
/packages/ckeditor5-alignment/src/alignmentediting.ts
1
/**
2
 * @license Copyright (c) 2003-2024, CKSource Holding sp. z o.o. All rights reserved.
3
 * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
4
 */
5

6
/**
7
 * @module alignment/alignmentediting
8
 */
9

10
import { Plugin, type Editor } from 'ckeditor5/src/core.js';
11
import type { AttributeDescriptor } from 'ckeditor5/src/engine.js';
12

13
import AlignmentCommand from './alignmentcommand.js';
14
import { isDefault, isSupported, normalizeAlignmentOptions, supportedOptions } from './utils.js';
15
import type { AlignmentFormat, SupportedOption } from './alignmentconfig.js';
16

17
/**
18
 * The alignment editing feature. It introduces the {@link module:alignment/alignmentcommand~AlignmentCommand command} and adds
19
 * the `alignment` attribute for block elements in the {@link module:engine/model/model~Model model}.
20
 */
21
export default class AlignmentEditing extends Plugin {
22
        /**
23
         * @inheritDoc
24
         */
25
        public static get pluginName() {
26
                return 'AlignmentEditing' as const;
513✔
27
        }
28

29
        /**
30
         * @inheritDoc
31
         */
32
        constructor( editor: Editor ) {
33
                super( editor );
128✔
34

35
                editor.config.define( 'alignment', {
128✔
36
                        options: supportedOptions.map( option => ( { name: option } ) )
512✔
37
                } );
38
        }
39

40
        /**
41
         * @inheritDoc
42
         */
43
        public init(): void {
44
                const editor = this.editor;
128✔
45
                const locale = editor.locale;
128✔
46
                const schema = editor.model.schema;
128✔
47

48
                const options: Array<AlignmentFormat> = normalizeAlignmentOptions( editor.config.get( 'alignment.options' )! );
128✔
49

50
                // Filter out unsupported options and those that are redundant, e.g. `left` in LTR / `right` in RTL mode.
51
                const optionsToConvert = options.filter(
128✔
52
                        option => isSupported( option.name ) && !isDefault( option.name, locale )
502✔
53
                );
54

55
                // Once there is at least one `className` defined, we switch to alignment with classes.
56
                const shouldUseClasses = optionsToConvert.some( option => !!option.className );
355✔
57

58
                // Allow alignment attribute on all blocks.
59
                schema.extend( '$block', { allowAttributes: 'alignment' } );
128✔
60
                editor.model.schema.setAttributeProperties( 'alignment', { isFormatting: true } );
128✔
61

62
                if ( shouldUseClasses ) {
128✔
63
                        editor.conversion.attributeToAttribute( buildClassDefinition( optionsToConvert ) );
12✔
64
                } else {
65
                        // Downcast inline styles.
66
                        editor.conversion.for( 'downcast' ).attributeToAttribute( buildDowncastInlineDefinition( optionsToConvert ) );
116✔
67
                }
68

69
                const upcastInlineDefinitions = buildUpcastInlineDefinitions( optionsToConvert );
128✔
70

71
                // Always upcast from inline styles.
72
                for ( const definition of upcastInlineDefinitions ) {
128✔
73
                        editor.conversion.for( 'upcast' ).attributeToAttribute( definition );
379✔
74
                }
75

76
                const upcastCompatibilityDefinitions = buildUpcastCompatibilityDefinitions( optionsToConvert );
128✔
77

78
                // Always upcast from deprecated `align` attribute.
79
                for ( const definition of upcastCompatibilityDefinitions ) {
128✔
80
                        editor.conversion.for( 'upcast' ).attributeToAttribute( definition );
379✔
81
                }
82

83
                editor.commands.add( 'alignment', new AlignmentCommand( editor ) );
128✔
84
        }
85
}
86

87
/**
88
 * Prepare downcast conversion definition for inline alignment styling.
89
 */
90
function buildDowncastInlineDefinition( options: Array<AlignmentFormat> ) {
91
        const view: Record<string, { key: 'style'; value: { 'text-align': SupportedOption } }> = {};
116✔
92

93
        for ( const { name } of options ) {
116✔
94
                view[ name ] = {
343✔
95
                        key: 'style',
96
                        value: {
97
                                'text-align': name
98
                        }
99
                };
100
        }
101

102
        const definition = {
116✔
103
                model: {
104
                        key: 'alignment',
105
                        values: options.map( option => option.name )
343✔
106
                },
107
                view
108
        };
109

110
        return definition;
116✔
111
}
112

113
/**
114
 * Prepare upcast definitions for inline alignment styles.
115
 */
116
function buildUpcastInlineDefinitions( options: Array<AlignmentFormat> ) {
117
        const definitions = [];
128✔
118

119
        for ( const { name } of options ) {
128✔
120
                definitions.push( {
379✔
121
                        view: {
122
                                key: 'style',
123
                                value: {
124
                                        'text-align': name
125
                                }
126
                        },
127
                        model: {
128
                                key: 'alignment',
129
                                value: name
130
                        }
131
                } );
132
        }
133

134
        return definitions;
128✔
135
}
136

137
/**
138
 * Prepare upcast definitions for deprecated `align` attribute.
139
 */
140
function buildUpcastCompatibilityDefinitions( options: Array<AlignmentFormat> ) {
141
        const definitions = [];
128✔
142

143
        for ( const { name } of options ) {
128✔
144
                definitions.push( {
379✔
145
                        view: {
146
                                key: 'align',
147
                                value: name
148
                        },
149
                        model: {
150
                                key: 'alignment',
151
                                value: name
152
                        }
153
                } );
154
        }
155

156
        return definitions;
128✔
157
}
158

159
/**
160
 * Prepare conversion definitions for upcast and downcast alignment with classes.
161
 */
162
function buildClassDefinition( options: Array<AlignmentFormat> ) {
163
        const view: Record<string, AttributeDescriptor> = {};
12✔
164

165
        for ( const option of options ) {
12✔
166
                view[ option.name ] = {
36✔
167
                        key: 'class',
168
                        value: option.className!
169
                };
170
        }
171

172
        const definition = {
12✔
173
                model: {
174
                        key: 'alignment',
175
                        values: options.map( option => option.name )
36✔
176
                },
177
                view
178
        };
179

180
        return definition;
12✔
181
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc