Skip to content
This repository was archived by the owner on Jun 26, 2020. It is now read-only.

Commit dca0fe4

Browse files
authored
Merge pull request #9 from ckeditor/i/5924
Fix: It should be possible to use multiple classes in the language configuration. Closes ckeditor/ckeditor5#5924.
2 parents c9e5c2c + 8a5d211 commit dca0fe4

File tree

4 files changed

+95
-7
lines changed

4 files changed

+95
-7
lines changed

docs/features/code-blocks.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ ClassicEditor
4242

4343
{@snippet features/code-block-custom-languages}
4444

45-
By default, the CSS class of the `<code>` element in the data and editing is generated using the `language` property (prefixed with "language-"). You can customize it by specifying an optional `class` property:
45+
By default, the CSS class of the `<code>` element in the data and editing is generated using the `language` property (prefixed with "language-"). You can customize it by specifying an optional `class` property. You can set **multiple classes** but **only the first one** will be used as defining language class:
4646

4747
```js
4848
ClassicEditor
@@ -56,7 +56,8 @@ ClassicEditor
5656
{ language: 'php', label: 'PHP', class: 'php-code' },
5757

5858
// Use the "js" class for JavaScript code blocks.
59-
{ language: 'javascript', label: 'JavaScript', class: 'js' },
59+
// Note that only the first ("js") class will determine the language of the block when loading data.
60+
{ language: 'javascript', label: 'JavaScript', class: 'js javascript js-code' },
6061

6162
// Python code blocks will have the default "language-python" CSS class.
6263
{ language: 'python', label: 'Python' }

src/codeblock.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ export default class CodeBlock extends Plugin {
5151
*
5252
* ClassicEditor
5353
* .create( editorElement, {
54-
* codeBlock: ... // The code block feature configuration.
54+
* codeBlock: ... // The code block feature configuration.
5555
* } )
5656
* .then( ... )
5757
* .catch( ... );
@@ -103,20 +103,22 @@ export default class CodeBlock extends Plugin {
103103
*
104104
* <pre><code class="language-javascript">window.alert( 'Hello world!' )</code></pre>
105105
*
106-
* You can customize the CSS class by specifying an optional `class` property in the language definition:
106+
* You can customize the CSS class by specifying an optional `class` property in the language definition.
107+
* You can set **multiple classes** but **only the first one** will be used as defining language class:
107108
*
108109
* ClassicEditor
109110
* .create( document.querySelector( '#editor' ), {
110111
* codeBlock: {
111112
* languages: [
112113
* // Do not render the CSS class for the plain text code blocks.
113-
* { language: 'plaintext', label: 'Plain text', class: '' },
114+
* { language: 'plaintext', label: 'Plain text', class: '' },
114115
*
115116
* // Use the "php-code" class for PHP code blocks.
116117
* { language: 'php', label: 'PHP', class: 'php-code' },
117118
*
118119
* // Use the "js" class for JavaScript code blocks.
119-
* { language: 'javascript', label: 'JavaScript', class: 'js' },
120+
* // Note that only the first ("js") class will determine the language of the block when loading data.
121+
* { language: 'javascript', label: 'JavaScript', class: 'js javascript js-code' },
120122
*
121123
* // Python code blocks will have the default "language-python" CSS class.
122124
* { language: 'python', label: 'Python' }

src/utils.js

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,18 @@ export function getNormalizedAndLocalizedLanguageDefinitions( editor ) {
7474
* @param {Object.<String,String>}
7575
*/
7676
export function getPropertyAssociation( languageDefs, key, value ) {
77-
return Object.assign( {}, ...languageDefs.map( def => ( { [ def[ key ] ]: def[ value ] } ) ) );
77+
const association = {};
78+
79+
for ( const def of languageDefs ) {
80+
if ( key === 'class' ) {
81+
// Only the first class is considered.
82+
association[ def[ key ].split( ' ' ).shift() ] = def[ value ];
83+
} else {
84+
association[ def[ key ] ] = def[ value ];
85+
}
86+
}
87+
88+
return association;
7889
}
7990

8091
/**

tests/codeblockediting.js

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -781,6 +781,38 @@ describe( 'CodeBlockEditing', () => {
781781
return editor.destroy();
782782
} );
783783
} );
784+
785+
it( 'should set multiple classes on the <code> if it was configured so', () => {
786+
const element = document.createElement( 'div' );
787+
document.body.appendChild( element );
788+
789+
return ClassicTestEditor
790+
.create( element, {
791+
plugins: [ CodeBlockEditing, AlignmentEditing, BoldEditing, Enter, Paragraph ],
792+
codeBlock: {
793+
languages: [
794+
{ language: 'javascript', label: 'JavaScript', class: 'language-js' },
795+
{ language: 'swift', label: 'Swift', class: 'swift ios-code' },
796+
]
797+
}
798+
} )
799+
.then( editor => {
800+
const model = editor.model;
801+
802+
setModelData( model,
803+
'<codeBlock language="swift">foo</codeBlock>' +
804+
'<codeBlock language="javascript">foo</codeBlock>'
805+
);
806+
expect( editor.getData() ).to.equal(
807+
'<pre><code class="swift ios-code">foo</code></pre>' +
808+
'<pre><code class="language-js">foo</code></pre>'
809+
);
810+
811+
element.remove();
812+
813+
return editor.destroy();
814+
} );
815+
} );
784816
} );
785817

786818
describe( 'data pipeline v -> m conversion ', () => {
@@ -1008,6 +1040,48 @@ describe( 'CodeBlockEditing', () => {
10081040
return editor.destroy();
10091041
} );
10101042
} );
1043+
1044+
// https://github.com/ckeditor/ckeditor5/issues/5924
1045+
it( 'should upcast using only the first class from config as a defining language class', () => {
1046+
// "baz" is the first class configured for the "baz" language.
1047+
return ClassicTestEditor.create( '<pre><code class="baz">foo</code></pre>', {
1048+
plugins: [ CodeBlockEditing ],
1049+
codeBlock: {
1050+
languages: [
1051+
{ language: 'foo', label: 'Foo', class: 'foo' },
1052+
{ language: 'baz', label: 'Baz', class: 'baz bar' },
1053+
{ language: 'qux', label: 'Qux', class: 'qux' },
1054+
]
1055+
}
1056+
} ).then( editor => {
1057+
model = editor.model;
1058+
1059+
expect( getModelData( model ) ).to.equal( '<codeBlock language="baz">[]foo</codeBlock>' );
1060+
1061+
return editor.destroy();
1062+
} );
1063+
} );
1064+
1065+
// https://github.com/ckeditor/ckeditor5/issues/5924
1066+
it( 'should not upcast if the class is not the first (defining) language class', () => {
1067+
// "bar" is the second class configured for the "baz" language.
1068+
return ClassicTestEditor.create( '<pre><code class="bar">foo</code></pre>', {
1069+
plugins: [ CodeBlockEditing ],
1070+
codeBlock: {
1071+
languages: [
1072+
{ language: 'foo', label: 'Foo', class: 'foo' },
1073+
{ language: 'baz', label: 'Baz', class: 'baz bar' },
1074+
{ language: 'qux', label: 'Qux', class: 'qux' },
1075+
]
1076+
}
1077+
} ).then( editor => {
1078+
model = editor.model;
1079+
1080+
expect( getModelData( model ) ).to.equal( '<codeBlock language="foo">[]foo</codeBlock>' );
1081+
1082+
return editor.destroy();
1083+
} );
1084+
} );
10111085
} );
10121086
} );
10131087

0 commit comments

Comments
 (0)