From 5909224f042661c28a1cfd01beaa2209f6401dbf Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Thu, 18 Feb 2021 09:24:59 +0100 Subject: [PATCH 01/36] Initial language plugin implementation. --- packages/ckeditor5-language/CHANGELOG.md | 6 + packages/ckeditor5-language/CONTRIBUTING.md | 4 + packages/ckeditor5-language/LICENSE.md | 17 +++ packages/ckeditor5-language/README.md | 16 +++ .../ckeditor5-language/lang/contexts.json | 3 + packages/ckeditor5-language/package.json | 46 +++++++ packages/ckeditor5-language/src/language.js | 39 ++++++ .../ckeditor5-language/src/languagecommand.js | 113 ++++++++++++++++ .../ckeditor5-language/src/languageediting.js | 59 +++++++++ packages/ckeditor5-language/src/languageui.js | 121 ++++++++++++++++++ .../tests/manual/language.html | 3 + .../tests/manual/language.js | 25 ++++ .../tests/manual/language.md | 1 + .../ckeditor5-language/theme/language.css | 3 + packages/ckeditor5-language/webpack.config.js | 17 +++ 15 files changed, 473 insertions(+) create mode 100644 packages/ckeditor5-language/CHANGELOG.md create mode 100644 packages/ckeditor5-language/CONTRIBUTING.md create mode 100644 packages/ckeditor5-language/LICENSE.md create mode 100644 packages/ckeditor5-language/README.md create mode 100644 packages/ckeditor5-language/lang/contexts.json create mode 100644 packages/ckeditor5-language/package.json create mode 100644 packages/ckeditor5-language/src/language.js create mode 100644 packages/ckeditor5-language/src/languagecommand.js create mode 100644 packages/ckeditor5-language/src/languageediting.js create mode 100644 packages/ckeditor5-language/src/languageui.js create mode 100644 packages/ckeditor5-language/tests/manual/language.html create mode 100644 packages/ckeditor5-language/tests/manual/language.js create mode 100644 packages/ckeditor5-language/tests/manual/language.md create mode 100644 packages/ckeditor5-language/theme/language.css create mode 100644 packages/ckeditor5-language/webpack.config.js diff --git a/packages/ckeditor5-language/CHANGELOG.md b/packages/ckeditor5-language/CHANGELOG.md new file mode 100644 index 00000000000..ec963d04c7d --- /dev/null +++ b/packages/ckeditor5-language/CHANGELOG.md @@ -0,0 +1,6 @@ +Changelog +========= + +All changes in the package are documented in the main repository. See: https://github.com/ckeditor/ckeditor5/blob/master/CHANGELOG.md. + +Changes for the past releases are available below. diff --git a/packages/ckeditor5-language/CONTRIBUTING.md b/packages/ckeditor5-language/CONTRIBUTING.md new file mode 100644 index 00000000000..95e8a028382 --- /dev/null +++ b/packages/ckeditor5-language/CONTRIBUTING.md @@ -0,0 +1,4 @@ +Contributing +======================================== + +See the [official contributors' guide to CKEditor 5](https://ckeditor.com/docs/ckeditor5/latest/framework/guides/contributing/contributing.html) to learn more. diff --git a/packages/ckeditor5-language/LICENSE.md b/packages/ckeditor5-language/LICENSE.md new file mode 100644 index 00000000000..a28e789437a --- /dev/null +++ b/packages/ckeditor5-language/LICENSE.md @@ -0,0 +1,17 @@ +Software License Agreement +========================== + +**CKEditor 5 Language Feature** – https://github.com/ckeditor/ckeditor5-language
+Copyright (c) 2003-2021, [CKSource](http://cksource.com) Frederico Knabben. All rights reserved. + +Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html). + +Sources of Intellectual Property Included in CKEditor +----------------------------------------------------- + +Where not otherwise indicated, all CKEditor content is authored by CKSource engineers and consists of CKSource-owned intellectual property. In some specific instances, CKEditor will incorporate work done by developers outside of CKSource with their express permission. + +Trademarks +---------- + +**CKEditor** is a trademark of [CKSource](http://cksource.com) Frederico Knabben. All other brand and product names are trademarks, registered trademarks or service marks of their respective holders. diff --git a/packages/ckeditor5-language/README.md b/packages/ckeditor5-language/README.md new file mode 100644 index 00000000000..a2205b3881e --- /dev/null +++ b/packages/ckeditor5-language/README.md @@ -0,0 +1,16 @@ +CKEditor 5 language feature +======================================== + +[![npm version](https://badge.fury.io/js/%40ckeditor%2Fckeditor5-language.svg)](https://www.npmjs.com/package/@ckeditor/ckeditor5-language) +[![Dependency Status](https://david-dm.org/ckeditor/ckeditor5-language/status.svg)](https://david-dm.org/ckeditor/ckeditor5-language) +[![devDependency Status](https://david-dm.org/ckeditor/ckeditor5-language/dev-status.svg)](https://david-dm.org/ckeditor/ckeditor5-language?type=dev) + +This package implements language support for CKEditor 5. + +## Documentation + +See the [`@ckeditor/ckeditor5-language` package](https://ckeditor.com/docs/ckeditor5/latest/api/language.html) page in [CKEditor 5 documentation](https://ckeditor.com/docs/ckeditor5/latest/). + +## License + +Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html). For full details about the license, please check the `LICENSE.md` file or [https://ckeditor.com/legal/ckeditor-oss-license](https://ckeditor.com/legal/ckeditor-oss-license). diff --git a/packages/ckeditor5-language/lang/contexts.json b/packages/ckeditor5-language/lang/contexts.json new file mode 100644 index 00000000000..bd576f6e597 --- /dev/null +++ b/packages/ckeditor5-language/lang/contexts.json @@ -0,0 +1,3 @@ +{ + "Language": "Toolbar button tooltip for the Language feature." +} diff --git a/packages/ckeditor5-language/package.json b/packages/ckeditor5-language/package.json new file mode 100644 index 00000000000..a448dab28d0 --- /dev/null +++ b/packages/ckeditor5-language/package.json @@ -0,0 +1,46 @@ +{ + "name": "@ckeditor/ckeditor5-language", + "version": "25.0.0", + "description": "Block quote feature for CKEditor 5.", + "keywords": [ + "ckeditor", + "ckeditor5", + "ckeditor 5", + "ckeditor5-feature", + "ckeditor5-plugin" + ], + "main": "src/index.js", + "dependencies": { + "ckeditor5": "^25.0.0" + }, + "devDependencies": { + "@ckeditor/ckeditor5-core": "^25.0.0", + "@ckeditor/ckeditor5-dev-utils": "^24.0.0", + "@ckeditor/ckeditor5-editor-classic": "^25.0.0", + "@ckeditor/ckeditor5-theme-lark": "^25.0.0", + "webpack": "^4.43.0", + "webpack-cli": "^3.3.11" + }, + "engines": { + "node": ">=12.0.0", + "npm": ">=5.7.1" + }, + "author": "CKSource (http://cksource.com/)", + "license": "GPL-2.0-or-later", + "homepage": "https://ckeditor.com/ckeditor-5", + "bugs": "https://github.com/ckeditor/ckeditor5/issues", + "repository": { + "type": "git", + "url": "https://github.com/ckeditor/ckeditor5.git", + "directory": "packages/ckeditor5-language" + }, + "files": [ + "lang", + "src", + "theme", + "build" + ], + "scripts": { + "build:dll": "webpack" + } +} diff --git a/packages/ckeditor5-language/src/language.js b/packages/ckeditor5-language/src/language.js new file mode 100644 index 00000000000..4a3648cc1e7 --- /dev/null +++ b/packages/ckeditor5-language/src/language.js @@ -0,0 +1,39 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module language/language + */ + +import { Plugin } from 'ckeditor5/src/core'; + +import LanguageEditing from './languageediting'; +import LanguageUI from './languageui'; + +/** + * The language plugin. + * + * For more information about this feature check the {@glink api/language package page}. + * + * This is a "glue" plugin which loads the {@link module:language/languageediting~LanguageEditing language editing feature} + * and {@link module:language/languageui~LanguageUI language UI feature}. + * + * @extends module:core/plugin~Plugin + */ +export default class Language extends Plugin { + /** + * @inheritDoc + */ + static get requires() { + return [ LanguageEditing, LanguageUI ]; + } + + /** + * @inheritDoc + */ + static get pluginName() { + return 'Language'; + } +} diff --git a/packages/ckeditor5-language/src/languagecommand.js b/packages/ckeditor5-language/src/languagecommand.js new file mode 100644 index 00000000000..bfb143b5fea --- /dev/null +++ b/packages/ckeditor5-language/src/languagecommand.js @@ -0,0 +1,113 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module language/languagecommand + */ + +import { Command } from 'ckeditor5/src/core'; + +/** + * The language command plugin. + * + * @extends module:core/command~Command + */ +export default class LanguageCommand extends Command { + /** + * @param {module:core/editor/editor~Editor} editor + * @param {String} attributeKey Attribute that will be set by the command. + */ + constructor( editor, attributeKey ) { + super( editor ); + + /** + * The attribute that will be set by the command. + * + * @readonly + * @member {String} + */ + this.attributeKey = attributeKey; + + /** + * If the selection starts in a language attribute the value is set to the code of that language. + * + * It is set to `false` otherwise. + * + * @observable + * @readonly + * @member {Boolean|String} #value + */ + } + + /** + * @inheritDoc + */ + refresh() { + const model = this.editor.model; + const doc = model.document; + + this.value = this._getValueFromFirstAllowedNode(); + this.isEnabled = model.schema.checkAttributeInSelection( doc.selection, this.attributeKey ); + } + + /** + * @fires execute + * @param {Object} [options] Command options. + * @param {String} [options.value] Language code to be applied to the model. + */ + execute( options = {} ) { + const model = this.editor.model; + const doc = model.document; + const selection = doc.selection; + const value = options.value; + + model.change( writer => { + if ( selection.isCollapsed ) { + if ( value ) { + writer.setSelectionAttribute( this.attributeKey, value ); + } else { + writer.removeSelectionAttribute( this.attributeKey ); + } + } else { + const ranges = model.schema.getValidRanges( selection.getRanges(), this.attributeKey ); + + for ( const range of ranges ) { + if ( value ) { + writer.setAttribute( this.attributeKey, value, range ); + } else { + writer.removeAttribute( this.attributeKey, range ); + } + } + } + } ); + } + + /** + * Checks the attribute value of the first node in the selection that allows the attribute. + * For the collapsed selection returns the selection attribute. + * + * @private + * @returns {Boolean} The attribute value. + */ + _getValueFromFirstAllowedNode() { + const model = this.editor.model; + const schema = model.schema; + const selection = model.document.selection; + + if ( selection.isCollapsed ) { + return selection.getAttribute( this.attributeKey ) || false; + } + + for ( const range of selection.getRanges() ) { + for ( const item of range.getItems() ) { + if ( schema.checkAttribute( item, this.attributeKey ) ) { + return item.getAttribute( this.attributeKey ) || false; + } + } + } + + return false; + } +} diff --git a/packages/ckeditor5-language/src/languageediting.js b/packages/ckeditor5-language/src/languageediting.js new file mode 100644 index 00000000000..f437db6dc1d --- /dev/null +++ b/packages/ckeditor5-language/src/languageediting.js @@ -0,0 +1,59 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module block-quote/languageediting + */ + +import { Plugin } from 'ckeditor5/src/core'; +import LanguageCommand from './languagecommand'; + +const LANGUAGE = 'language'; + +/** + * The language editing. + * + * Introduces the `'language'` command and the `'language'` model element. + * + * @extends module:core/plugin~Plugin + */ +export default class LanguageEditing extends Plugin { + /** + * @inheritDoc + */ + static get pluginName() { + return 'LanguageEditing'; + } + + /** + * @inheritDoc + */ + init() { + const editor = this.editor; + + editor.model.schema.extend( '$text', { allowAttributes: LANGUAGE } ); + editor.model.schema.setAttributeProperties( LANGUAGE, { + copyOnEnter: true + } ); + + editor.conversion.for( 'upcast' ).attributeToAttribute( { + model: LANGUAGE, + view: 'lang' + } ); + + editor.conversion.for( 'downcast' ).attributeToElement( { + model: LANGUAGE, + view: ( attributeValue, { writer } ) => { + if ( !attributeValue ) { + return; + } + + return writer.createAttributeElement( 'span', { 'lang': attributeValue } ); + } + } ); + + editor.commands.add( LANGUAGE, new LanguageCommand( editor, LANGUAGE ) ); + } +} diff --git a/packages/ckeditor5-language/src/languageui.js b/packages/ckeditor5-language/src/languageui.js new file mode 100644 index 00000000000..15f1818e5b8 --- /dev/null +++ b/packages/ckeditor5-language/src/languageui.js @@ -0,0 +1,121 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module language/languageui + */ + +import { Plugin } from 'ckeditor5/src/core'; +import { Model, createDropdown, addListToDropdown } from 'ckeditor5/src/ui'; +import { Collection } from 'ckeditor5/src/utils'; + +import '../theme/language.css'; + +/** + * The language UI plugin. + * + * It introduces the `'language'` button. + * + * @extends module:core/plugin~Plugin + */ +export default class LanguageUI extends Plugin { + /** + * @inheritDoc + */ + static get pluginName() { + return 'LanguageUI'; + } + + /** + * @inheritDoc + */ + init() { + const editor = this.editor; + const t = editor.t; + const options = getLocalizedOptions( editor ); + const defaultTitle = t( 'Choose language' ); + const removeTitle = t( 'Remove language' ); + const dropdownTooltip = t( 'Language' ); + + // Register UI component. + editor.ui.componentFactory.add( 'language', locale => { + const itemDefinitions = new Collection(); + const titles = {}; + + const languageCommand = editor.commands.get( 'language' ); + + for ( const option of options ) { + const def = { + type: 'button', + model: new Model( { + label: option.title, + class: option.class, + languageCode: option.languageCode, + textDirection: option.textDirection, + withText: true + } ) + }; + + def.model.bind( 'isOn' ).to( languageCommand, 'value', value => value === option.languageCode ); + + itemDefinitions.add( def ); + + titles[ option.languageCode ] = option.title; + } + + itemDefinitions.add( { + type: 'separator' + } ); + + // Item definition with false `languageCode` will behave as remove lang button. + itemDefinitions.add( { + type: 'button', + model: new Model( { + label: removeTitle, + languageCode: false, + withText: true + } ) + } ); + + const dropdownView = createDropdown( locale ); + addListToDropdown( dropdownView, itemDefinitions ); + + dropdownView.buttonView.set( { + isOn: false, + withText: true, + tooltip: dropdownTooltip + } ); + + dropdownView.extendTemplate( { + attributes: { + class: [ + 'ck-language-dropdown' + ] + } + } ); + + dropdownView.bind( 'isEnabled' ).to( languageCommand, 'isEnabled' ); + dropdownView.buttonView.bind( 'label' ).to( languageCommand, 'value', value => { + return titles[ value ] || defaultTitle; + } ); + + // Execute command when an item from the dropdown is selected. + this.listenTo( dropdownView, 'execute', evt => { + editor.execute( 'language', { value: evt.source.languageCode } ); + editor.editing.view.focus(); + } ); + + return dropdownView; + } ); + } +} + +function getLocalizedOptions() { + return [ + { title: 'Arabic', class: 'ck-language_ar', languageCode: 'ar', textDirection: 'rtl' }, + { title: 'French', class: 'ck-language_fr', languageCode: 'fr', textDirection: 'ltr' }, + { title: 'Spanish', class: 'ck-language_es', languageCode: 'es', textDirection: 'ltr' } + ]; +} diff --git a/packages/ckeditor5-language/tests/manual/language.html b/packages/ckeditor5-language/tests/manual/language.html new file mode 100644 index 00000000000..7e990c0469c --- /dev/null +++ b/packages/ckeditor5-language/tests/manual/language.html @@ -0,0 +1,3 @@ +
+

Hello, world!

+
diff --git a/packages/ckeditor5-language/tests/manual/language.js b/packages/ckeditor5-language/tests/manual/language.js new file mode 100644 index 00000000000..2bef3ae0b21 --- /dev/null +++ b/packages/ckeditor5-language/tests/manual/language.js @@ -0,0 +1,25 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/* global document, console, window */ + +import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor'; +import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset'; +import Language from '../../src/language'; + +ClassicEditor + .create( document.querySelector( '#editor' ), { + plugins: [ + ArticlePluginSet, + Language + ], + toolbar: [ 'language', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ] + } ) + .then( editor => { + window.editor = editor; + } ) + .catch( err => { + console.error( err.stack ); + } ); diff --git a/packages/ckeditor5-language/tests/manual/language.md b/packages/ckeditor5-language/tests/manual/language.md new file mode 100644 index 00000000000..a2e69359bab --- /dev/null +++ b/packages/ckeditor5-language/tests/manual/language.md @@ -0,0 +1 @@ +## Language diff --git a/packages/ckeditor5-language/theme/language.css b/packages/ckeditor5-language/theme/language.css new file mode 100644 index 00000000000..73c85a8f4cc --- /dev/null +++ b/packages/ckeditor5-language/theme/language.css @@ -0,0 +1,3 @@ +.ck-content span[lang] { + font-style: italic; +} diff --git a/packages/ckeditor5-language/webpack.config.js b/packages/ckeditor5-language/webpack.config.js new file mode 100644 index 00000000000..fcaa78a2eed --- /dev/null +++ b/packages/ckeditor5-language/webpack.config.js @@ -0,0 +1,17 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +'use strict'; + +/* eslint-env node */ + +const { builds } = require( '@ckeditor/ckeditor5-dev-utils' ); + +module.exports = builds.getDllPluginWebpackConfig( { + themePath: require.resolve( '@ckeditor/ckeditor5-theme-lark' ), + packagePath: __dirname, + manifestPath: require.resolve( 'ckeditor5/build/ckeditor5-dll.manifest.json' ), + isDevelopmentMode: process.argv.includes( '--dev' ) +} ); From 593709d1d6eee20a14c3634688ea0723dcaecbed Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Fri, 19 Feb 2021 08:51:29 +0100 Subject: [PATCH 02/36] Added text direction support and documentation. --- packages/ckeditor5-language/src/language.js | 61 +++++++++++++++++++ .../ckeditor5-language/src/languagecommand.js | 39 +++++++++--- .../ckeditor5-language/src/languageediting.js | 57 ++++++++++++++--- packages/ckeditor5-language/src/languageui.js | 16 ++--- packages/ckeditor5-language/src/utils.js | 44 +++++++++++++ packages/ckeditor5-utils/src/language.js | 26 ++++++++ packages/ckeditor5-utils/src/locale.js | 11 +--- 7 files changed, 220 insertions(+), 34 deletions(-) create mode 100644 packages/ckeditor5-language/src/utils.js create mode 100644 packages/ckeditor5-utils/src/language.js diff --git a/packages/ckeditor5-language/src/language.js b/packages/ckeditor5-language/src/language.js index 4a3648cc1e7..ed2455c3888 100644 --- a/packages/ckeditor5-language/src/language.js +++ b/packages/ckeditor5-language/src/language.js @@ -37,3 +37,64 @@ export default class Language extends Plugin { return 'Language'; } } + +/** + * The configuration of the language feature. Introduced by the {@link module:language/languageediting~LanguageEditing} feature. + * + * Read more in {@link module:language/language~LanguageConfig}. + * + * @member {module:language/language~LanguageConfig} module:core/editor/editorconfig~EditorConfig#language + */ + +/** + * The configuration of the language feature. + * The option is used by the {@link module:language/languageediting~LanguageEditing} feature. + * + * ClassicEditor + * .create( { + * language: ... // Language feature config. + * } ) + * .then( ... ) + * .catch( ... ); + * + * See {@link module:core/editor/editorconfig~EditorConfig all editor options}. + * + * @interface LanguageConfig + */ + +/** + * The available language options. + * + * The default value is: + * + * const languageConfig = { + * options: [ + * { title: 'Arabic', class: 'ck-language_ar', languageCode: 'ar' }, + * { title: 'French', class: 'ck-language_fr', languageCode: 'fr' }, + * { title: 'Spanish', class: 'ck-language_es', languageCode: 'es' } + * ] + * }; + * + * The `title` and `class` properties will be used by the `language` dropdown to render available options. + * + * The `languageCode` property is used for the lang attribute in ISO 639 format. Language codes can be found + * [here](http://www.loc.gov/standards/iso639-2/php/English_list.php). You can use both 2-letter ISO-639-1 codes + * and 3-letter ISO-639-2 codes, though for consistency it is recommended to stick to ISO-639-1 2-letter codes. + * + * You can also specify optional `textDirection` property indicating the reading direction of the language. + * Correct values are `ltr` and `rtl`. When `textDirection` property is missing, the language feature will + * specify text direction by itself. + * + * @member {Array.} module:language/language~LanguageConfig#options + */ + +/** + * Language option descriptor. + * + * @typedef {Object} module:language/language~LanguageOption + * @property {String} title The user-readable title of the option. + * @property {String} class The class which will be added to the dropdown item representing this option. + * @property {String} languageCode The language code in ISO 639 format. + * @property {Strint} [textDirection] Language text direction. Automatically detected if omitted. + * @extends module:engine/conversion/conversion~ConverterDefinition + */ diff --git a/packages/ckeditor5-language/src/languagecommand.js b/packages/ckeditor5-language/src/languagecommand.js index bfb143b5fea..a598e05be84 100644 --- a/packages/ckeditor5-language/src/languagecommand.js +++ b/packages/ckeditor5-language/src/languagecommand.js @@ -8,6 +8,7 @@ */ import { Command } from 'ckeditor5/src/core'; +import { parseLanguageToString } from './utils'; /** * The language command plugin. @@ -31,9 +32,17 @@ export default class LanguageCommand extends Command { this.attributeKey = attributeKey; /** - * If the selection starts in a language attribute the value is set to the code of that language. + * If the selection starts in a language attribute the value is set to + * the value of that language in a format: * - * It is set to `false` otherwise. + * : + * + * * `languageCode` - The language code used for the lang attribute in ISO 639 format. + * * `textDirection` - One of the following values: `rtl` or `ltr`, indicating the reading direction of the language. + * + * See {@link module:language/language~LanguageConfig language config} for more information about language properties. + * + * It is set to `false` otherwise. * * @observable * @readonly @@ -53,15 +62,31 @@ export default class LanguageCommand extends Command { } /** + * Executes the command. Applies the attribute to the selection or removes it from the selection. + * + * If `languageCode` is set to `false` or `null` value, it will remove attributes. Otherwise, it will set + * attribute in `{@link #value value}` format. + * + * The execution result differs, depending on the {@link module:engine/model/document~Document#selection}: + * + * * If the selection is on a range, the command applies the attribute to all nodes in that range + * (if they are allowed to have this attribute by the {@link module:engine/model/schema~Schema schema}). + * * If the selection is collapsed in a non-empty node, the command applies the attribute to the + * {@link module:engine/model/document~Document#selection} itself (note that typed characters copy attributes from the selection). + * * If the selection is collapsed in an empty node, the command applies the attribute to the parent node of the selection (note + * that the selection inherits all attributes from a node if it is in an empty node). + * * @fires execute * @param {Object} [options] Command options. - * @param {String} [options.value] Language code to be applied to the model. + * @param {String|Boolean} [options.languageCode] Language code to be applied to the model. + * @param {String} [options.textDirection] Language text direction. */ - execute( options = {} ) { + execute( { languageCode, textDirection } = {} ) { const model = this.editor.model; const doc = model.document; const selection = doc.selection; - const value = options.value; + + const value = languageCode ? parseLanguageToString( languageCode, textDirection ) : false; model.change( writer => { if ( selection.isCollapsed ) { @@ -85,11 +110,11 @@ export default class LanguageCommand extends Command { } /** - * Checks the attribute value of the first node in the selection that allows the attribute. + * Returns the attribute value of the first node in the selection that allows the attribute. * For the collapsed selection returns the selection attribute. * * @private - * @returns {Boolean} The attribute value. + * @returns {Object} The attribute value. */ _getValueFromFirstAllowedNode() { const model = this.editor.model; diff --git a/packages/ckeditor5-language/src/languageediting.js b/packages/ckeditor5-language/src/languageediting.js index f437db6dc1d..08adf4ccfa0 100644 --- a/packages/ckeditor5-language/src/languageediting.js +++ b/packages/ckeditor5-language/src/languageediting.js @@ -9,6 +9,7 @@ import { Plugin } from 'ckeditor5/src/core'; import LanguageCommand from './languagecommand'; +import { parseLanguageToString, parseLanguageFromString } from './utils'; const LANGUAGE = 'language'; @@ -27,6 +28,23 @@ export default class LanguageEditing extends Plugin { return 'LanguageEditing'; } + /** + * @inheritDoc + */ + constructor( editor ) { + super( editor ); + + const t = editor.t; + + editor.config.define( 'language', { + options: [ + { title: t( 'Arabic' ), class: 'ck-language_ar', languageCode: 'ar' }, + { title: t( 'French' ), class: 'ck-language_fr', languageCode: 'fr' }, + { title: t( 'Spanish' ), class: 'ck-language_es', languageCode: 'es' } + ] + } ); + } + /** * @inheritDoc */ @@ -38,22 +56,47 @@ export default class LanguageEditing extends Plugin { copyOnEnter: true } ); - editor.conversion.for( 'upcast' ).attributeToAttribute( { - model: LANGUAGE, - view: 'lang' + this._defineConverters(); + + editor.commands.add( LANGUAGE, new LanguageCommand( editor, LANGUAGE ) ); + } + + /** + * @private + */ + _defineConverters() { + const conversion = this.editor.conversion; + + conversion.for( 'upcast' ).elementToAttribute( { + model: { + key: LANGUAGE, + value: viewElement => { + const languageCode = viewElement.getAttribute( 'lang' ); + const textDirection = viewElement.getAttribute( 'dir' ); + + return parseLanguageToString( languageCode, textDirection ); + } + }, + view: { + name: 'span', + attributes: { lang: /[^]/ } + } } ); - editor.conversion.for( 'downcast' ).attributeToElement( { + conversion.for( 'downcast' ).attributeToElement( { model: LANGUAGE, view: ( attributeValue, { writer } ) => { if ( !attributeValue ) { return; } - return writer.createAttributeElement( 'span', { 'lang': attributeValue } ); + const { languageCode, textDirection } = parseLanguageFromString( attributeValue ); + + return writer.createAttributeElement( 'span', { + lang: languageCode, + dir: textDirection + } ); } } ); - - editor.commands.add( LANGUAGE, new LanguageCommand( editor, LANGUAGE ) ); } } diff --git a/packages/ckeditor5-language/src/languageui.js b/packages/ckeditor5-language/src/languageui.js index 15f1818e5b8..de87fed6ff7 100644 --- a/packages/ckeditor5-language/src/languageui.js +++ b/packages/ckeditor5-language/src/languageui.js @@ -34,7 +34,7 @@ export default class LanguageUI extends Plugin { init() { const editor = this.editor; const t = editor.t; - const options = getLocalizedOptions( editor ); + const options = editor.config.get( 'language.options' ); const defaultTitle = t( 'Choose language' ); const removeTitle = t( 'Remove language' ); const dropdownTooltip = t( 'Language' ); @@ -103,7 +103,11 @@ export default class LanguageUI extends Plugin { // Execute command when an item from the dropdown is selected. this.listenTo( dropdownView, 'execute', evt => { - editor.execute( 'language', { value: evt.source.languageCode } ); + editor.execute( 'language', { + languageCode: evt.source.languageCode, + textDirection: evt.source.textDirection + } ); + editor.editing.view.focus(); } ); @@ -111,11 +115,3 @@ export default class LanguageUI extends Plugin { } ); } } - -function getLocalizedOptions() { - return [ - { title: 'Arabic', class: 'ck-language_ar', languageCode: 'ar', textDirection: 'rtl' }, - { title: 'French', class: 'ck-language_fr', languageCode: 'fr', textDirection: 'ltr' }, - { title: 'Spanish', class: 'ck-language_es', languageCode: 'es', textDirection: 'ltr' } - ]; -} diff --git a/packages/ckeditor5-language/src/utils.js b/packages/ckeditor5-language/src/utils.js new file mode 100644 index 00000000000..8d9da443b76 --- /dev/null +++ b/packages/ckeditor5-language/src/utils.js @@ -0,0 +1,44 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module language/utils + */ + +import { getLanguageDirection } from '@ckeditor/ckeditor5-utils/src/language'; + +/** + * Returns language attribute value in a human-readable text format: + * + * : + * + * * `languageCode` - The language code used for the lang attribute in ISO 639 format. + * * `textDirection` - One of the following values: `rtl` or `ltr`, indicating the reading direction of the language. + * + * See {@link module:language/language~LanguageConfig language config} for more information about language properties. + * + * If `textDirection` argument is omitted, it will be automatically detected based on `languageCode`. + * + * @param {String} languageCode The language code in ISO 639 format. + * @param {String} [textDirection] Language text direction. Automatically detected if omitted. + */ +export function parseLanguageToString( languageCode, textDirection ) { + textDirection = textDirection || getLanguageDirection( languageCode ); + return `${ languageCode }:${ textDirection }`; +} + +/** + * Retrieves language properties converted to attribute value by + * {@link module:language/utils~parseLanguageToString parseLanguageToString} function. + * + * @param {String} str Attribute value. + * @returns result + * @returns result.languageCode The language code in ISO 639 format. + * @returns result.textDirection Language text direction. + */ +export function parseLanguageFromString( str ) { + const parts = str.split( ':' ); + return { languageCode: parts[ 0 ], textDirection: parts[ 1 ] }; +} diff --git a/packages/ckeditor5-utils/src/language.js b/packages/ckeditor5-utils/src/language.js new file mode 100644 index 00000000000..561a96c95d5 --- /dev/null +++ b/packages/ckeditor5-utils/src/language.js @@ -0,0 +1,26 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module utils/language + */ + +const RTL_LANGUAGE_CODES = [ + 'ar', 'ara', // Arabic + 'fa', 'per', 'fas', // Persian + 'he', 'heb', // Hebrew + 'ku', 'kur', // Kurdish + 'ug', 'uig' // Uighur, Uyghur +]; + +/** + * Helps determine whether a language text direction is LTR or RTL. + * + * @param {String} language The ISO 639 language code. + * @returns {String} 'ltr' or 'rtl + */ +export function getLanguageDirection( languageCode ) { + return RTL_LANGUAGE_CODES.includes( languageCode ) ? 'rtl' : 'ltr'; +} diff --git a/packages/ckeditor5-utils/src/locale.js b/packages/ckeditor5-utils/src/locale.js index 1e5c9413a34..e0ab46cbdcb 100644 --- a/packages/ckeditor5-utils/src/locale.js +++ b/packages/ckeditor5-utils/src/locale.js @@ -11,8 +11,7 @@ import toArray from './toarray'; import { _translate } from './translation-service'; - -const RTL_LANGUAGE_CODES = [ 'ar', 'fa', 'he', 'ku', 'ug' ]; +import { getLanguageDirection } from './language'; /** * Represents the localization services. @@ -175,11 +174,3 @@ function interpolateString( string, values ) { return ( index < values.length ) ? values[ index ] : match; } ); } - -// Helps determine whether a language is LTR or RTL. -// -// @param {String} language The ISO 639-1 language code. -// @returns {String} 'ltr' or 'rtl -function getLanguageDirection( languageCode ) { - return RTL_LANGUAGE_CODES.includes( languageCode ) ? 'rtl' : 'ltr'; -} From 6a9149193245c3e6adb8d054ec56ee62eb1ac3a6 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Fri, 19 Feb 2021 13:05:47 +0100 Subject: [PATCH 03/36] Added unit tests. --- packages/ckeditor5-language/package.json | 6 +- .../ckeditor5-language/src/languageediting.js | 10 +- packages/ckeditor5-language/src/languageui.js | 10 +- packages/ckeditor5-language/src/utils.js | 20 + packages/ckeditor5-language/tests/language.js | 18 + .../tests/languagecommand.js | 383 ++++++++++++++++++ .../tests/languageediting.js | 103 +++++ .../ckeditor5-language/tests/languageui.js | 261 ++++++++++++ 8 files changed, 801 insertions(+), 10 deletions(-) create mode 100644 packages/ckeditor5-language/tests/language.js create mode 100644 packages/ckeditor5-language/tests/languagecommand.js create mode 100644 packages/ckeditor5-language/tests/languageediting.js create mode 100644 packages/ckeditor5-language/tests/languageui.js diff --git a/packages/ckeditor5-language/package.json b/packages/ckeditor5-language/package.json index a448dab28d0..3ae76cd8a7f 100644 --- a/packages/ckeditor5-language/package.json +++ b/packages/ckeditor5-language/package.json @@ -11,13 +11,17 @@ ], "main": "src/index.js", "dependencies": { - "ckeditor5": "^25.0.0" + "ckeditor5": "^25.0.0", + "@ckeditor/ckeditor5-utils": "^25.0.0" }, "devDependencies": { "@ckeditor/ckeditor5-core": "^25.0.0", "@ckeditor/ckeditor5-dev-utils": "^24.0.0", "@ckeditor/ckeditor5-editor-classic": "^25.0.0", + "@ckeditor/ckeditor5-engine": "^25.0.0", + "@ckeditor/ckeditor5-paragraph": "^25.0.0", "@ckeditor/ckeditor5-theme-lark": "^25.0.0", + "@ckeditor/ckeditor5-ui": "^25.0.0", "webpack": "^4.43.0", "webpack-cli": "^3.3.11" }, diff --git a/packages/ckeditor5-language/src/languageediting.js b/packages/ckeditor5-language/src/languageediting.js index 08adf4ccfa0..343e529a93c 100644 --- a/packages/ckeditor5-language/src/languageediting.js +++ b/packages/ckeditor5-language/src/languageediting.js @@ -34,13 +34,11 @@ export default class LanguageEditing extends Plugin { constructor( editor ) { super( editor ); - const t = editor.t; - - editor.config.define( 'language', { + editor.config.define( 'languageList', { options: [ - { title: t( 'Arabic' ), class: 'ck-language_ar', languageCode: 'ar' }, - { title: t( 'French' ), class: 'ck-language_fr', languageCode: 'fr' }, - { title: t( 'Spanish' ), class: 'ck-language_es', languageCode: 'es' } + { title: 'Arabic', class: 'ck-language_ar', languageCode: 'ar' }, + { title: 'French', class: 'ck-language_fr', languageCode: 'fr' }, + { title: 'Spanish', class: 'ck-language_es', languageCode: 'es' } ] } ); } diff --git a/packages/ckeditor5-language/src/languageui.js b/packages/ckeditor5-language/src/languageui.js index de87fed6ff7..b3ddba223c7 100644 --- a/packages/ckeditor5-language/src/languageui.js +++ b/packages/ckeditor5-language/src/languageui.js @@ -10,6 +10,7 @@ import { Plugin } from 'ckeditor5/src/core'; import { Model, createDropdown, addListToDropdown } from 'ckeditor5/src/ui'; import { Collection } from 'ckeditor5/src/utils'; +import { parseLanguageToString, getLocalizedOptions } from './utils'; import '../theme/language.css'; @@ -34,7 +35,7 @@ export default class LanguageUI extends Plugin { init() { const editor = this.editor; const t = editor.t; - const options = editor.config.get( 'language.options' ); + const options = getLocalizedOptions( editor ); const defaultTitle = t( 'Choose language' ); const removeTitle = t( 'Remove language' ); const dropdownTooltip = t( 'Language' ); @@ -58,11 +59,13 @@ export default class LanguageUI extends Plugin { } ) }; - def.model.bind( 'isOn' ).to( languageCommand, 'value', value => value === option.languageCode ); + const language = parseLanguageToString( option.languageCode, option.textDirection ); + + def.model.bind( 'isOn' ).to( languageCommand, 'value', value => value === language ); itemDefinitions.add( def ); - titles[ option.languageCode ] = option.title; + titles[ language ] = option.title; } itemDefinitions.add( { @@ -74,6 +77,7 @@ export default class LanguageUI extends Plugin { type: 'button', model: new Model( { label: removeTitle, + class: 'ck-language_remove', languageCode: false, withText: true } ) diff --git a/packages/ckeditor5-language/src/utils.js b/packages/ckeditor5-language/src/utils.js index 8d9da443b76..15548c9cbfc 100644 --- a/packages/ckeditor5-language/src/utils.js +++ b/packages/ckeditor5-language/src/utils.js @@ -42,3 +42,23 @@ export function parseLanguageFromString( str ) { const parts = str.split( ':' ); return { languageCode: parts[ 0 ], textDirection: parts[ 1 ] }; } + +/** + * Returns language options as defined in `config.languageList.options` but processed to consider + * the editor localization, i.e. to display {@link module:language/language~LanguageOption} + * in the correct language. + * + * Note: The reason behind this method is that there is no way to use {@link module:utils/locale~Locale#t} + * when the user configuration is defined because the editor does not exist yet. + * + * @param {module:core/editor/editor~Editor} editor + * @returns {Array.}. + */ +export function getLocalizedOptions( editor ) { + const t = editor.t; + + return editor.config.get( 'languageList.options' ).map( option => { + option.title = t( option.title ); + return option; + } ); +} diff --git a/packages/ckeditor5-language/tests/language.js b/packages/ckeditor5-language/tests/language.js new file mode 100644 index 00000000000..4bf7f676323 --- /dev/null +++ b/packages/ckeditor5-language/tests/language.js @@ -0,0 +1,18 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +import Language from '../src/language'; +import LanguageEditing from '../src/languageediting'; +import LanguageUI from '../src/languageui'; + +describe( 'Language', () => { + it( 'should require LanguageEditing and LanguageUI', () => { + expect( Language.requires ).to.deep.equal( [ LanguageEditing, LanguageUI ] ); + } ); + + it( 'should be named', () => { + expect( Language.pluginName ).to.equal( 'Language' ); + } ); +} ); diff --git a/packages/ckeditor5-language/tests/languagecommand.js b/packages/ckeditor5-language/tests/languagecommand.js new file mode 100644 index 00000000000..57daf24e203 --- /dev/null +++ b/packages/ckeditor5-language/tests/languagecommand.js @@ -0,0 +1,383 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor'; +import LanguageCommand from '../src/languagecommand'; +import { setData, getData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; + +describe( 'LanguageCommand', () => { + const attrKey = 'language'; + let editor, command, model, doc, root; + + beforeEach( () => { + return ModelTestEditor + .create() + .then( newEditor => { + editor = newEditor; + model = editor.model; + doc = model.document; + root = doc.getRoot(); + + command = new LanguageCommand( editor, attrKey ); + + model.schema.register( 'p', { inheritAllFrom: '$block' } ); + model.schema.register( 'h1', { inheritAllFrom: '$block' } ); + model.schema.register( 'img', { + allowWhere: [ '$block', '$text' ], + isObject: true + } ); + + model.schema.addAttributeCheck( ( ctx, attributeName ) => { + // Allow 'language' on p>$text. + if ( ctx.endsWith( 'p $text' ) && attributeName == 'language' ) { + return true; + } + } ); + } ); + } ); + + afterEach( () => { + command.destroy(); + + return editor.destroy(); + } ); + + describe( 'value', () => { + it( 'includes language when collapsed selection has the attribute', () => { + model.change( writer => { + writer.setSelectionAttribute( attrKey, 'fr:ltr' ); + } ); + + expect( command.value ).to.eql( 'fr:ltr' ); + } ); + + it( 'is false when collapsed selection does not have the attribute', () => { + model.change( writer => { + writer.setSelectionAttribute( attrKey, 'fr:ltr' ); + } ); + + model.change( writer => { + writer.removeSelectionAttribute( attrKey ); + } ); + + expect( command.value ).to.be.false; + } ); + + it( 'includes language when the first item that allows attribute has the attribute #1', () => { + setData( model, '

<$text language="fr:ltr">fo[o

b]ar

' ); + + expect( command.value ).to.eql( 'fr:ltr' ); + } ); + + it( 'includes language when the first item that allows attribute has the attribute #2', () => { + setData( model, '

fo[o

<$text language="fr:ltr">fo]o

' ); + + expect( command.value ).to.eql( 'fr:ltr' ); + } ); + + it( 'is false when the selection does not have the attribute', () => { + setData( model, '

[foo]bar

' ); + + expect( command.value ).to.be.false; + } ); + + it( 'is false when the first item that allows attribute does not have the attribute #1', () => { + setData( model, '

b[a<$text language="fr:ltr">r

fo]o

' ); + + expect( command.value ).to.be.false; + } ); + + it( 'is false when the first item that allows attribute does not have the attribute #2', () => { + setData( model, '

fo[o

b<$text language="fr:ltr">rr]

' ); + + expect( command.value ).to.be.false; + } ); + + it( 'includes language when the first item that allows attribute has the attribute - object with nested editable', () => { + model.schema.register( 'caption', { + allowContentOf: '$block', + allowIn: 'img', + isLimit: true + } ); + model.schema.extend( '$text', { + allowIn: 'caption', + allowAttributes: 'language' + } ); + + setData( model, '

[Some caption inside the image.]

' ); + + expect( command.value ).to.be.false; + command.execute( { languageCode: 'fr', textDirection: 'ltr' } ); + + expect( command.value ).to.eql( 'fr:ltr' ); + + expect( getData( model ) ).equal( + '

[<$text language="fr:ltr">Some caption inside the image.]

' + ); + } ); + } ); + + describe( 'isEnabled', () => { + // This test doesn't tests every possible case. + // Method `refresh()` uses `checkAttributeInSelection()` which is fully tested in its own test. + + beforeEach( () => { + model.schema.register( 'x', { inheritAllFrom: '$block' } ); + } ); + + describe( 'when selection is collapsed', () => { + it( 'should return true if characters with the attribute can be placed at caret position', () => { + setData( model, '

f[]oo

' ); + expect( command.isEnabled ).to.be.true; + } ); + + it( 'should return false if characters with the attribute cannot be placed at caret position', () => { + setData( model, 'fo[]o' ); + expect( command.isEnabled ).to.be.false; + } ); + } ); + + describe( 'when selection is not collapsed', () => { + it( 'should return true if there is at least one node in selection that can have the attribute', () => { + setData( model, '

[foo]

' ); + expect( command.isEnabled ).to.be.true; + } ); + + it( 'should return false if there are no nodes in selection that can have the attribute', () => { + setData( model, '[foo]' ); + expect( command.isEnabled ).to.be.false; + } ); + } ); + + it( 'should be disabled in a readonly mode', () => { + editor.isReadOnly = true; + setData( model, '

f[]oo

' ); + expect( command.isEnabled ).to.be.false; + } ); + } ); + + describe( 'execute()', () => { + it( 'should do nothing if the command is disabled', () => { + setData( model, '

fo[ob]ar

' ); + + command.isEnabled = false; + + command.execute( { languageCode: 'fr', textDirection: 'ltr' } ); + + expect( getData( model ) ).equal( '

fo[ob]ar

' ); + } ); + + it( 'should add attribute on selected nodes if the command value was not set', () => { + setData( model, '

a[bc<$text language="fr:ltr">fo]obarxyz

' ); + + expect( command.value ).to.be.false; + + command.execute( { languageCode: 'fr', textDirection: 'ltr' } ); + + expect( command.value ).to.eql( 'fr:ltr' ); + expect( getData( model ) ).equal( '

a[<$text language="fr:ltr">bcfo]obarxyz

' ); + } ); + + it( 'should remove attribute from selected nodes if the command value was not set', () => { + setData( model, '

abc[<$text language="fr:ltr">foo]barxyz

' ); + + expect( command.value ).to.eql( 'fr:ltr' ); + + command.execute(); + + expect( getData( model ) ).equal( '

abc[foo]<$text language="fr:ltr">barxyz

' ); + expect( command.value ).to.be.false; + } ); + + it( 'should replace attribute on selected nodes if execute parameter was set', () => { + setData( model, '

abc<$text language="fr:ltr">foob[arx]yz

' ); + + expect( command.value ).to.eql( 'fr:ltr' ); + + command.execute( { languageCode: 'ar', textDirection: 'rtl' } ); + + expect( command.value ).to.eql( 'ar:rtl' ); + expect( getData( model ) ).equal( '

abc<$text language="fr:ltr">foob[<$text language="ar:rtl">arx]yz

' ); + } ); + + it( 'should remove attribute on selected nodes if execute parameter was set to false', () => { + setData( model, '

a[bc<$text language="fr:ltr">fo]obarxyz

' ); + + command.execute( { languageCode: false } ); + + expect( command.value ).to.be.false; + expect( getData( model ) ).equal( '

a[bcfo]<$text language="fr:ltr">obarxyz

' ); + } ); + + it( 'should remove attribute on selected nodes if execute parameter was set to null', () => { + setData( model, '

a[bc<$text language="fr:ltr">fo]obarxyz

' ); + + command.execute( { languageCode: null } ); + + expect( command.value ).to.be.false; + expect( getData( model ) ).equal( '

a[bcfo]<$text language="fr:ltr">obarxyz

' ); + } ); + + it( 'should change selection attribute if selection is collapsed in non-empty parent', () => { + setData( model, '

a[]bc<$text language="fr:ltr">foobarxyz

' ); + + expect( command.value ).to.be.false; + + command.execute( { languageCode: 'ar', textDirection: 'rtl' } ); + + expect( command.value ).to.eql( 'ar:rtl' ); + expect( doc.selection.getAttribute( 'language' ) ).to.eql( 'ar:rtl' ); + + command.execute( { languageCode: false } ); + + expect( command.value ).to.be.false; + expect( doc.selection.hasAttribute( 'language' ) ).to.be.false; + } ); + + it( 'should not store attribute change on selection if selection is collapsed in non-empty parent', () => { + setData( model, '

a[]bc<$text language="fr:ltr">foobarxyz

' ); + + command.execute( { languageCode: 'ar', textDirection: 'rtl' } ); + + // It should not save that language was executed at position ( root, [ 0, 1 ] ). + + model.change( writer => { + // Simulate clicking right arrow key by changing selection ranges. + writer.setSelection( writer.createRange( + writer.createPositionAt( root.getNodeByPath( [ 0 ] ), 2 ) + ) ); + + // Get back to previous selection. + writer.setSelection( writer.createRange( + writer.createPositionAt( root.getNodeByPath( [ 0 ] ), 1 ) + ) ); + } ); + + expect( command.value ).to.be.false; + } ); + + it( 'should change selection attribute and store it if selection is collapsed in empty parent', () => { + setData( model, '

abc<$text language="fr:ltr">foobarxyz

[]

' ); + + expect( command.value ).to.be.false; + + command.execute( { languageCode: 'ar', textDirection: 'rtl' } ); + + expect( command.value ).to.eql( 'ar:rtl' ); + expect( doc.selection.getAttribute( 'language' ) ).to.eql( 'ar:rtl' ); + + // Attribute should be stored. + // Simulate clicking somewhere else in the editor. + model.change( writer => { + writer.setSelection( root.getNodeByPath( [ 0 ] ), 2 ); + } ); + + expect( command.value ).to.be.false; + + // Go back to where attribute was stored. + model.change( writer => { + writer.setSelection( root.getNodeByPath( [ 1 ] ), 0 ); + } ); + + // Attribute should be restored. + expect( command.value ).to.eql( 'ar:rtl' ); + + command.execute( { languageCode: false } ); + + expect( command.value ).to.be.false; + expect( doc.selection.hasAttribute( 'language' ) ).to.be.false; + } ); + + it( 'should force language text direction if textDirection was set', () => { + setData( model, '

x[]y

' ); + + command.execute( { languageCode: 'ar', textDirection: 'ltr' } ); + + expect( command.value ).to.eql( 'ar:ltr' ); + expect( doc.selection.getAttribute( 'language' ) ).to.eql( 'ar:ltr' ); + } ); + + it( 'should detect language text direction if textDirection was not set', () => { + setData( model, '

x[]y

' ); + + command.execute( { languageCode: 'ar' } ); + + expect( command.value ).to.eql( 'ar:rtl' ); + expect( doc.selection.getAttribute( 'language' ) ).to.eql( 'ar:rtl' ); + } ); + + describe( 'model change event', () => { + let spy; + + beforeEach( () => { + spy = sinon.spy(); + } ); + + describe( 'should be fired when execute parameter was set to language', () => { + it( 'collapsed selection in non-empty parent', () => { + setData( model, '

x[]y

' ); + + model.document.on( 'change', spy ); + + command.execute( { languageCode: 'fr' } ); + + expect( spy.called ).to.be.true; + } ); + + it( 'non-collapsed selection', () => { + setData( model, '

[xy]

' ); + + model.document.on( 'change', spy ); + + command.execute( { languageCode: 'fr' } ); + + expect( spy.called ).to.be.true; + } ); + + it( 'in empty parent', () => { + setData( model, '

[]

' ); + + model.document.on( 'change', spy ); + + command.execute( { languageCode: 'fr' } ); + + expect( spy.called ).to.be.true; + } ); + } ); + + describe( 'should not be fired when execute parameter was set to false', () => { + it( 'collapsed selection in non-empty parent', () => { + setData( model, '

x[]y

' ); + + model.document.on( 'change', spy ); + + command.execute( { languageCode: false } ); + + expect( spy.called ).to.be.false; + } ); + + it( 'non-collapsed selection', () => { + setData( model, '

[xy]

' ); + + model.document.on( 'change', spy ); + + command.execute( { languageCode: false } ); + + expect( spy.called ).to.be.false; + } ); + + it( 'in empty parent', () => { + setData( model, '

[]

' ); + + model.document.on( 'change', spy ); + + command.execute( { languageCode: false } ); + + expect( spy.called ).to.be.false; + } ); + } ); + } ); + } ); +} ); diff --git a/packages/ckeditor5-language/tests/languageediting.js b/packages/ckeditor5-language/tests/languageediting.js new file mode 100644 index 00000000000..18a1067bc19 --- /dev/null +++ b/packages/ckeditor5-language/tests/languageediting.js @@ -0,0 +1,103 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; +import LanguageEditing from '../src/languageediting'; +import LanguageCommand from '../src/languagecommand'; +import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor'; +import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; +import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view'; + +describe( 'LanguageEditing', () => { + let editor, model; + + beforeEach( () => { + return VirtualTestEditor + .create( { + plugins: [ LanguageEditing, Paragraph ] + } ) + .then( newEditor => { + editor = newEditor; + model = editor.model; + } ); + } ); + + it( 'should have pluginName', () => { + expect( LanguageEditing.pluginName ).to.equal( 'LanguageEditing' ); + } ); + + it( 'should be loaded', () => { + expect( editor.plugins.get( LanguageEditing ) ).to.be.instanceOf( LanguageEditing ); + } ); + + it( 'should set proper schema rules', () => { + expect( model.schema.checkAttribute( [ '$root', '$block', '$text' ], 'language' ) ).to.be.true; + expect( model.schema.checkAttribute( [ '$clipboardHolder', '$text' ], 'language' ) ).to.be.true; + } ); + + it( 'its attribute is marked with a copOnEnter property', () => { + expect( model.schema.getAttributeProperties( 'language' ) ).to.include( { + copyOnEnter: true + } ); + } ); + + describe( 'command', () => { + it( 'should register language command', () => { + const command = editor.commands.get( 'language' ); + + expect( command ).to.be.instanceOf( LanguageCommand ); + expect( command ).to.have.property( 'attributeKey', 'language' ); + } ); + } ); + + describe( 'data pipeline conversions', () => { + it( 'should convert lang to language attribute', () => { + editor.setData( '

foobar

' ); + + expect( getModelData( model, { withoutSelection: true } ) ) + .to.equal( '<$text language="fr:ltr">foobar' ); + + expect( editor.getData() ).to.equal( '

foobar

' ); + } ); + + it( 'should respect dir attribute', () => { + editor.setData( '

foobar

' ); + + expect( getModelData( model, { withoutSelection: true } ) ) + .to.equal( '<$text language="fr:rtl">foobar' ); + + expect( editor.getData() ).to.equal( '

foobar

' ); + } ); + + it( 'should be integrated with autoparagraphing', () => { + editor.setData( 'foobar' ); + + expect( getModelData( model, { withoutSelection: true } ) ) + .to.equal( '<$text language="fr:ltr">foobar' ); + + expect( editor.getData() ).to.equal( '

foobar

' ); + } ); + } ); + + describe( 'editing pipeline conversion', () => { + it( 'should convert attribute', () => { + setModelData( model, '<$text language="fr:ltr">foobar' ); + + expect( getViewData( editor.editing.view, { withoutSelection: true } ) ) + .to.equal( '

foobar

' ); + } ); + } ); + + describe( 'config', () => { + it( 'should be set', () => { + expect( editor.config.get( 'languageList.options' ) ).to.deep.equal( [ + { title: 'Arabic', class: 'ck-language_ar', languageCode: 'ar' }, + { title: 'French', class: 'ck-language_fr', languageCode: 'fr' }, + { title: 'Spanish', class: 'ck-language_es', languageCode: 'es' } + ] ); + } ); + } ); +} ); + diff --git a/packages/ckeditor5-language/tests/languageui.js b/packages/ckeditor5-language/tests/languageui.js new file mode 100644 index 00000000000..43a0c527b38 --- /dev/null +++ b/packages/ckeditor5-language/tests/languageui.js @@ -0,0 +1,261 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/* globals document */ + +import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; +import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; +import LanguageEditing from '../src/languageediting'; +import LanguageUI from '../src/languageui'; +import DropdownView from '@ckeditor/ckeditor5-ui/src/dropdown/dropdownview'; +import { add as addTranslations, _clear as clearTranslations } from '@ckeditor/ckeditor5-utils/src/translation-service'; +import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; +import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; + +describe( 'LanguageUI', () => { + let editor, editorElement, dropdown; + + testUtils.createSinonSandbox(); + + beforeEach( () => { + editorElement = document.createElement( 'div' ); + document.body.appendChild( editorElement ); + + return ClassicTestEditor + .create( editorElement, { + plugins: [ LanguageUI, LanguageEditing, Paragraph ], + toolbar: [ 'language' ] + } ) + .then( newEditor => { + editor = newEditor; + dropdown = editor.ui.componentFactory.create( 'language' ); + + // Set data so the commands will be enabled. + setData( editor.model, '[foo]' ); + } ); + } ); + + afterEach( () => { + editorElement.remove(); + + return editor.destroy(); + } ); + + describe( 'init()', () => { + it( 'should register options feature component', () => { + const dropdown = editor.ui.componentFactory.create( 'language' ); + + expect( dropdown ).to.be.instanceOf( DropdownView ); + expect( dropdown.buttonView.isEnabled ).to.be.true; + expect( dropdown.buttonView.isOn ).to.be.false; + expect( dropdown.buttonView.label ).to.equal( 'Choose language' ); + expect( dropdown.buttonView.tooltip ).to.equal( 'Language' ); + } ); + + it( 'should execute language command on model (no language selected)', () => { + const executeSpy = testUtils.sinon.spy( editor, 'execute' ); + const dropdown = editor.ui.componentFactory.create( 'language' ); + + dropdown.fire( 'execute' ); + + sinon.assert.calledOnce( executeSpy ); + sinon.assert.calledWithExactly( executeSpy, 'language', + { languageCode: undefined, textDirection: undefined } ); + } ); + + it( 'should execute language command on model (language selected)', () => { + const executeSpy = testUtils.sinon.spy( editor, 'execute' ); + const dropdown = editor.ui.componentFactory.create( 'language' ); + + dropdown.languageCode = 'fr'; + dropdown.textDirection = 'ltr'; + dropdown.fire( 'execute' ); + + sinon.assert.calledOnce( executeSpy ); + sinon.assert.calledWithExactly( executeSpy, 'language', + { languageCode: 'fr', textDirection: 'ltr' } ); + } ); + + it( 'should focus view after command execution', () => { + const focusSpy = testUtils.sinon.spy( editor.editing.view, 'focus' ); + const dropdown = editor.ui.componentFactory.create( 'language' ); + + dropdown.languageCode = 'fr'; + dropdown.fire( 'execute' ); + + sinon.assert.calledOnce( focusSpy ); + } ); + + it( 'should add custom CSS class to dropdown', () => { + const dropdown = editor.ui.componentFactory.create( 'language' ); + + dropdown.render(); + + expect( dropdown.element.classList.contains( 'ck-language-dropdown' ) ).to.be.true; + } ); + + describe( 'model to command binding', () => { + let command; + + beforeEach( () => { + command = editor.commands.get( 'language' ); + } ); + + it( 'isEnabled', () => { + command.isEnabled = false; + + expect( dropdown.buttonView.isEnabled ).to.be.false; + + command.isEnabled = true; + expect( dropdown.buttonView.isEnabled ).to.be.true; + + command.isEnabled = false; + expect( dropdown.buttonView.isEnabled ).to.be.false; + } ); + + it( 'label', () => { + command.value = false; + + expect( dropdown.buttonView.label ).to.equal( 'Choose language' ); + + command.value = 'fr:ltr'; + expect( dropdown.buttonView.label ).to.equal( 'French' ); + + command.value = 'ar:rtl'; + expect( dropdown.buttonView.label ).to.equal( 'Arabic' ); + } ); + } ); + + describe( 'localization', () => { + let command, editor, dropdown; + + before( () => { + addTranslations( 'en', { + 'Choose language': 'Choose language', + 'Language': 'Language', + 'Hebrew': 'Hebrew', + 'Polish': 'Polish', + 'Remove language': 'Remove language' + } ); + + addTranslations( 'pl', { + 'Choose language': 'Wybierz język', + 'Language': 'Język', + 'Hebrew': 'Hebrajski', + 'Polish': 'Polski', + 'Remove language': 'Usuń język' + } ); + } ); + + after( () => { + clearTranslations(); + } ); + + beforeEach( () => { + return localizedEditor( [ + { title: 'Hebrew', languageCode: 'he' }, + { title: 'Polish', languageCode: 'pl' } + ] ); + } ); + + it( 'does not alter the original config', () => { + expect( editor.config.get( 'languageList.options' ) ).to.deep.equal( [ + { title: 'Hebrew', languageCode: 'he' }, + { title: 'Polish', languageCode: 'pl' } + ] ); + } ); + + it( 'works for the #buttonView', () => { + const buttonView = dropdown.buttonView; + + expect( buttonView.label ).to.equal( 'Wybierz język' ); + expect( buttonView.tooltip ).to.equal( 'Język' ); + + command.value = 'he:rtl'; + expect( buttonView.label ).to.equal( 'Hebrajski' ); + } ); + + it( 'works for the listView#items in the panel', () => { + const listView = dropdown.listView; + + expect( getListViewItems( listView ).map( item => item.children.first.label ) ).to.deep.equal( [ + 'Hebrajski', + 'Polski', + 'Usuń język' + ] ); + } ); + + it( 'allows custom titles', () => { + return localizedEditor( [ + { title: 'He', languageCode: 'he' }, + { title: 'Pl', languageCode: 'pl' } + ] ).then( () => { + const listView = dropdown.listView; + + expect( getListViewItems( listView ).map( item => item.children.first.label ) ).to.deep.equal( [ + 'He', + 'Pl', + 'Usuń język' + ] ); + } ); + } ); + + function localizedEditor( options ) { + const editorElement = document.createElement( 'div' ); + document.body.appendChild( editorElement ); + + return ClassicTestEditor + .create( editorElement, { + plugins: [ LanguageEditing, LanguageUI ], + toolbar: [ 'language' ], + language: 'pl', + languageList: { + options + } + } ) + .then( newEditor => { + editor = newEditor; + dropdown = editor.ui.componentFactory.create( 'language' ); + command = editor.commands.get( 'language' ); + + editorElement.remove(); + + return editor.destroy(); + } ); + } + } ); + + describe( 'class', () => { + it( 'is set for the listView#items in the panel', () => { + const listView = dropdown.listView; + + expect( getListViewItems( listView ).map( item => item.children.first.class ) ).to.deep.equal( [ + 'ck-language_ar', + 'ck-language_fr', + 'ck-language_es', + 'ck-language_remove' + ] ); + } ); + + it( 'reflects the #value of the commands', () => { + const listView = dropdown.listView; + + setData( editor.model, '[<$text language="fr:ltr">te]xt' ); + + expect( getListViewItems( listView ).map( item => item.children.first.isOn ) ).to.deep.equal( [ + false, + true, + false, + false + ] ); + } ); + } ); + } ); +} ); + +function getListViewItems( listView ) { + // Let's drop separator. + return listView.items.filter( item => item.children ); +} From c7a6a2816c072b9d425c6176c82bc2d0570d6043 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Fri, 19 Feb 2021 14:26:53 +0100 Subject: [PATCH 04/36] Updated manual test with test steps. --- .../tests/manual/language.html | 26 ++++++++++++++++++- .../tests/manual/language.md | 9 ++++++- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/packages/ckeditor5-language/tests/manual/language.html b/packages/ckeditor5-language/tests/manual/language.html index 7e990c0469c..542973d48f9 100644 --- a/packages/ckeditor5-language/tests/manual/language.html +++ b/packages/ckeditor5-language/tests/manual/language.html @@ -1,3 +1,27 @@
-

Hello, world!

+

+ Language is the human ability to acquire and use complex systems of communication, + and a language is any specific example of such a system. The scientific study of language + is called linguistics. +

+

+ + Un lenguaje (del provenzal lenguatge y este del latín lingua) es un sistema de comunicación + estructurado para el que existe un contexto de uso y ciertos principios combinatorios formales. Existen + contextos tanto naturales como artificiales. + +

+

+ + اللغة نسق من الإشارات والرموز، يشكل أداة من أدوات المعرفة، وتعتبر اللغة أهم وسائل التفاهم + والاحتكاك بين أفراد امجتمع في جميع ميادين الحياة. وبدون اللغة يتعذر نشاط الناس المعرفي. + +

+

+ + La langue est la capacité humaine à acquérir et à utiliser des systèmes complexes de communication, + et une langue est un exemple spécifique d'un tel système. L'étude scientifique de la langue + s'appelle la linguistique. + +

diff --git a/packages/ckeditor5-language/tests/manual/language.md b/packages/ckeditor5-language/tests/manual/language.md index a2e69359bab..d3db58cdd15 100644 --- a/packages/ckeditor5-language/tests/manual/language.md +++ b/packages/ckeditor5-language/tests/manual/language.md @@ -1 +1,8 @@ -## Language +## Language feature + +1. The data should be loaded with four paragraph. Each paragraph style with applied language should be italic. +2. Put selection in each paragraph and check if language dropdown label is changing properly. +3. Play with languages: + * Change language of the text selection. + * Put selection that spans across multiple blocks and switch languages. + * Remove language from selection. From 67575c360a5897a4ad376be6330ec0ff7816bf60 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 23 Feb 2021 08:39:18 +0100 Subject: [PATCH 05/36] Added missing language utils tests. --- packages/ckeditor5-utils/tests/language.js | 32 ++++++++++++++++++++++ 1 file changed, 32 insertions(+) create mode 100644 packages/ckeditor5-utils/tests/language.js diff --git a/packages/ckeditor5-utils/tests/language.js b/packages/ckeditor5-utils/tests/language.js new file mode 100644 index 00000000000..820057301dc --- /dev/null +++ b/packages/ckeditor5-utils/tests/language.js @@ -0,0 +1,32 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +import { getLanguageDirection } from '../src/language'; + +describe( 'language', () => { + describe( 'getLanguageDirection', () => { + it( 'determines the language direction', () => { + expect( getLanguageDirection( 'en' ) ).to.eql( 'ltr' ); + expect( getLanguageDirection( 'pl' ) ).to.eql( 'ltr' ); + expect( getLanguageDirection( 'fr' ) ).to.eql( 'ltr' ); + + expect( getLanguageDirection( 'ar' ) ).to.eql( 'rtl' ); + expect( getLanguageDirection( 'ara' ) ).to.eql( 'rtl' ); + + expect( getLanguageDirection( 'fa' ) ).to.eql( 'rtl' ); + expect( getLanguageDirection( 'per' ) ).to.eql( 'rtl' ); + expect( getLanguageDirection( 'fas' ) ).to.eql( 'rtl' ); + + expect( getLanguageDirection( 'he' ) ).to.eql( 'rtl' ); + expect( getLanguageDirection( 'heb' ) ).to.eql( 'rtl' ); + + expect( getLanguageDirection( 'ku' ) ).to.eql( 'rtl' ); + expect( getLanguageDirection( 'kur' ) ).to.eql( 'rtl' ); + + expect( getLanguageDirection( 'ug' ) ).to.eql( 'rtl' ); + expect( getLanguageDirection( 'uig' ) ).to.eql( 'rtl' ); + } ); + } ); +} ); From 8fe21fd9018dfe070f3df25a8efc412a686d7595 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 23 Feb 2021 08:51:23 +0100 Subject: [PATCH 06/36] Removed some copy&paste. --- packages/ckeditor5-language/CHANGELOG.md | 6 ------ 1 file changed, 6 deletions(-) delete mode 100644 packages/ckeditor5-language/CHANGELOG.md diff --git a/packages/ckeditor5-language/CHANGELOG.md b/packages/ckeditor5-language/CHANGELOG.md deleted file mode 100644 index ec963d04c7d..00000000000 --- a/packages/ckeditor5-language/CHANGELOG.md +++ /dev/null @@ -1,6 +0,0 @@ -Changelog -========= - -All changes in the package are documented in the main repository. See: https://github.com/ckeditor/ckeditor5/blob/master/CHANGELOG.md. - -Changes for the past releases are available below. From 06ff434951e65fd298d553321943d466b9c61617 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20Bogda=C5=84ski?= Date: Tue, 23 Feb 2021 09:09:52 +0100 Subject: [PATCH 07/36] Update packages/ckeditor5-language/LICENSE.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Piotrek Koszuliński --- packages/ckeditor5-language/LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ckeditor5-language/LICENSE.md b/packages/ckeditor5-language/LICENSE.md index a28e789437a..89e7a37ef1f 100644 --- a/packages/ckeditor5-language/LICENSE.md +++ b/packages/ckeditor5-language/LICENSE.md @@ -1,7 +1,7 @@ Software License Agreement ========================== -**CKEditor 5 Language Feature** – https://github.com/ckeditor/ckeditor5-language
+**CKEditor 5 Language feature** – https://github.com/ckeditor/ckeditor5-language
Copyright (c) 2003-2021, [CKSource](http://cksource.com) Frederico Knabben. All rights reserved. Licensed under the terms of [GNU General Public License Version 2 or later](http://www.gnu.org/licenses/gpl.html). From 74049b9ecd46faeebf22649685e104d943e471d4 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 23 Feb 2021 09:11:36 +0100 Subject: [PATCH 08/36] Corrected references. --- packages/ckeditor5-language/package.json | 2 +- packages/ckeditor5-language/src/languageediting.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ckeditor5-language/package.json b/packages/ckeditor5-language/package.json index 3ae76cd8a7f..2cf76f7968e 100644 --- a/packages/ckeditor5-language/package.json +++ b/packages/ckeditor5-language/package.json @@ -1,7 +1,7 @@ { "name": "@ckeditor/ckeditor5-language", "version": "25.0.0", - "description": "Block quote feature for CKEditor 5.", + "description": "Language feature for CKEditor 5.", "keywords": [ "ckeditor", "ckeditor5", diff --git a/packages/ckeditor5-language/src/languageediting.js b/packages/ckeditor5-language/src/languageediting.js index 343e529a93c..e34c7bc34f9 100644 --- a/packages/ckeditor5-language/src/languageediting.js +++ b/packages/ckeditor5-language/src/languageediting.js @@ -4,7 +4,7 @@ */ /** - * @module block-quote/languageediting + * @module language/languageediting */ import { Plugin } from 'ckeditor5/src/core'; From 414511b2335a8a76b84df852eefda3e071ed8ff5 Mon Sep 17 00:00:00 2001 From: Kuba Niegowski Date: Fri, 26 Feb 2021 16:25:02 +0100 Subject: [PATCH 09/36] Fixed DLL import. --- packages/ckeditor5-language/package.json | 4 ++-- packages/ckeditor5-language/src/utils.js | 2 +- packages/ckeditor5-utils/src/index.js | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/ckeditor5-language/package.json b/packages/ckeditor5-language/package.json index 2cf76f7968e..31fbade18ec 100644 --- a/packages/ckeditor5-language/package.json +++ b/packages/ckeditor5-language/package.json @@ -11,8 +11,7 @@ ], "main": "src/index.js", "dependencies": { - "ckeditor5": "^25.0.0", - "@ckeditor/ckeditor5-utils": "^25.0.0" + "ckeditor5": "^25.0.0" }, "devDependencies": { "@ckeditor/ckeditor5-core": "^25.0.0", @@ -22,6 +21,7 @@ "@ckeditor/ckeditor5-paragraph": "^25.0.0", "@ckeditor/ckeditor5-theme-lark": "^25.0.0", "@ckeditor/ckeditor5-ui": "^25.0.0", + "@ckeditor/ckeditor5-utils": "^25.0.0", "webpack": "^4.43.0", "webpack-cli": "^3.3.11" }, diff --git a/packages/ckeditor5-language/src/utils.js b/packages/ckeditor5-language/src/utils.js index 15548c9cbfc..a081229e308 100644 --- a/packages/ckeditor5-language/src/utils.js +++ b/packages/ckeditor5-language/src/utils.js @@ -7,7 +7,7 @@ * @module language/utils */ -import { getLanguageDirection } from '@ckeditor/ckeditor5-utils/src/language'; +import { getLanguageDirection } from 'ckeditor5/src/utils'; /** * Returns language attribute value in a human-readable text format: diff --git a/packages/ckeditor5-utils/src/index.js b/packages/ckeditor5-utils/src/index.js index 13b48fccb05..7b635e11d87 100644 --- a/packages/ckeditor5-utils/src/index.js +++ b/packages/ckeditor5-utils/src/index.js @@ -28,6 +28,7 @@ export { default as setDataInElement } from './dom/setdatainelement'; export { default as toUnit } from './dom/tounit'; export * from './keyboard'; +export * from './language'; export { default as Locale } from './locale'; export { default as Collection } from './collection'; export { default as first } from './first'; From f90c5ff63f67e2d9dbf904d44d63c8252ab2cd0a Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Mon, 1 Mar 2021 12:47:57 +0100 Subject: [PATCH 10/36] Corrected tests. --- packages/ckeditor5-utils/tests/language.js | 42 +++++++++++++--------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/packages/ckeditor5-utils/tests/language.js b/packages/ckeditor5-utils/tests/language.js index 820057301dc..e7433864e05 100644 --- a/packages/ckeditor5-utils/tests/language.js +++ b/packages/ckeditor5-utils/tests/language.js @@ -6,27 +6,37 @@ import { getLanguageDirection } from '../src/language'; describe( 'language', () => { - describe( 'getLanguageDirection', () => { - it( 'determines the language direction', () => { - expect( getLanguageDirection( 'en' ) ).to.eql( 'ltr' ); - expect( getLanguageDirection( 'pl' ) ).to.eql( 'ltr' ); - expect( getLanguageDirection( 'fr' ) ).to.eql( 'ltr' ); + describe( 'getLanguageDirection()', () => { + [ + // Common LTR languages. + { code: 'en', textDirection: 'ltr' }, + { code: 'pl', textDirection: 'ltr' }, + { code: 'fr', textDirection: 'ltr' }, - expect( getLanguageDirection( 'ar' ) ).to.eql( 'rtl' ); - expect( getLanguageDirection( 'ara' ) ).to.eql( 'rtl' ); + // Arabic + { code: 'ar', textDirection: 'rtl' }, + { code: 'ara', textDirection: 'rtl' }, - expect( getLanguageDirection( 'fa' ) ).to.eql( 'rtl' ); - expect( getLanguageDirection( 'per' ) ).to.eql( 'rtl' ); - expect( getLanguageDirection( 'fas' ) ).to.eql( 'rtl' ); + // Persian + { code: 'fa', textDirection: 'rtl' }, + { code: 'per', textDirection: 'rtl' }, + { code: 'fas', textDirection: 'rtl' }, - expect( getLanguageDirection( 'he' ) ).to.eql( 'rtl' ); - expect( getLanguageDirection( 'heb' ) ).to.eql( 'rtl' ); + // Hebrew + { code: 'he', textDirection: 'rtl' }, + { code: 'heb', textDirection: 'rtl' }, - expect( getLanguageDirection( 'ku' ) ).to.eql( 'rtl' ); - expect( getLanguageDirection( 'kur' ) ).to.eql( 'rtl' ); + // Kurdish + { code: 'ku', textDirection: 'rtl' }, + { code: 'kur', textDirection: 'rtl' }, - expect( getLanguageDirection( 'ug' ) ).to.eql( 'rtl' ); - expect( getLanguageDirection( 'uig' ) ).to.eql( 'rtl' ); + // Uighur, Uyghur + { code: 'ug', textDirection: 'rtl' }, + { code: 'uig', textDirection: 'rtl' } + ].forEach( ( { code, textDirection } ) => { + it( `determines the "${ code }" language direction`, () => { + expect( getLanguageDirection( code ) ).to.equal( textDirection ); + } ); } ); } ); } ); From f1116f120541b33a7bd4d36905350a0f7eba19a1 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Mon, 1 Mar 2021 12:54:03 +0100 Subject: [PATCH 11/36] Removed class binding. --- packages/ckeditor5-language/src/language.js | 9 ++--- .../ckeditor5-language/src/languageediting.js | 6 +-- packages/ckeditor5-language/src/languageui.js | 2 - .../tests/languageediting.js | 6 +-- .../ckeditor5-language/tests/languageui.js | 39 +++++++------------ 5 files changed, 23 insertions(+), 39 deletions(-) diff --git a/packages/ckeditor5-language/src/language.js b/packages/ckeditor5-language/src/language.js index ed2455c3888..a0115016c60 100644 --- a/packages/ckeditor5-language/src/language.js +++ b/packages/ckeditor5-language/src/language.js @@ -69,13 +69,13 @@ export default class Language extends Plugin { * * const languageConfig = { * options: [ - * { title: 'Arabic', class: 'ck-language_ar', languageCode: 'ar' }, - * { title: 'French', class: 'ck-language_fr', languageCode: 'fr' }, - * { title: 'Spanish', class: 'ck-language_es', languageCode: 'es' } + * { title: 'Arabic', languageCode: 'ar' }, + * { title: 'French', languageCode: 'fr' }, + * { title: 'Spanish', languageCode: 'es' } * ] * }; * - * The `title` and `class` properties will be used by the `language` dropdown to render available options. + * The `title` property will be used by the `language` dropdown to render available options. * * The `languageCode` property is used for the lang attribute in ISO 639 format. Language codes can be found * [here](http://www.loc.gov/standards/iso639-2/php/English_list.php). You can use both 2-letter ISO-639-1 codes @@ -93,7 +93,6 @@ export default class Language extends Plugin { * * @typedef {Object} module:language/language~LanguageOption * @property {String} title The user-readable title of the option. - * @property {String} class The class which will be added to the dropdown item representing this option. * @property {String} languageCode The language code in ISO 639 format. * @property {Strint} [textDirection] Language text direction. Automatically detected if omitted. * @extends module:engine/conversion/conversion~ConverterDefinition diff --git a/packages/ckeditor5-language/src/languageediting.js b/packages/ckeditor5-language/src/languageediting.js index e34c7bc34f9..7a0ec8e0de5 100644 --- a/packages/ckeditor5-language/src/languageediting.js +++ b/packages/ckeditor5-language/src/languageediting.js @@ -36,9 +36,9 @@ export default class LanguageEditing extends Plugin { editor.config.define( 'languageList', { options: [ - { title: 'Arabic', class: 'ck-language_ar', languageCode: 'ar' }, - { title: 'French', class: 'ck-language_fr', languageCode: 'fr' }, - { title: 'Spanish', class: 'ck-language_es', languageCode: 'es' } + { title: 'Arabic', languageCode: 'ar' }, + { title: 'French', languageCode: 'fr' }, + { title: 'Spanish', languageCode: 'es' } ] } ); } diff --git a/packages/ckeditor5-language/src/languageui.js b/packages/ckeditor5-language/src/languageui.js index b3ddba223c7..94a3d2cc615 100644 --- a/packages/ckeditor5-language/src/languageui.js +++ b/packages/ckeditor5-language/src/languageui.js @@ -52,7 +52,6 @@ export default class LanguageUI extends Plugin { type: 'button', model: new Model( { label: option.title, - class: option.class, languageCode: option.languageCode, textDirection: option.textDirection, withText: true @@ -77,7 +76,6 @@ export default class LanguageUI extends Plugin { type: 'button', model: new Model( { label: removeTitle, - class: 'ck-language_remove', languageCode: false, withText: true } ) diff --git a/packages/ckeditor5-language/tests/languageediting.js b/packages/ckeditor5-language/tests/languageediting.js index 18a1067bc19..3ecca34143e 100644 --- a/packages/ckeditor5-language/tests/languageediting.js +++ b/packages/ckeditor5-language/tests/languageediting.js @@ -93,9 +93,9 @@ describe( 'LanguageEditing', () => { describe( 'config', () => { it( 'should be set', () => { expect( editor.config.get( 'languageList.options' ) ).to.deep.equal( [ - { title: 'Arabic', class: 'ck-language_ar', languageCode: 'ar' }, - { title: 'French', class: 'ck-language_fr', languageCode: 'fr' }, - { title: 'Spanish', class: 'ck-language_es', languageCode: 'es' } + { title: 'Arabic', languageCode: 'ar' }, + { title: 'French', languageCode: 'fr' }, + { title: 'Spanish', languageCode: 'es' } ] ); } ); } ); diff --git a/packages/ckeditor5-language/tests/languageui.js b/packages/ckeditor5-language/tests/languageui.js index 43a0c527b38..2a53706bda6 100644 --- a/packages/ckeditor5-language/tests/languageui.js +++ b/packages/ckeditor5-language/tests/languageui.js @@ -126,6 +126,19 @@ describe( 'LanguageUI', () => { command.value = 'ar:rtl'; expect( dropdown.buttonView.label ).to.equal( 'Arabic' ); } ); + + it( 'reflects the #value of the command', () => { + const listView = dropdown.listView; + + setData( editor.model, '[<$text language="fr:ltr">te]xt' ); + + expect( getListViewItems( listView ).map( item => item.children.first.isOn ) ).to.deep.equal( [ + false, + true, + false, + false + ] ); + } ); } ); describe( 'localization', () => { @@ -226,32 +239,6 @@ describe( 'LanguageUI', () => { } ); } } ); - - describe( 'class', () => { - it( 'is set for the listView#items in the panel', () => { - const listView = dropdown.listView; - - expect( getListViewItems( listView ).map( item => item.children.first.class ) ).to.deep.equal( [ - 'ck-language_ar', - 'ck-language_fr', - 'ck-language_es', - 'ck-language_remove' - ] ); - } ); - - it( 'reflects the #value of the commands', () => { - const listView = dropdown.listView; - - setData( editor.model, '[<$text language="fr:ltr">te]xt' ); - - expect( getListViewItems( listView ).map( item => item.children.first.isOn ) ).to.deep.equal( [ - false, - true, - false, - false - ] ); - } ); - } ); } ); } ); From 3747505e919d6117423285d5089cab20e9c594c1 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Mon, 1 Mar 2021 13:03:47 +0100 Subject: [PATCH 12/36] Inlined attribute key. --- .../ckeditor5-language/src/languagecommand.js | 66 ++++++++----------- .../ckeditor5-language/src/languageediting.js | 2 +- .../tests/languagecommand.js | 2 +- .../tests/languageediting.js | 2 - 4 files changed, 28 insertions(+), 44 deletions(-) diff --git a/packages/ckeditor5-language/src/languagecommand.js b/packages/ckeditor5-language/src/languagecommand.js index a598e05be84..9ab6d2d0a8a 100644 --- a/packages/ckeditor5-language/src/languagecommand.js +++ b/packages/ckeditor5-language/src/languagecommand.js @@ -10,6 +10,8 @@ import { Command } from 'ckeditor5/src/core'; import { parseLanguageToString } from './utils'; +const ATTRIBUTE_KEY = 'language'; + /** * The language command plugin. * @@ -17,38 +19,22 @@ import { parseLanguageToString } from './utils'; */ export default class LanguageCommand extends Command { /** - * @param {module:core/editor/editor~Editor} editor - * @param {String} attributeKey Attribute that will be set by the command. + * If the selection starts in a language attribute the value is set to + * the value of that language in a format: + * + * : + * + * * `languageCode` - The language code used for the lang attribute in ISO 639 format. + * * `textDirection` - One of the following values: `rtl` or `ltr`, indicating the reading direction of the language. + * + * See {@link module:language/language~LanguageConfig language config} for more information about language properties. + * + * It is set to `false` otherwise. + * + * @observable + * @readonly + * @member {Boolean|String} #value */ - constructor( editor, attributeKey ) { - super( editor ); - - /** - * The attribute that will be set by the command. - * - * @readonly - * @member {String} - */ - this.attributeKey = attributeKey; - - /** - * If the selection starts in a language attribute the value is set to - * the value of that language in a format: - * - * : - * - * * `languageCode` - The language code used for the lang attribute in ISO 639 format. - * * `textDirection` - One of the following values: `rtl` or `ltr`, indicating the reading direction of the language. - * - * See {@link module:language/language~LanguageConfig language config} for more information about language properties. - * - * It is set to `false` otherwise. - * - * @observable - * @readonly - * @member {Boolean|String} #value - */ - } /** * @inheritDoc @@ -58,7 +44,7 @@ export default class LanguageCommand extends Command { const doc = model.document; this.value = this._getValueFromFirstAllowedNode(); - this.isEnabled = model.schema.checkAttributeInSelection( doc.selection, this.attributeKey ); + this.isEnabled = model.schema.checkAttributeInSelection( doc.selection, ATTRIBUTE_KEY ); } /** @@ -91,18 +77,18 @@ export default class LanguageCommand extends Command { model.change( writer => { if ( selection.isCollapsed ) { if ( value ) { - writer.setSelectionAttribute( this.attributeKey, value ); + writer.setSelectionAttribute( ATTRIBUTE_KEY, value ); } else { - writer.removeSelectionAttribute( this.attributeKey ); + writer.removeSelectionAttribute( ATTRIBUTE_KEY ); } } else { - const ranges = model.schema.getValidRanges( selection.getRanges(), this.attributeKey ); + const ranges = model.schema.getValidRanges( selection.getRanges(), ATTRIBUTE_KEY ); for ( const range of ranges ) { if ( value ) { - writer.setAttribute( this.attributeKey, value, range ); + writer.setAttribute( ATTRIBUTE_KEY, value, range ); } else { - writer.removeAttribute( this.attributeKey, range ); + writer.removeAttribute( ATTRIBUTE_KEY, range ); } } } @@ -122,13 +108,13 @@ export default class LanguageCommand extends Command { const selection = model.document.selection; if ( selection.isCollapsed ) { - return selection.getAttribute( this.attributeKey ) || false; + return selection.getAttribute( ATTRIBUTE_KEY ) || false; } for ( const range of selection.getRanges() ) { for ( const item of range.getItems() ) { - if ( schema.checkAttribute( item, this.attributeKey ) ) { - return item.getAttribute( this.attributeKey ) || false; + if ( schema.checkAttribute( item, ATTRIBUTE_KEY ) ) { + return item.getAttribute( ATTRIBUTE_KEY ) || false; } } } diff --git a/packages/ckeditor5-language/src/languageediting.js b/packages/ckeditor5-language/src/languageediting.js index 7a0ec8e0de5..c332a26a440 100644 --- a/packages/ckeditor5-language/src/languageediting.js +++ b/packages/ckeditor5-language/src/languageediting.js @@ -56,7 +56,7 @@ export default class LanguageEditing extends Plugin { this._defineConverters(); - editor.commands.add( LANGUAGE, new LanguageCommand( editor, LANGUAGE ) ); + editor.commands.add( LANGUAGE, new LanguageCommand( editor ) ); } /** diff --git a/packages/ckeditor5-language/tests/languagecommand.js b/packages/ckeditor5-language/tests/languagecommand.js index 57daf24e203..563ca71891a 100644 --- a/packages/ckeditor5-language/tests/languagecommand.js +++ b/packages/ckeditor5-language/tests/languagecommand.js @@ -20,7 +20,7 @@ describe( 'LanguageCommand', () => { doc = model.document; root = doc.getRoot(); - command = new LanguageCommand( editor, attrKey ); + command = new LanguageCommand( editor ); model.schema.register( 'p', { inheritAllFrom: '$block' } ); model.schema.register( 'h1', { inheritAllFrom: '$block' } ); diff --git a/packages/ckeditor5-language/tests/languageediting.js b/packages/ckeditor5-language/tests/languageediting.js index 3ecca34143e..3a906bca256 100644 --- a/packages/ckeditor5-language/tests/languageediting.js +++ b/packages/ckeditor5-language/tests/languageediting.js @@ -46,9 +46,7 @@ describe( 'LanguageEditing', () => { describe( 'command', () => { it( 'should register language command', () => { const command = editor.commands.get( 'language' ); - expect( command ).to.be.instanceOf( LanguageCommand ); - expect( command ).to.have.property( 'attributeKey', 'language' ); } ); } ); From 8a420a4e6058c2676fd1defc36866e63a3f0dc45 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Mon, 1 Mar 2021 13:08:11 +0100 Subject: [PATCH 13/36] Renaming. --- packages/ckeditor5-language/src/languagecommand.js | 4 ++-- packages/ckeditor5-language/src/languageediting.js | 6 +++--- packages/ckeditor5-language/src/languageui.js | 4 ++-- packages/ckeditor5-language/src/utils.js | 6 +++--- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/ckeditor5-language/src/languagecommand.js b/packages/ckeditor5-language/src/languagecommand.js index 9ab6d2d0a8a..78a47459544 100644 --- a/packages/ckeditor5-language/src/languagecommand.js +++ b/packages/ckeditor5-language/src/languagecommand.js @@ -8,7 +8,7 @@ */ import { Command } from 'ckeditor5/src/core'; -import { parseLanguageToString } from './utils'; +import { stringifyLanguageAttribute } from './utils'; const ATTRIBUTE_KEY = 'language'; @@ -72,7 +72,7 @@ export default class LanguageCommand extends Command { const doc = model.document; const selection = doc.selection; - const value = languageCode ? parseLanguageToString( languageCode, textDirection ) : false; + const value = languageCode ? stringifyLanguageAttribute( languageCode, textDirection ) : false; model.change( writer => { if ( selection.isCollapsed ) { diff --git a/packages/ckeditor5-language/src/languageediting.js b/packages/ckeditor5-language/src/languageediting.js index c332a26a440..84c0ab7ad81 100644 --- a/packages/ckeditor5-language/src/languageediting.js +++ b/packages/ckeditor5-language/src/languageediting.js @@ -9,7 +9,7 @@ import { Plugin } from 'ckeditor5/src/core'; import LanguageCommand from './languagecommand'; -import { parseLanguageToString, parseLanguageFromString } from './utils'; +import { stringifyLanguageAttribute, parseLanguageAttribute } from './utils'; const LANGUAGE = 'language'; @@ -72,7 +72,7 @@ export default class LanguageEditing extends Plugin { const languageCode = viewElement.getAttribute( 'lang' ); const textDirection = viewElement.getAttribute( 'dir' ); - return parseLanguageToString( languageCode, textDirection ); + return stringifyLanguageAttribute( languageCode, textDirection ); } }, view: { @@ -88,7 +88,7 @@ export default class LanguageEditing extends Plugin { return; } - const { languageCode, textDirection } = parseLanguageFromString( attributeValue ); + const { languageCode, textDirection } = parseLanguageAttribute( attributeValue ); return writer.createAttributeElement( 'span', { lang: languageCode, diff --git a/packages/ckeditor5-language/src/languageui.js b/packages/ckeditor5-language/src/languageui.js index 94a3d2cc615..d0902be388f 100644 --- a/packages/ckeditor5-language/src/languageui.js +++ b/packages/ckeditor5-language/src/languageui.js @@ -10,7 +10,7 @@ import { Plugin } from 'ckeditor5/src/core'; import { Model, createDropdown, addListToDropdown } from 'ckeditor5/src/ui'; import { Collection } from 'ckeditor5/src/utils'; -import { parseLanguageToString, getLocalizedOptions } from './utils'; +import { stringifyLanguageAttribute, getLocalizedOptions } from './utils'; import '../theme/language.css'; @@ -58,7 +58,7 @@ export default class LanguageUI extends Plugin { } ) }; - const language = parseLanguageToString( option.languageCode, option.textDirection ); + const language = stringifyLanguageAttribute( option.languageCode, option.textDirection ); def.model.bind( 'isOn' ).to( languageCommand, 'value', value => value === language ); diff --git a/packages/ckeditor5-language/src/utils.js b/packages/ckeditor5-language/src/utils.js index a081229e308..4e8424daa5b 100644 --- a/packages/ckeditor5-language/src/utils.js +++ b/packages/ckeditor5-language/src/utils.js @@ -24,21 +24,21 @@ import { getLanguageDirection } from 'ckeditor5/src/utils'; * @param {String} languageCode The language code in ISO 639 format. * @param {String} [textDirection] Language text direction. Automatically detected if omitted. */ -export function parseLanguageToString( languageCode, textDirection ) { +export function stringifyLanguageAttribute( languageCode, textDirection ) { textDirection = textDirection || getLanguageDirection( languageCode ); return `${ languageCode }:${ textDirection }`; } /** * Retrieves language properties converted to attribute value by - * {@link module:language/utils~parseLanguageToString parseLanguageToString} function. + * {@link module:language/utils~stringifyLanguageAttribute stringifyLanguageAttribute} function. * * @param {String} str Attribute value. * @returns result * @returns result.languageCode The language code in ISO 639 format. * @returns result.textDirection Language text direction. */ -export function parseLanguageFromString( str ) { +export function parseLanguageAttribute( str ) { const parts = str.split( ':' ); return { languageCode: parts[ 0 ], textDirection: parts[ 1 ] }; } From db1304837c9eba0ce9de629b48d1ec5b8349c33c Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Mon, 1 Mar 2021 13:18:40 +0100 Subject: [PATCH 14/36] Removed translations for default options. --- packages/ckeditor5-language/package.json | 1 - .../ckeditor5-language/src/languageediting.js | 3 + packages/ckeditor5-language/src/languageui.js | 4 +- packages/ckeditor5-language/src/utils.js | 20 ---- .../ckeditor5-language/tests/languageui.js | 100 ------------------ 5 files changed, 5 insertions(+), 123 deletions(-) diff --git a/packages/ckeditor5-language/package.json b/packages/ckeditor5-language/package.json index 31fbade18ec..eabb85e6ba2 100644 --- a/packages/ckeditor5-language/package.json +++ b/packages/ckeditor5-language/package.json @@ -21,7 +21,6 @@ "@ckeditor/ckeditor5-paragraph": "^25.0.0", "@ckeditor/ckeditor5-theme-lark": "^25.0.0", "@ckeditor/ckeditor5-ui": "^25.0.0", - "@ckeditor/ckeditor5-utils": "^25.0.0", "webpack": "^4.43.0", "webpack-cli": "^3.3.11" }, diff --git a/packages/ckeditor5-language/src/languageediting.js b/packages/ckeditor5-language/src/languageediting.js index 84c0ab7ad81..eb12e5be705 100644 --- a/packages/ckeditor5-language/src/languageediting.js +++ b/packages/ckeditor5-language/src/languageediting.js @@ -34,6 +34,9 @@ export default class LanguageEditing extends Plugin { constructor( editor ) { super( editor ); + // Language options are only used to ensure that the feature works by default. + // In the real usage it should be reconfigured by a developer. We are not providing + // translations for `title` properties on purpose, as it's only an example configuration. editor.config.define( 'languageList', { options: [ { title: 'Arabic', languageCode: 'ar' }, diff --git a/packages/ckeditor5-language/src/languageui.js b/packages/ckeditor5-language/src/languageui.js index d0902be388f..da54663f2e0 100644 --- a/packages/ckeditor5-language/src/languageui.js +++ b/packages/ckeditor5-language/src/languageui.js @@ -10,7 +10,7 @@ import { Plugin } from 'ckeditor5/src/core'; import { Model, createDropdown, addListToDropdown } from 'ckeditor5/src/ui'; import { Collection } from 'ckeditor5/src/utils'; -import { stringifyLanguageAttribute, getLocalizedOptions } from './utils'; +import { stringifyLanguageAttribute } from './utils'; import '../theme/language.css'; @@ -35,7 +35,7 @@ export default class LanguageUI extends Plugin { init() { const editor = this.editor; const t = editor.t; - const options = getLocalizedOptions( editor ); + const options = editor.config.get( 'languageList.options' ); const defaultTitle = t( 'Choose language' ); const removeTitle = t( 'Remove language' ); const dropdownTooltip = t( 'Language' ); diff --git a/packages/ckeditor5-language/src/utils.js b/packages/ckeditor5-language/src/utils.js index 4e8424daa5b..eb47828a516 100644 --- a/packages/ckeditor5-language/src/utils.js +++ b/packages/ckeditor5-language/src/utils.js @@ -42,23 +42,3 @@ export function parseLanguageAttribute( str ) { const parts = str.split( ':' ); return { languageCode: parts[ 0 ], textDirection: parts[ 1 ] }; } - -/** - * Returns language options as defined in `config.languageList.options` but processed to consider - * the editor localization, i.e. to display {@link module:language/language~LanguageOption} - * in the correct language. - * - * Note: The reason behind this method is that there is no way to use {@link module:utils/locale~Locale#t} - * when the user configuration is defined because the editor does not exist yet. - * - * @param {module:core/editor/editor~Editor} editor - * @returns {Array.}. - */ -export function getLocalizedOptions( editor ) { - const t = editor.t; - - return editor.config.get( 'languageList.options' ).map( option => { - option.title = t( option.title ); - return option; - } ); -} diff --git a/packages/ckeditor5-language/tests/languageui.js b/packages/ckeditor5-language/tests/languageui.js index 2a53706bda6..8b34c0ce670 100644 --- a/packages/ckeditor5-language/tests/languageui.js +++ b/packages/ckeditor5-language/tests/languageui.js @@ -10,7 +10,6 @@ import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; import LanguageEditing from '../src/languageediting'; import LanguageUI from '../src/languageui'; import DropdownView from '@ckeditor/ckeditor5-ui/src/dropdown/dropdownview'; -import { add as addTranslations, _clear as clearTranslations } from '@ckeditor/ckeditor5-utils/src/translation-service'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; @@ -140,105 +139,6 @@ describe( 'LanguageUI', () => { ] ); } ); } ); - - describe( 'localization', () => { - let command, editor, dropdown; - - before( () => { - addTranslations( 'en', { - 'Choose language': 'Choose language', - 'Language': 'Language', - 'Hebrew': 'Hebrew', - 'Polish': 'Polish', - 'Remove language': 'Remove language' - } ); - - addTranslations( 'pl', { - 'Choose language': 'Wybierz język', - 'Language': 'Język', - 'Hebrew': 'Hebrajski', - 'Polish': 'Polski', - 'Remove language': 'Usuń język' - } ); - } ); - - after( () => { - clearTranslations(); - } ); - - beforeEach( () => { - return localizedEditor( [ - { title: 'Hebrew', languageCode: 'he' }, - { title: 'Polish', languageCode: 'pl' } - ] ); - } ); - - it( 'does not alter the original config', () => { - expect( editor.config.get( 'languageList.options' ) ).to.deep.equal( [ - { title: 'Hebrew', languageCode: 'he' }, - { title: 'Polish', languageCode: 'pl' } - ] ); - } ); - - it( 'works for the #buttonView', () => { - const buttonView = dropdown.buttonView; - - expect( buttonView.label ).to.equal( 'Wybierz język' ); - expect( buttonView.tooltip ).to.equal( 'Język' ); - - command.value = 'he:rtl'; - expect( buttonView.label ).to.equal( 'Hebrajski' ); - } ); - - it( 'works for the listView#items in the panel', () => { - const listView = dropdown.listView; - - expect( getListViewItems( listView ).map( item => item.children.first.label ) ).to.deep.equal( [ - 'Hebrajski', - 'Polski', - 'Usuń język' - ] ); - } ); - - it( 'allows custom titles', () => { - return localizedEditor( [ - { title: 'He', languageCode: 'he' }, - { title: 'Pl', languageCode: 'pl' } - ] ).then( () => { - const listView = dropdown.listView; - - expect( getListViewItems( listView ).map( item => item.children.first.label ) ).to.deep.equal( [ - 'He', - 'Pl', - 'Usuń język' - ] ); - } ); - } ); - - function localizedEditor( options ) { - const editorElement = document.createElement( 'div' ); - document.body.appendChild( editorElement ); - - return ClassicTestEditor - .create( editorElement, { - plugins: [ LanguageEditing, LanguageUI ], - toolbar: [ 'language' ], - language: 'pl', - languageList: { - options - } - } ) - .then( newEditor => { - editor = newEditor; - dropdown = editor.ui.componentFactory.create( 'language' ); - command = editor.commands.get( 'language' ); - - editorElement.remove(); - - return editor.destroy(); - } ); - } - } ); } ); } ); From 33a1b5a299a05d63a2d2f1eefc40f1c94d0d4d1c Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 2 Mar 2021 09:00:51 +0100 Subject: [PATCH 15/36] Renaming language to text fragment language. --- packages/ckeditor5-language/src/language.js | 99 ----------------- .../src/textfragmentlanguage.js | 103 ++++++++++++++++++ ...mand.js => textfragmentlanguagecommand.js} | 6 +- ...ting.js => textfragmentlanguageediting.js} | 26 ++--- ...anguageui.js => textfragmentlanguageui.js} | 16 +-- packages/ckeditor5-language/tests/language.js | 18 --- .../tests/textfragmentlanguage.js | 18 +++ ...mand.js => textfragmentlanguagecommand.js} | 6 +- ...ting.js => textfragmentlanguageediting.js} | 18 +-- ...anguageui.js => textfragmentlanguageui.js} | 34 +++--- 10 files changed, 174 insertions(+), 170 deletions(-) delete mode 100644 packages/ckeditor5-language/src/language.js create mode 100644 packages/ckeditor5-language/src/textfragmentlanguage.js rename packages/ckeditor5-language/src/{languagecommand.js => textfragmentlanguagecommand.js} (96%) rename packages/ckeditor5-language/src/{languageediting.js => textfragmentlanguageediting.js} (70%) rename packages/ckeditor5-language/src/{languageui.js => textfragmentlanguageui.js} (86%) delete mode 100644 packages/ckeditor5-language/tests/language.js create mode 100644 packages/ckeditor5-language/tests/textfragmentlanguage.js rename packages/ckeditor5-language/tests/{languagecommand.js => textfragmentlanguagecommand.js} (98%) rename packages/ckeditor5-language/tests/{languageediting.js => textfragmentlanguageediting.js} (82%) rename packages/ckeditor5-language/tests/{languageui.js => textfragmentlanguageui.js} (73%) diff --git a/packages/ckeditor5-language/src/language.js b/packages/ckeditor5-language/src/language.js deleted file mode 100644 index a0115016c60..00000000000 --- a/packages/ckeditor5-language/src/language.js +++ /dev/null @@ -1,99 +0,0 @@ -/** - * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - -/** - * @module language/language - */ - -import { Plugin } from 'ckeditor5/src/core'; - -import LanguageEditing from './languageediting'; -import LanguageUI from './languageui'; - -/** - * The language plugin. - * - * For more information about this feature check the {@glink api/language package page}. - * - * This is a "glue" plugin which loads the {@link module:language/languageediting~LanguageEditing language editing feature} - * and {@link module:language/languageui~LanguageUI language UI feature}. - * - * @extends module:core/plugin~Plugin - */ -export default class Language extends Plugin { - /** - * @inheritDoc - */ - static get requires() { - return [ LanguageEditing, LanguageUI ]; - } - - /** - * @inheritDoc - */ - static get pluginName() { - return 'Language'; - } -} - -/** - * The configuration of the language feature. Introduced by the {@link module:language/languageediting~LanguageEditing} feature. - * - * Read more in {@link module:language/language~LanguageConfig}. - * - * @member {module:language/language~LanguageConfig} module:core/editor/editorconfig~EditorConfig#language - */ - -/** - * The configuration of the language feature. - * The option is used by the {@link module:language/languageediting~LanguageEditing} feature. - * - * ClassicEditor - * .create( { - * language: ... // Language feature config. - * } ) - * .then( ... ) - * .catch( ... ); - * - * See {@link module:core/editor/editorconfig~EditorConfig all editor options}. - * - * @interface LanguageConfig - */ - -/** - * The available language options. - * - * The default value is: - * - * const languageConfig = { - * options: [ - * { title: 'Arabic', languageCode: 'ar' }, - * { title: 'French', languageCode: 'fr' }, - * { title: 'Spanish', languageCode: 'es' } - * ] - * }; - * - * The `title` property will be used by the `language` dropdown to render available options. - * - * The `languageCode` property is used for the lang attribute in ISO 639 format. Language codes can be found - * [here](http://www.loc.gov/standards/iso639-2/php/English_list.php). You can use both 2-letter ISO-639-1 codes - * and 3-letter ISO-639-2 codes, though for consistency it is recommended to stick to ISO-639-1 2-letter codes. - * - * You can also specify optional `textDirection` property indicating the reading direction of the language. - * Correct values are `ltr` and `rtl`. When `textDirection` property is missing, the language feature will - * specify text direction by itself. - * - * @member {Array.} module:language/language~LanguageConfig#options - */ - -/** - * Language option descriptor. - * - * @typedef {Object} module:language/language~LanguageOption - * @property {String} title The user-readable title of the option. - * @property {String} languageCode The language code in ISO 639 format. - * @property {Strint} [textDirection] Language text direction. Automatically detected if omitted. - * @extends module:engine/conversion/conversion~ConverterDefinition - */ diff --git a/packages/ckeditor5-language/src/textfragmentlanguage.js b/packages/ckeditor5-language/src/textfragmentlanguage.js new file mode 100644 index 00000000000..77f9bd804c2 --- /dev/null +++ b/packages/ckeditor5-language/src/textfragmentlanguage.js @@ -0,0 +1,103 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module language/textfragmentlanguage + */ + +import { Plugin } from 'ckeditor5/src/core'; + +import TextFragmentLanguageEditing from './textfragmentlanguageediting'; +import TextFragmentLanguageUI from './textfragmentlanguageui'; + +/** + * The text fragment language plugin. + * + * For more information about this feature check the {@glink api/textfragmentlanguage package page}. + * + * This is a "glue" plugin which loads the {@link module:language/textfragmentlanguageediting~TextFragmentLanguageEditing + * text fragment language editing feature} and + * {@link module:language/textfragmentlanguageui~TextFragmentLanguageUI text fragment language UI feature}. + * + * @extends module:core/plugin~Plugin + */ +export default class TextFragmentLanguage extends Plugin { + /** + * @inheritDoc + */ + static get requires() { + return [ TextFragmentLanguageEditing, TextFragmentLanguageUI ]; + } + + /** + * @inheritDoc + */ + static get pluginName() { + return 'TextFragmentLanguage'; + } +} + +/** + * The configuration of the text fragment language feature. + * Introduced by the {@link module:language/textfragmentlanguageediting~TextFragmentLanguageEditing} feature. + * + * Read more in {@link module:language/textfragmentlanguage~TextFragmentLanguageConfig}. + * + * @member {module:language/textfragmentlanguage~TextFragmentLanguageConfig} + * module:core/editor/editorconfig~EditorConfig#textFragmentLanguage + */ + +/** + * The configuration of the text fragment language feature. + * The option is used by the {@link module:language/textfragmentlanguageediting~TextFragmentLanguageEditing} feature. + * + * ClassicEditor + * .create( { + * textFragmentLanguage: ... // Text fragment language feature config. + * } ) + * .then( ... ) + * .catch( ... ); + * + * See {@link module:core/editor/editorconfig~EditorConfig all editor options}. + * + * @interface TextFragmentLanguageConfig + */ + +/** + * The available text fragment language options. + * + * The default value is: + * + * const config = { + * options: [ + * { title: 'Arabic', languageCode: 'ar' }, + * { title: 'French', languageCode: 'fr' }, + * { title: 'Spanish', languageCode: 'es' } + * ] + * }; + * + * The `title` property will be used by the text fragment language dropdown to render available options. + * + * The `languageCode` property is used for the lang attribute in ISO 639 format. Language codes can be found + * [here](http://www.loc.gov/standards/iso639-2/php/English_list.php). You can use both 2-letter ISO-639-1 codes + * and 3-letter ISO-639-2 codes, though for consistency it is recommended to stick to ISO-639-1 2-letter codes. + * + * You can also specify optional `textDirection` property indicating the reading direction of the language. + * Correct values are `ltr` and `rtl`. When `textDirection` property is missing, the text fragment language feature will + * specify text direction by itself. + * + * @member {Array.} + * module:language/textfragmentlanguage~TextFragmentLanguageConfig#options + */ + +/** + * Text fragment language feature option descriptor. + * + * @typedef {Object} module:language/textfragmentlanguage~TextFragmentLanguageOption + * @property {String} title The user-readable title of the option. + * @property {String} languageCode The language code in ISO 639 format. + * @property {Strint} [textDirection] The language text direction. Automatically detected if omitted. + * @extends module:engine/conversion/conversion~ConverterDefinition + */ diff --git a/packages/ckeditor5-language/src/languagecommand.js b/packages/ckeditor5-language/src/textfragmentlanguagecommand.js similarity index 96% rename from packages/ckeditor5-language/src/languagecommand.js rename to packages/ckeditor5-language/src/textfragmentlanguagecommand.js index 78a47459544..a51fbc1042b 100644 --- a/packages/ckeditor5-language/src/languagecommand.js +++ b/packages/ckeditor5-language/src/textfragmentlanguagecommand.js @@ -4,7 +4,7 @@ */ /** - * @module language/languagecommand + * @module language/textfragmentlanguagecommand */ import { Command } from 'ckeditor5/src/core'; @@ -13,11 +13,11 @@ import { stringifyLanguageAttribute } from './utils'; const ATTRIBUTE_KEY = 'language'; /** - * The language command plugin. + * The text fragment language command plugin. * * @extends module:core/command~Command */ -export default class LanguageCommand extends Command { +export default class TextFragmentLanguageCommand extends Command { /** * If the selection starts in a language attribute the value is set to * the value of that language in a format: diff --git a/packages/ckeditor5-language/src/languageediting.js b/packages/ckeditor5-language/src/textfragmentlanguageediting.js similarity index 70% rename from packages/ckeditor5-language/src/languageediting.js rename to packages/ckeditor5-language/src/textfragmentlanguageediting.js index eb12e5be705..915d6dc14f0 100644 --- a/packages/ckeditor5-language/src/languageediting.js +++ b/packages/ckeditor5-language/src/textfragmentlanguageediting.js @@ -4,28 +4,28 @@ */ /** - * @module language/languageediting + * @module language/textfragmentlanguageediting */ import { Plugin } from 'ckeditor5/src/core'; -import LanguageCommand from './languagecommand'; +import TextFragmentLanguageCommand from './textfragmentlanguagecommand'; import { stringifyLanguageAttribute, parseLanguageAttribute } from './utils'; -const LANGUAGE = 'language'; +const ATTRIBUTE_KEY = 'language'; /** - * The language editing. + * The text fragment language editing. * - * Introduces the `'language'` command and the `'language'` model element. + * Introduces the `'textFragmentLanguage'` command and the `'language'` model element attribute. * * @extends module:core/plugin~Plugin */ -export default class LanguageEditing extends Plugin { +export default class TextFragmentLanguageEditing extends Plugin { /** * @inheritDoc */ static get pluginName() { - return 'LanguageEditing'; + return 'TextFragmentLanguageEditing'; } /** @@ -34,7 +34,7 @@ export default class LanguageEditing extends Plugin { constructor( editor ) { super( editor ); - // Language options are only used to ensure that the feature works by default. + // Text fragment language options are only used to ensure that the feature works by default. // In the real usage it should be reconfigured by a developer. We are not providing // translations for `title` properties on purpose, as it's only an example configuration. editor.config.define( 'languageList', { @@ -52,14 +52,14 @@ export default class LanguageEditing extends Plugin { init() { const editor = this.editor; - editor.model.schema.extend( '$text', { allowAttributes: LANGUAGE } ); - editor.model.schema.setAttributeProperties( LANGUAGE, { + editor.model.schema.extend( '$text', { allowAttributes: ATTRIBUTE_KEY } ); + editor.model.schema.setAttributeProperties( ATTRIBUTE_KEY, { copyOnEnter: true } ); this._defineConverters(); - editor.commands.add( LANGUAGE, new LanguageCommand( editor ) ); + editor.commands.add( 'textFragmentLanguage', new TextFragmentLanguageCommand( editor ) ); } /** @@ -70,7 +70,7 @@ export default class LanguageEditing extends Plugin { conversion.for( 'upcast' ).elementToAttribute( { model: { - key: LANGUAGE, + key: ATTRIBUTE_KEY, value: viewElement => { const languageCode = viewElement.getAttribute( 'lang' ); const textDirection = viewElement.getAttribute( 'dir' ); @@ -85,7 +85,7 @@ export default class LanguageEditing extends Plugin { } ); conversion.for( 'downcast' ).attributeToElement( { - model: LANGUAGE, + model: ATTRIBUTE_KEY, view: ( attributeValue, { writer } ) => { if ( !attributeValue ) { return; diff --git a/packages/ckeditor5-language/src/languageui.js b/packages/ckeditor5-language/src/textfragmentlanguageui.js similarity index 86% rename from packages/ckeditor5-language/src/languageui.js rename to packages/ckeditor5-language/src/textfragmentlanguageui.js index da54663f2e0..09d32f1ece5 100644 --- a/packages/ckeditor5-language/src/languageui.js +++ b/packages/ckeditor5-language/src/textfragmentlanguageui.js @@ -4,7 +4,7 @@ */ /** - * @module language/languageui + * @module language/textfragmentlanguageui */ import { Plugin } from 'ckeditor5/src/core'; @@ -15,18 +15,18 @@ import { stringifyLanguageAttribute } from './utils'; import '../theme/language.css'; /** - * The language UI plugin. + * The text fragment language UI plugin. * * It introduces the `'language'` button. * * @extends module:core/plugin~Plugin */ -export default class LanguageUI extends Plugin { +export default class TextFragmentLanguageUI extends Plugin { /** * @inheritDoc */ static get pluginName() { - return 'LanguageUI'; + return 'TextFragmentLanguageUI'; } /** @@ -41,11 +41,11 @@ export default class LanguageUI extends Plugin { const dropdownTooltip = t( 'Language' ); // Register UI component. - editor.ui.componentFactory.add( 'language', locale => { + editor.ui.componentFactory.add( 'textFragmentLanguage', locale => { const itemDefinitions = new Collection(); const titles = {}; - const languageCommand = editor.commands.get( 'language' ); + const languageCommand = editor.commands.get( 'textFragmentLanguage' ); for ( const option of options ) { const def = { @@ -93,7 +93,7 @@ export default class LanguageUI extends Plugin { dropdownView.extendTemplate( { attributes: { class: [ - 'ck-language-dropdown' + 'ck-text-fragment-language-dropdown' ] } } ); @@ -105,7 +105,7 @@ export default class LanguageUI extends Plugin { // Execute command when an item from the dropdown is selected. this.listenTo( dropdownView, 'execute', evt => { - editor.execute( 'language', { + editor.execute( 'textFragmentLanguage', { languageCode: evt.source.languageCode, textDirection: evt.source.textDirection } ); diff --git a/packages/ckeditor5-language/tests/language.js b/packages/ckeditor5-language/tests/language.js deleted file mode 100644 index 4bf7f676323..00000000000 --- a/packages/ckeditor5-language/tests/language.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - -import Language from '../src/language'; -import LanguageEditing from '../src/languageediting'; -import LanguageUI from '../src/languageui'; - -describe( 'Language', () => { - it( 'should require LanguageEditing and LanguageUI', () => { - expect( Language.requires ).to.deep.equal( [ LanguageEditing, LanguageUI ] ); - } ); - - it( 'should be named', () => { - expect( Language.pluginName ).to.equal( 'Language' ); - } ); -} ); diff --git a/packages/ckeditor5-language/tests/textfragmentlanguage.js b/packages/ckeditor5-language/tests/textfragmentlanguage.js new file mode 100644 index 00000000000..2a800e967a5 --- /dev/null +++ b/packages/ckeditor5-language/tests/textfragmentlanguage.js @@ -0,0 +1,18 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +import TextFragmentLanguage from '../src/textfragmentlanguage'; +import TextFragmentLanguageEditing from '../src/textfragmentlanguageediting'; +import TextFragmentLanguageUI from '../src/textfragmentlanguageui'; + +describe( 'TextFragmentLanguage', () => { + it( 'should require TextFragmentLanguageEditing and TextFragmentLanguageUI', () => { + expect( TextFragmentLanguage.requires ).to.deep.equal( [ TextFragmentLanguageEditing, TextFragmentLanguageUI ] ); + } ); + + it( 'should be named', () => { + expect( TextFragmentLanguage.pluginName ).to.equal( 'TextFragmentLanguage' ); + } ); +} ); diff --git a/packages/ckeditor5-language/tests/languagecommand.js b/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js similarity index 98% rename from packages/ckeditor5-language/tests/languagecommand.js rename to packages/ckeditor5-language/tests/textfragmentlanguagecommand.js index 563ca71891a..9d21b79175b 100644 --- a/packages/ckeditor5-language/tests/languagecommand.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js @@ -4,10 +4,10 @@ */ import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor'; -import LanguageCommand from '../src/languagecommand'; +import TextFragmentLanguageCommand from '../src/textfragmentlanguagecommand'; import { setData, getData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; -describe( 'LanguageCommand', () => { +describe( 'TextFragmentLanguageCommand', () => { const attrKey = 'language'; let editor, command, model, doc, root; @@ -20,7 +20,7 @@ describe( 'LanguageCommand', () => { doc = model.document; root = doc.getRoot(); - command = new LanguageCommand( editor ); + command = new TextFragmentLanguageCommand( editor ); model.schema.register( 'p', { inheritAllFrom: '$block' } ); model.schema.register( 'h1', { inheritAllFrom: '$block' } ); diff --git a/packages/ckeditor5-language/tests/languageediting.js b/packages/ckeditor5-language/tests/textfragmentlanguageediting.js similarity index 82% rename from packages/ckeditor5-language/tests/languageediting.js rename to packages/ckeditor5-language/tests/textfragmentlanguageediting.js index 3a906bca256..d465d72330e 100644 --- a/packages/ckeditor5-language/tests/languageediting.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguageediting.js @@ -4,19 +4,19 @@ */ import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; -import LanguageEditing from '../src/languageediting'; -import LanguageCommand from '../src/languagecommand'; +import TextFragmentLanguageEditing from '../src/textfragmentlanguageediting'; +import TextFragmentLanguageCommand from '../src/textfragmentlanguagecommand'; import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor'; import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view'; -describe( 'LanguageEditing', () => { +describe( 'TextFragmentLanguageEditing', () => { let editor, model; beforeEach( () => { return VirtualTestEditor .create( { - plugins: [ LanguageEditing, Paragraph ] + plugins: [ TextFragmentLanguageEditing, Paragraph ] } ) .then( newEditor => { editor = newEditor; @@ -25,11 +25,11 @@ describe( 'LanguageEditing', () => { } ); it( 'should have pluginName', () => { - expect( LanguageEditing.pluginName ).to.equal( 'LanguageEditing' ); + expect( TextFragmentLanguageEditing.pluginName ).to.equal( 'TextFragmentLanguageEditing' ); } ); it( 'should be loaded', () => { - expect( editor.plugins.get( LanguageEditing ) ).to.be.instanceOf( LanguageEditing ); + expect( editor.plugins.get( TextFragmentLanguageEditing ) ).to.be.instanceOf( TextFragmentLanguageEditing ); } ); it( 'should set proper schema rules', () => { @@ -44,9 +44,9 @@ describe( 'LanguageEditing', () => { } ); describe( 'command', () => { - it( 'should register language command', () => { - const command = editor.commands.get( 'language' ); - expect( command ).to.be.instanceOf( LanguageCommand ); + it( 'should register textFragmentLanguage command', () => { + const command = editor.commands.get( 'textFragmentLanguage' ); + expect( command ).to.be.instanceOf( TextFragmentLanguageCommand ); } ); } ); diff --git a/packages/ckeditor5-language/tests/languageui.js b/packages/ckeditor5-language/tests/textfragmentlanguageui.js similarity index 73% rename from packages/ckeditor5-language/tests/languageui.js rename to packages/ckeditor5-language/tests/textfragmentlanguageui.js index 8b34c0ce670..386dccd24fc 100644 --- a/packages/ckeditor5-language/tests/languageui.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguageui.js @@ -7,13 +7,13 @@ import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; -import LanguageEditing from '../src/languageediting'; -import LanguageUI from '../src/languageui'; +import TextFragmentLanguageEditing from '../src/textfragmentlanguageediting'; +import TextFragmentLanguageUI from '../src/textfragmentlanguageui'; import DropdownView from '@ckeditor/ckeditor5-ui/src/dropdown/dropdownview'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; -describe( 'LanguageUI', () => { +describe( 'TextFragmentLanguageUI', () => { let editor, editorElement, dropdown; testUtils.createSinonSandbox(); @@ -24,12 +24,12 @@ describe( 'LanguageUI', () => { return ClassicTestEditor .create( editorElement, { - plugins: [ LanguageUI, LanguageEditing, Paragraph ], - toolbar: [ 'language' ] + plugins: [ TextFragmentLanguageUI, TextFragmentLanguageEditing, Paragraph ], + toolbar: [ 'textFragmentLanguage' ] } ) .then( newEditor => { editor = newEditor; - dropdown = editor.ui.componentFactory.create( 'language' ); + dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); // Set data so the commands will be enabled. setData( editor.model, '[foo]' ); @@ -44,7 +44,7 @@ describe( 'LanguageUI', () => { describe( 'init()', () => { it( 'should register options feature component', () => { - const dropdown = editor.ui.componentFactory.create( 'language' ); + const dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); expect( dropdown ).to.be.instanceOf( DropdownView ); expect( dropdown.buttonView.isEnabled ).to.be.true; @@ -53,33 +53,33 @@ describe( 'LanguageUI', () => { expect( dropdown.buttonView.tooltip ).to.equal( 'Language' ); } ); - it( 'should execute language command on model (no language selected)', () => { + it( 'should execute textFragmentLanguage command on model (no language selected)', () => { const executeSpy = testUtils.sinon.spy( editor, 'execute' ); - const dropdown = editor.ui.componentFactory.create( 'language' ); + const dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); dropdown.fire( 'execute' ); sinon.assert.calledOnce( executeSpy ); - sinon.assert.calledWithExactly( executeSpy, 'language', + sinon.assert.calledWithExactly( executeSpy, 'textFragmentLanguage', { languageCode: undefined, textDirection: undefined } ); } ); - it( 'should execute language command on model (language selected)', () => { + it( 'should execute textFragmentLanguage command on model (language selected)', () => { const executeSpy = testUtils.sinon.spy( editor, 'execute' ); - const dropdown = editor.ui.componentFactory.create( 'language' ); + const dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); dropdown.languageCode = 'fr'; dropdown.textDirection = 'ltr'; dropdown.fire( 'execute' ); sinon.assert.calledOnce( executeSpy ); - sinon.assert.calledWithExactly( executeSpy, 'language', + sinon.assert.calledWithExactly( executeSpy, 'textFragmentLanguage', { languageCode: 'fr', textDirection: 'ltr' } ); } ); it( 'should focus view after command execution', () => { const focusSpy = testUtils.sinon.spy( editor.editing.view, 'focus' ); - const dropdown = editor.ui.componentFactory.create( 'language' ); + const dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); dropdown.languageCode = 'fr'; dropdown.fire( 'execute' ); @@ -88,18 +88,18 @@ describe( 'LanguageUI', () => { } ); it( 'should add custom CSS class to dropdown', () => { - const dropdown = editor.ui.componentFactory.create( 'language' ); + const dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); dropdown.render(); - expect( dropdown.element.classList.contains( 'ck-language-dropdown' ) ).to.be.true; + expect( dropdown.element.classList.contains( 'ck-text-fragment-language-dropdown' ) ).to.be.true; } ); describe( 'model to command binding', () => { let command; beforeEach( () => { - command = editor.commands.get( 'language' ); + command = editor.commands.get( 'textFragmentLanguage' ); } ); it( 'isEnabled', () => { From 313a4b85d37972d7bb37fd3da8269bb706ee74af Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 2 Mar 2021 09:07:07 +0100 Subject: [PATCH 16/36] Renamed options, updated manual tests. --- .../ckeditor5-language/src/textfragmentlanguageediting.js | 4 ++-- packages/ckeditor5-language/src/textfragmentlanguageui.js | 2 +- .../manual/{language.html => textfragmentlanguage.html} | 0 .../tests/manual/{language.js => textfragmentlanguage.js} | 6 +++--- .../tests/manual/{language.md => textfragmentlanguage.md} | 0 .../ckeditor5-language/tests/textfragmentlanguageediting.js | 2 +- 6 files changed, 7 insertions(+), 7 deletions(-) rename packages/ckeditor5-language/tests/manual/{language.html => textfragmentlanguage.html} (100%) rename packages/ckeditor5-language/tests/manual/{language.js => textfragmentlanguage.js} (73%) rename packages/ckeditor5-language/tests/manual/{language.md => textfragmentlanguage.md} (100%) diff --git a/packages/ckeditor5-language/src/textfragmentlanguageediting.js b/packages/ckeditor5-language/src/textfragmentlanguageediting.js index 915d6dc14f0..11cc8087535 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguageediting.js +++ b/packages/ckeditor5-language/src/textfragmentlanguageediting.js @@ -37,8 +37,8 @@ export default class TextFragmentLanguageEditing extends Plugin { // Text fragment language options are only used to ensure that the feature works by default. // In the real usage it should be reconfigured by a developer. We are not providing // translations for `title` properties on purpose, as it's only an example configuration. - editor.config.define( 'languageList', { - options: [ + editor.config.define( 'language', { + textFragmentLanguage: [ { title: 'Arabic', languageCode: 'ar' }, { title: 'French', languageCode: 'fr' }, { title: 'Spanish', languageCode: 'es' } diff --git a/packages/ckeditor5-language/src/textfragmentlanguageui.js b/packages/ckeditor5-language/src/textfragmentlanguageui.js index 09d32f1ece5..44028b27a01 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguageui.js +++ b/packages/ckeditor5-language/src/textfragmentlanguageui.js @@ -35,7 +35,7 @@ export default class TextFragmentLanguageUI extends Plugin { init() { const editor = this.editor; const t = editor.t; - const options = editor.config.get( 'languageList.options' ); + const options = editor.config.get( 'language.textFragmentLanguage' ); const defaultTitle = t( 'Choose language' ); const removeTitle = t( 'Remove language' ); const dropdownTooltip = t( 'Language' ); diff --git a/packages/ckeditor5-language/tests/manual/language.html b/packages/ckeditor5-language/tests/manual/textfragmentlanguage.html similarity index 100% rename from packages/ckeditor5-language/tests/manual/language.html rename to packages/ckeditor5-language/tests/manual/textfragmentlanguage.html diff --git a/packages/ckeditor5-language/tests/manual/language.js b/packages/ckeditor5-language/tests/manual/textfragmentlanguage.js similarity index 73% rename from packages/ckeditor5-language/tests/manual/language.js rename to packages/ckeditor5-language/tests/manual/textfragmentlanguage.js index 2bef3ae0b21..b85eedf9543 100644 --- a/packages/ckeditor5-language/tests/manual/language.js +++ b/packages/ckeditor5-language/tests/manual/textfragmentlanguage.js @@ -7,15 +7,15 @@ import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor'; import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset'; -import Language from '../../src/language'; +import TextFragmentLanguage from '../../src/textfragmentlanguage'; ClassicEditor .create( document.querySelector( '#editor' ), { plugins: [ ArticlePluginSet, - Language + TextFragmentLanguage ], - toolbar: [ 'language', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ] + toolbar: [ 'textFragmentLanguage', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ] } ) .then( editor => { window.editor = editor; diff --git a/packages/ckeditor5-language/tests/manual/language.md b/packages/ckeditor5-language/tests/manual/textfragmentlanguage.md similarity index 100% rename from packages/ckeditor5-language/tests/manual/language.md rename to packages/ckeditor5-language/tests/manual/textfragmentlanguage.md diff --git a/packages/ckeditor5-language/tests/textfragmentlanguageediting.js b/packages/ckeditor5-language/tests/textfragmentlanguageediting.js index d465d72330e..f64cdfbad10 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguageediting.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguageediting.js @@ -90,7 +90,7 @@ describe( 'TextFragmentLanguageEditing', () => { describe( 'config', () => { it( 'should be set', () => { - expect( editor.config.get( 'languageList.options' ) ).to.deep.equal( [ + expect( editor.config.get( 'language.textFragmentLanguage' ) ).to.deep.equal( [ { title: 'Arabic', languageCode: 'ar' }, { title: 'French', languageCode: 'fr' }, { title: 'Spanish', languageCode: 'es' } From f69578ce702e5ffb1dffce6fb74ac094c40ab7a4 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 2 Mar 2021 13:45:31 +0100 Subject: [PATCH 17/36] Docs. --- .../src/editor/editorconfig.jsdoc | 39 ++++++++++++++++- packages/ckeditor5-language/src/index.js | 18 ++++++++ .../src/textfragmentlanguage.js | 43 +++---------------- .../src/textfragmentlanguagecommand.js | 3 +- packages/ckeditor5-language/src/utils.js | 10 +++-- 5 files changed, 70 insertions(+), 43 deletions(-) create mode 100644 packages/ckeditor5-language/src/index.js diff --git a/packages/ckeditor5-core/src/editor/editorconfig.jsdoc b/packages/ckeditor5-core/src/editor/editorconfig.jsdoc index 33eea4a764c..a12de5103ac 100644 --- a/packages/ckeditor5-core/src/editor/editorconfig.jsdoc +++ b/packages/ckeditor5-core/src/editor/editorconfig.jsdoc @@ -176,6 +176,25 @@ * @member {Array.|Object} module:core/editor/editorconfig~EditorConfig#toolbar */ +/** + * The configuration of the editor language. + * + * ClassicEditor + * .create( document.querySelector( '#editor' ), { + * language: ... // Editor language configuration. + * } ) + * .then( editor => { + * console.log( editor ); + * } ) + * .catch( error => { + * console.error( error ); + * } ); + * + * See {@link module:core/editor/editorconfig~EditorConfig all editor options}. + * + * @interface LanguageConfig + */ + /** * The language of the editor UI and its content. * @@ -197,7 +216,7 @@ * console.error( error ); * } ); * - * Use different languages for the UI and the content using the object syntax: + * Use different languages for the UI and the content using the {@link module:core/editor/editorconfig~LanguageConfig configuration} syntax: * * ClassicEditor * .create( document.querySelector( '#editor' ), { @@ -231,7 +250,23 @@ * * Check the {@glink features/ui-language UI language guide} for more information about the localization options and translation process. * - * @member {String|Object} module:core/editor/editorconfig~EditorConfig#language + * @member {String|module:core/editor/editorconfig~LanguageConfig} module:core/editor/editorconfig~EditorConfig#language + */ + +/** + * Allows to use different language for the editor UI. + * + * The language codes are defined in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) standard. + * + * @member {String} module:core/editor/editorconfig~LanguageConfig#ui + */ + +/** + * Allows to use different language of the editor content. + * + * The language codes are defined in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) standard. + * + * @member {String} module:core/editor/editorconfig~LanguageConfig#content */ /** diff --git a/packages/ckeditor5-language/src/index.js b/packages/ckeditor5-language/src/index.js new file mode 100644 index 00000000000..ce310add4f4 --- /dev/null +++ b/packages/ckeditor5-language/src/index.js @@ -0,0 +1,18 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module block-quote + */ + +import TextFragmentLanguage from './textfragmentlanguage'; +import TextFragmentLanguageEditing from './textfragmentlanguageediting'; +import TextFragmentLanguageUI from './textfragmentlanguageui'; + +export default { + TextFragmentLanguage, + TextFragmentLanguageEditing, + TextFragmentLanguageUI +}; diff --git a/packages/ckeditor5-language/src/textfragmentlanguage.js b/packages/ckeditor5-language/src/textfragmentlanguage.js index 77f9bd804c2..9db87e152cd 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguage.js +++ b/packages/ckeditor5-language/src/textfragmentlanguage.js @@ -39,44 +39,16 @@ export default class TextFragmentLanguage extends Plugin { } } -/** - * The configuration of the text fragment language feature. - * Introduced by the {@link module:language/textfragmentlanguageediting~TextFragmentLanguageEditing} feature. - * - * Read more in {@link module:language/textfragmentlanguage~TextFragmentLanguageConfig}. - * - * @member {module:language/textfragmentlanguage~TextFragmentLanguageConfig} - * module:core/editor/editorconfig~EditorConfig#textFragmentLanguage - */ - -/** - * The configuration of the text fragment language feature. - * The option is used by the {@link module:language/textfragmentlanguageediting~TextFragmentLanguageEditing} feature. - * - * ClassicEditor - * .create( { - * textFragmentLanguage: ... // Text fragment language feature config. - * } ) - * .then( ... ) - * .catch( ... ); - * - * See {@link module:core/editor/editorconfig~EditorConfig all editor options}. - * - * @interface TextFragmentLanguageConfig - */ - /** * The available text fragment language options. * * The default value is: * - * const config = { - * options: [ - * { title: 'Arabic', languageCode: 'ar' }, - * { title: 'French', languageCode: 'fr' }, - * { title: 'Spanish', languageCode: 'es' } - * ] - * }; + * const config = [ + * { title: 'Arabic', languageCode: 'ar' }, + * { title: 'French', languageCode: 'fr' }, + * { title: 'Spanish', languageCode: 'es' } + * ]; * * The `title` property will be used by the text fragment language dropdown to render available options. * @@ -89,7 +61,7 @@ export default class TextFragmentLanguage extends Plugin { * specify text direction by itself. * * @member {Array.} - * module:language/textfragmentlanguage~TextFragmentLanguageConfig#options + * module:core/editor/editorconfig~LanguageConfig#textFragmentLanguage */ /** @@ -98,6 +70,5 @@ export default class TextFragmentLanguage extends Plugin { * @typedef {Object} module:language/textfragmentlanguage~TextFragmentLanguageOption * @property {String} title The user-readable title of the option. * @property {String} languageCode The language code in ISO 639 format. - * @property {Strint} [textDirection] The language text direction. Automatically detected if omitted. - * @extends module:engine/conversion/conversion~ConverterDefinition + * @property {String} [textDirection] The language text direction. Automatically detected if omitted. */ diff --git a/packages/ckeditor5-language/src/textfragmentlanguagecommand.js b/packages/ckeditor5-language/src/textfragmentlanguagecommand.js index a51fbc1042b..991b95f5253 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguagecommand.js +++ b/packages/ckeditor5-language/src/textfragmentlanguagecommand.js @@ -27,7 +27,8 @@ export default class TextFragmentLanguageCommand extends Command { * * `languageCode` - The language code used for the lang attribute in ISO 639 format. * * `textDirection` - One of the following values: `rtl` or `ltr`, indicating the reading direction of the language. * - * See {@link module:language/language~LanguageConfig language config} for more information about language properties. + * See {@link module:core/editor/editorconfig~LanguageConfig#textFragmentLanguage text fragment config} + * for more information about language properties. * * It is set to `false` otherwise. * diff --git a/packages/ckeditor5-language/src/utils.js b/packages/ckeditor5-language/src/utils.js index eb47828a516..2c47d9106ed 100644 --- a/packages/ckeditor5-language/src/utils.js +++ b/packages/ckeditor5-language/src/utils.js @@ -17,12 +17,14 @@ import { getLanguageDirection } from 'ckeditor5/src/utils'; * * `languageCode` - The language code used for the lang attribute in ISO 639 format. * * `textDirection` - One of the following values: `rtl` or `ltr`, indicating the reading direction of the language. * - * See {@link module:language/language~LanguageConfig language config} for more information about language properties. + * See {@link module:core/editor/editorconfig~LanguageConfig#textFragmentLanguage text fragment config} + * for more information about language properties. * * If `textDirection` argument is omitted, it will be automatically detected based on `languageCode`. * * @param {String} languageCode The language code in ISO 639 format. * @param {String} [textDirection] Language text direction. Automatically detected if omitted. + * @returns {String} */ export function stringifyLanguageAttribute( languageCode, textDirection ) { textDirection = textDirection || getLanguageDirection( languageCode ); @@ -34,9 +36,9 @@ export function stringifyLanguageAttribute( languageCode, textDirection ) { * {@link module:language/utils~stringifyLanguageAttribute stringifyLanguageAttribute} function. * * @param {String} str Attribute value. - * @returns result - * @returns result.languageCode The language code in ISO 639 format. - * @returns result.textDirection Language text direction. + * @returns {Object} result + * @returns {String} result.languageCode The language code in ISO 639 format. + * @returns {String} result.textDirection Language text direction. */ export function parseLanguageAttribute( str ) { const parts = str.split( ':' ); From d05dea88b45131221b19390127efb1456a633a30 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 2 Mar 2021 13:58:41 +0100 Subject: [PATCH 18/36] Corrected leftovers. --- packages/ckeditor5-language/src/index.js | 2 +- .../tests/manual/textfragmentlanguage.md | 2 +- .../tests/textfragmentlanguagecommand.js | 50 ++++++++++--------- 3 files changed, 28 insertions(+), 26 deletions(-) diff --git a/packages/ckeditor5-language/src/index.js b/packages/ckeditor5-language/src/index.js index ce310add4f4..8d9c334e876 100644 --- a/packages/ckeditor5-language/src/index.js +++ b/packages/ckeditor5-language/src/index.js @@ -4,7 +4,7 @@ */ /** - * @module block-quote + * @module language */ import TextFragmentLanguage from './textfragmentlanguage'; diff --git a/packages/ckeditor5-language/tests/manual/textfragmentlanguage.md b/packages/ckeditor5-language/tests/manual/textfragmentlanguage.md index d3db58cdd15..18e1f752a81 100644 --- a/packages/ckeditor5-language/tests/manual/textfragmentlanguage.md +++ b/packages/ckeditor5-language/tests/manual/textfragmentlanguage.md @@ -1,4 +1,4 @@ -## Language feature +## Text fragment language feature 1. The data should be loaded with four paragraph. Each paragraph style with applied language should be italic. 2. Put selection in each paragraph and check if language dropdown label is changing properly. diff --git a/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js b/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js index 9d21b79175b..d8c9503dc06 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js @@ -50,7 +50,7 @@ describe( 'TextFragmentLanguageCommand', () => { writer.setSelectionAttribute( attrKey, 'fr:ltr' ); } ); - expect( command.value ).to.eql( 'fr:ltr' ); + expect( command.value ).to.equal( 'fr:ltr' ); } ); it( 'is false when collapsed selection does not have the attribute', () => { @@ -68,13 +68,13 @@ describe( 'TextFragmentLanguageCommand', () => { it( 'includes language when the first item that allows attribute has the attribute #1', () => { setData( model, '

<$text language="fr:ltr">fo[o

b]ar

' ); - expect( command.value ).to.eql( 'fr:ltr' ); + expect( command.value ).to.equal( 'fr:ltr' ); } ); it( 'includes language when the first item that allows attribute has the attribute #2', () => { setData( model, '

fo[o

<$text language="fr:ltr">fo]o

' ); - expect( command.value ).to.eql( 'fr:ltr' ); + expect( command.value ).to.equal( 'fr:ltr' ); } ); it( 'is false when the selection does not have the attribute', () => { @@ -111,9 +111,9 @@ describe( 'TextFragmentLanguageCommand', () => { expect( command.value ).to.be.false; command.execute( { languageCode: 'fr', textDirection: 'ltr' } ); - expect( command.value ).to.eql( 'fr:ltr' ); + expect( command.value ).to.equal( 'fr:ltr' ); - expect( getData( model ) ).equal( + expect( getData( model ) ).to.equal( '

[<$text language="fr:ltr">Some caption inside the image.]

' ); } ); @@ -166,7 +166,7 @@ describe( 'TextFragmentLanguageCommand', () => { command.execute( { languageCode: 'fr', textDirection: 'ltr' } ); - expect( getData( model ) ).equal( '

fo[ob]ar

' ); + expect( getData( model ) ).to.equal( '

fo[ob]ar

' ); } ); it( 'should add attribute on selected nodes if the command value was not set', () => { @@ -176,30 +176,32 @@ describe( 'TextFragmentLanguageCommand', () => { command.execute( { languageCode: 'fr', textDirection: 'ltr' } ); - expect( command.value ).to.eql( 'fr:ltr' ); - expect( getData( model ) ).equal( '

a[<$text language="fr:ltr">bcfo]obarxyz

' ); + expect( command.value ).to.equal( 'fr:ltr' ); + expect( getData( model ) ).to.equal( '

a[<$text language="fr:ltr">bcfo]obarxyz

' ); } ); it( 'should remove attribute from selected nodes if the command value was not set', () => { setData( model, '

abc[<$text language="fr:ltr">foo]barxyz

' ); - expect( command.value ).to.eql( 'fr:ltr' ); + expect( command.value ).to.equal( 'fr:ltr' ); command.execute(); - expect( getData( model ) ).equal( '

abc[foo]<$text language="fr:ltr">barxyz

' ); + expect( getData( model ) ).to.equal( '

abc[foo]<$text language="fr:ltr">barxyz

' ); expect( command.value ).to.be.false; } ); it( 'should replace attribute on selected nodes if execute parameter was set', () => { setData( model, '

abc<$text language="fr:ltr">foob[arx]yz

' ); - expect( command.value ).to.eql( 'fr:ltr' ); + expect( command.value ).to.equal( 'fr:ltr' ); command.execute( { languageCode: 'ar', textDirection: 'rtl' } ); - expect( command.value ).to.eql( 'ar:rtl' ); - expect( getData( model ) ).equal( '

abc<$text language="fr:ltr">foob[<$text language="ar:rtl">arx]yz

' ); + expect( command.value ).to.equal( 'ar:rtl' ); + expect( getData( model ) ).to.equal( + '

abc<$text language="fr:ltr">foob[<$text language="ar:rtl">arx]yz

' + ); } ); it( 'should remove attribute on selected nodes if execute parameter was set to false', () => { @@ -208,7 +210,7 @@ describe( 'TextFragmentLanguageCommand', () => { command.execute( { languageCode: false } ); expect( command.value ).to.be.false; - expect( getData( model ) ).equal( '

a[bcfo]<$text language="fr:ltr">obarxyz

' ); + expect( getData( model ) ).to.equal( '

a[bcfo]<$text language="fr:ltr">obarxyz

' ); } ); it( 'should remove attribute on selected nodes if execute parameter was set to null', () => { @@ -217,7 +219,7 @@ describe( 'TextFragmentLanguageCommand', () => { command.execute( { languageCode: null } ); expect( command.value ).to.be.false; - expect( getData( model ) ).equal( '

a[bcfo]<$text language="fr:ltr">obarxyz

' ); + expect( getData( model ) ).to.equal( '

a[bcfo]<$text language="fr:ltr">obarxyz

' ); } ); it( 'should change selection attribute if selection is collapsed in non-empty parent', () => { @@ -227,8 +229,8 @@ describe( 'TextFragmentLanguageCommand', () => { command.execute( { languageCode: 'ar', textDirection: 'rtl' } ); - expect( command.value ).to.eql( 'ar:rtl' ); - expect( doc.selection.getAttribute( 'language' ) ).to.eql( 'ar:rtl' ); + expect( command.value ).to.equal( 'ar:rtl' ); + expect( doc.selection.getAttribute( 'language' ) ).to.equal( 'ar:rtl' ); command.execute( { languageCode: false } ); @@ -265,8 +267,8 @@ describe( 'TextFragmentLanguageCommand', () => { command.execute( { languageCode: 'ar', textDirection: 'rtl' } ); - expect( command.value ).to.eql( 'ar:rtl' ); - expect( doc.selection.getAttribute( 'language' ) ).to.eql( 'ar:rtl' ); + expect( command.value ).to.equal( 'ar:rtl' ); + expect( doc.selection.getAttribute( 'language' ) ).to.equal( 'ar:rtl' ); // Attribute should be stored. // Simulate clicking somewhere else in the editor. @@ -282,7 +284,7 @@ describe( 'TextFragmentLanguageCommand', () => { } ); // Attribute should be restored. - expect( command.value ).to.eql( 'ar:rtl' ); + expect( command.value ).to.equal( 'ar:rtl' ); command.execute( { languageCode: false } ); @@ -295,8 +297,8 @@ describe( 'TextFragmentLanguageCommand', () => { command.execute( { languageCode: 'ar', textDirection: 'ltr' } ); - expect( command.value ).to.eql( 'ar:ltr' ); - expect( doc.selection.getAttribute( 'language' ) ).to.eql( 'ar:ltr' ); + expect( command.value ).to.equal( 'ar:ltr' ); + expect( doc.selection.getAttribute( 'language' ) ).to.equal( 'ar:ltr' ); } ); it( 'should detect language text direction if textDirection was not set', () => { @@ -304,8 +306,8 @@ describe( 'TextFragmentLanguageCommand', () => { command.execute( { languageCode: 'ar' } ); - expect( command.value ).to.eql( 'ar:rtl' ); - expect( doc.selection.getAttribute( 'language' ) ).to.eql( 'ar:rtl' ); + expect( command.value ).to.equal( 'ar:rtl' ); + expect( doc.selection.getAttribute( 'language' ) ).to.equal( 'ar:rtl' ); } ); describe( 'model change event', () => { From c70e91a50dcac6848cfd53275d3ae99dc3bf154e Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 2 Mar 2021 14:16:00 +0100 Subject: [PATCH 19/36] Improved docs to distinguish it from UI language. --- .../src/textfragmentlanguage.js | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/packages/ckeditor5-language/src/textfragmentlanguage.js b/packages/ckeditor5-language/src/textfragmentlanguage.js index 9db87e152cd..8613ccf08f7 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguage.js +++ b/packages/ckeditor5-language/src/textfragmentlanguage.js @@ -15,6 +15,14 @@ import TextFragmentLanguageUI from './textfragmentlanguageui'; /** * The text fragment language plugin. * + * This feature allows setting language of parts of the content using simple dropdown button. For example, + * use it when you would like to indicate that the specific quote is in different language than the rest of the content. + * Refer to [WCAG 3.1.2 Language of Parts](https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html) specification + * to learn more. + * + * To change UI editor language, refer to [Setting the UI language](https://ckeditor.com/docs/ckeditor5/latest/features/ui-language.html) + * guide. + * * For more information about this feature check the {@glink api/textfragmentlanguage package page}. * * This is a "glue" plugin which loads the {@link module:language/textfragmentlanguageediting~TextFragmentLanguageEditing @@ -40,7 +48,13 @@ export default class TextFragmentLanguage extends Plugin { } /** - * The available text fragment language options. + * The available {@link module:language/textfragmentlanguage} options allowing setting language of parts of the content. + * + * Refer to [WCAG 3.1.2 Language of Parts](https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html) specification + * to learn more. + * + * To change UI editor languge, refer to [Setting the UI language](https://ckeditor.com/docs/ckeditor5/latest/features/ui-language.html) + * guide. * * The default value is: * From 73e3f181f14ccdd72e8b6f75e267eba48a6b1c4a Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 2 Mar 2021 14:22:30 +0100 Subject: [PATCH 20/36] Updated lang files description. --- packages/ckeditor5-language/lang/contexts.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ckeditor5-language/lang/contexts.json b/packages/ckeditor5-language/lang/contexts.json index bd576f6e597..3884a72a652 100644 --- a/packages/ckeditor5-language/lang/contexts.json +++ b/packages/ckeditor5-language/lang/contexts.json @@ -1,3 +1,3 @@ { - "Language": "Toolbar button tooltip for the Language feature." + "Language": "Toolbar button tooltip for the Text Fragment Language feature." } From 9ce37422ba0e9588b43a6b775bc4bcd0ca4196c9 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 2 Mar 2021 14:58:39 +0100 Subject: [PATCH 21/36] Added test confirming that config can be customized. --- .../tests/textfragmentlanguageediting.js | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/packages/ckeditor5-language/tests/textfragmentlanguageediting.js b/packages/ckeditor5-language/tests/textfragmentlanguageediting.js index f64cdfbad10..98b919333f9 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguageediting.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguageediting.js @@ -96,6 +96,33 @@ describe( 'TextFragmentLanguageEditing', () => { { title: 'Spanish', languageCode: 'es' } ] ); } ); + + it( 'should be customizable', async () => { + const languageConfig = { + ui: 'pl', + content: 'pl', + textFragmentLanguage: [ + { title: 'Hebrew', languageCode: 'he' }, + { title: 'Polish', languageCode: 'pl' } + ] + }; + + await createCustomConfigEditor( languageConfig ); + + expect( editor.config.get( 'language' ) ).to.deep.equal( languageConfig ); + } ); + + function createCustomConfigEditor( languageConfig ) { + return VirtualTestEditor + .create( { + plugins: [ TextFragmentLanguageEditing, Paragraph ], + language: languageConfig + } ) + .then( newEditor => { + editor = newEditor; + model = editor.model; + } ); + } } ); } ); From d85541acbf8efea2505dcfda26d4e58a9db56257 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Tue, 2 Mar 2021 15:37:27 +0100 Subject: [PATCH 22/36] Refactoring. --- .../src/textfragmentlanguageui.js | 2 +- .../tests/textfragmentlanguageui.js | 18 +++++++----------- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/packages/ckeditor5-language/src/textfragmentlanguageui.js b/packages/ckeditor5-language/src/textfragmentlanguageui.js index 44028b27a01..81d1941eb90 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguageui.js +++ b/packages/ckeditor5-language/src/textfragmentlanguageui.js @@ -105,7 +105,7 @@ export default class TextFragmentLanguageUI extends Plugin { // Execute command when an item from the dropdown is selected. this.listenTo( dropdownView, 'execute', evt => { - editor.execute( 'textFragmentLanguage', { + languageCommand.execute( { languageCode: evt.source.languageCode, textDirection: evt.source.textDirection } ); diff --git a/packages/ckeditor5-language/tests/textfragmentlanguageui.js b/packages/ckeditor5-language/tests/textfragmentlanguageui.js index 386dccd24fc..9af850ddf99 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguageui.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguageui.js @@ -14,7 +14,7 @@ import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; describe( 'TextFragmentLanguageUI', () => { - let editor, editorElement, dropdown; + let editor, editorElement, dropdown, command; testUtils.createSinonSandbox(); @@ -31,6 +31,8 @@ describe( 'TextFragmentLanguageUI', () => { editor = newEditor; dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); + command = editor.commands.get( 'textFragmentLanguage' ); + // Set data so the commands will be enabled. setData( editor.model, '[foo]' ); } ); @@ -54,18 +56,18 @@ describe( 'TextFragmentLanguageUI', () => { } ); it( 'should execute textFragmentLanguage command on model (no language selected)', () => { - const executeSpy = testUtils.sinon.spy( editor, 'execute' ); + const executeSpy = testUtils.sinon.spy( command, 'execute' ); const dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); dropdown.fire( 'execute' ); sinon.assert.calledOnce( executeSpy ); - sinon.assert.calledWithExactly( executeSpy, 'textFragmentLanguage', + sinon.assert.calledWithExactly( executeSpy, { languageCode: undefined, textDirection: undefined } ); } ); it( 'should execute textFragmentLanguage command on model (language selected)', () => { - const executeSpy = testUtils.sinon.spy( editor, 'execute' ); + const executeSpy = testUtils.sinon.spy( command, 'execute' ); const dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); dropdown.languageCode = 'fr'; @@ -73,7 +75,7 @@ describe( 'TextFragmentLanguageUI', () => { dropdown.fire( 'execute' ); sinon.assert.calledOnce( executeSpy ); - sinon.assert.calledWithExactly( executeSpy, 'textFragmentLanguage', + sinon.assert.calledWithExactly( executeSpy, { languageCode: 'fr', textDirection: 'ltr' } ); } ); @@ -96,12 +98,6 @@ describe( 'TextFragmentLanguageUI', () => { } ); describe( 'model to command binding', () => { - let command; - - beforeEach( () => { - command = editor.commands.get( 'textFragmentLanguage' ); - } ); - it( 'isEnabled', () => { command.isEnabled = false; From 49db2d15fb014e979eee29d842c2b2122e0d64bb Mon Sep 17 00:00:00 2001 From: Kuba Niegowski Date: Thu, 4 Mar 2021 10:41:41 +0100 Subject: [PATCH 23/36] Updated package.json. --- packages/ckeditor5-language/package.json | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/ckeditor5-language/package.json b/packages/ckeditor5-language/package.json index eabb85e6ba2..ec12367fe49 100644 --- a/packages/ckeditor5-language/package.json +++ b/packages/ckeditor5-language/package.json @@ -1,6 +1,6 @@ { "name": "@ckeditor/ckeditor5-language", - "version": "25.0.0", + "version": "26.0.0", "description": "Language feature for CKEditor 5.", "keywords": [ "ckeditor", @@ -11,16 +11,16 @@ ], "main": "src/index.js", "dependencies": { - "ckeditor5": "^25.0.0" + "ckeditor5": "^26.0.0" }, "devDependencies": { - "@ckeditor/ckeditor5-core": "^25.0.0", + "@ckeditor/ckeditor5-core": "^26.0.0", "@ckeditor/ckeditor5-dev-utils": "^24.0.0", - "@ckeditor/ckeditor5-editor-classic": "^25.0.0", - "@ckeditor/ckeditor5-engine": "^25.0.0", - "@ckeditor/ckeditor5-paragraph": "^25.0.0", - "@ckeditor/ckeditor5-theme-lark": "^25.0.0", - "@ckeditor/ckeditor5-ui": "^25.0.0", + "@ckeditor/ckeditor5-editor-classic": "^26.0.0", + "@ckeditor/ckeditor5-engine": "^26.0.0", + "@ckeditor/ckeditor5-paragraph": "^26.0.0", + "@ckeditor/ckeditor5-theme-lark": "^26.0.0", + "@ckeditor/ckeditor5-ui": "^26.0.0", "webpack": "^4.43.0", "webpack-cli": "^3.3.11" }, @@ -44,6 +44,6 @@ "build" ], "scripts": { - "build:dll": "webpack" + "dll:build": "webpack" } } From 5cd4ee479ae41eada3c075bf64d1916c4b28d773 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Fri, 5 Mar 2021 10:25:01 +0100 Subject: [PATCH 24/36] Updated lang context file. --- packages/ckeditor5-language/lang/contexts.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/ckeditor5-language/lang/contexts.json b/packages/ckeditor5-language/lang/contexts.json index 3884a72a652..4153131779a 100644 --- a/packages/ckeditor5-language/lang/contexts.json +++ b/packages/ckeditor5-language/lang/contexts.json @@ -1,3 +1,5 @@ { - "Language": "Toolbar button tooltip for the Text Fragment Language feature." + "Language": "Toolbar button tooltip for the text fragment language feature.", + "Choose language": "Default label for the text fragment language dropdown.", + "Remove language": "The label of the remove language option for the text fragment language dropdown." } From 9b969c8f2c95b0e6e305c23316b06fc007bc652b Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Fri, 5 Mar 2021 10:32:19 +0100 Subject: [PATCH 25/36] Improved docs. --- packages/ckeditor5-language/src/textfragmentlanguage.js | 6 ++---- .../ckeditor5-language/src/textfragmentlanguagecommand.js | 2 +- packages/ckeditor5-language/src/textfragmentlanguageui.js | 2 +- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/ckeditor5-language/src/textfragmentlanguage.js b/packages/ckeditor5-language/src/textfragmentlanguage.js index 8613ccf08f7..0249cf79354 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguage.js +++ b/packages/ckeditor5-language/src/textfragmentlanguage.js @@ -20,8 +20,7 @@ import TextFragmentLanguageUI from './textfragmentlanguageui'; * Refer to [WCAG 3.1.2 Language of Parts](https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html) specification * to learn more. * - * To change UI editor language, refer to [Setting the UI language](https://ckeditor.com/docs/ckeditor5/latest/features/ui-language.html) - * guide. + * To change UI editor language, refer to {@glink features/ui-language setting the UI language} guide. * * For more information about this feature check the {@glink api/textfragmentlanguage package page}. * @@ -53,8 +52,7 @@ export default class TextFragmentLanguage extends Plugin { * Refer to [WCAG 3.1.2 Language of Parts](https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html) specification * to learn more. * - * To change UI editor languge, refer to [Setting the UI language](https://ckeditor.com/docs/ckeditor5/latest/features/ui-language.html) - * guide. + * To change UI editor language, refer to {@glink features/ui-language setting the UI language} guide. * * The default value is: * diff --git a/packages/ckeditor5-language/src/textfragmentlanguagecommand.js b/packages/ckeditor5-language/src/textfragmentlanguagecommand.js index 991b95f5253..6fad3103386 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguagecommand.js +++ b/packages/ckeditor5-language/src/textfragmentlanguagecommand.js @@ -101,7 +101,7 @@ export default class TextFragmentLanguageCommand extends Command { * For the collapsed selection returns the selection attribute. * * @private - * @returns {Object} The attribute value. + * @returns {Boolean|String} The attribute value. */ _getValueFromFirstAllowedNode() { const model = this.editor.model; diff --git a/packages/ckeditor5-language/src/textfragmentlanguageui.js b/packages/ckeditor5-language/src/textfragmentlanguageui.js index 81d1941eb90..147e6c9e038 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguageui.js +++ b/packages/ckeditor5-language/src/textfragmentlanguageui.js @@ -17,7 +17,7 @@ import '../theme/language.css'; /** * The text fragment language UI plugin. * - * It introduces the `'language'` button. + * It introduces the `'language'` dropdown. * * @extends module:core/plugin~Plugin */ From 8947f570df61375f63cc350b4bce050441f66607 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jacek=20Bogda=C5=84ski?= Date: Fri, 5 Mar 2021 10:37:15 +0100 Subject: [PATCH 26/36] Refactoring, docs improvements. Co-authored-by: Kuba Niegowski <1232187+niegowski@users.noreply.github.com> --- packages/ckeditor5-language/src/textfragmentlanguage.js | 5 +++-- packages/ckeditor5-language/src/utils.js | 7 ++++--- .../tests/textfragmentlanguageediting.js | 3 +-- packages/ckeditor5-utils/src/language.js | 2 +- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/ckeditor5-language/src/textfragmentlanguage.js b/packages/ckeditor5-language/src/textfragmentlanguage.js index 0249cf79354..2973c0c61d9 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguage.js +++ b/packages/ckeditor5-language/src/textfragmentlanguage.js @@ -47,7 +47,8 @@ export default class TextFragmentLanguage extends Plugin { } /** - * The available {@link module:language/textfragmentlanguage} options allowing setting language of parts of the content. + * The available {@link module:language/textfragmentlanguage~TextFragmentLanguage +} options allowing setting language of parts of the content. * * Refer to [WCAG 3.1.2 Language of Parts](https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html) specification * to learn more. @@ -82,5 +83,5 @@ export default class TextFragmentLanguage extends Plugin { * @typedef {Object} module:language/textfragmentlanguage~TextFragmentLanguageOption * @property {String} title The user-readable title of the option. * @property {String} languageCode The language code in ISO 639 format. - * @property {String} [textDirection] The language text direction. Automatically detected if omitted. + * @property {'ltr'|'rtl'} [textDirection] The language text direction. Automatically detected if omitted. */ diff --git a/packages/ckeditor5-language/src/utils.js b/packages/ckeditor5-language/src/utils.js index 2c47d9106ed..54c21d46868 100644 --- a/packages/ckeditor5-language/src/utils.js +++ b/packages/ckeditor5-language/src/utils.js @@ -23,7 +23,7 @@ import { getLanguageDirection } from 'ckeditor5/src/utils'; * If `textDirection` argument is omitted, it will be automatically detected based on `languageCode`. * * @param {String} languageCode The language code in ISO 639 format. - * @param {String} [textDirection] Language text direction. Automatically detected if omitted. + * @param {'ltr'|'rtl'} [textDirection] Language text direction. Automatically detected if omitted. * @returns {String} */ export function stringifyLanguageAttribute( languageCode, textDirection ) { @@ -41,6 +41,7 @@ export function stringifyLanguageAttribute( languageCode, textDirection ) { * @returns {String} result.textDirection Language text direction. */ export function parseLanguageAttribute( str ) { - const parts = str.split( ':' ); - return { languageCode: parts[ 0 ], textDirection: parts[ 1 ] }; + const [ languageCode, textDirection ] = str.split( ':' ); + + return { languageCode, textDirection }; } diff --git a/packages/ckeditor5-language/tests/textfragmentlanguageediting.js b/packages/ckeditor5-language/tests/textfragmentlanguageediting.js index 98b919333f9..a3d482be791 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguageediting.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguageediting.js @@ -37,7 +37,7 @@ describe( 'TextFragmentLanguageEditing', () => { expect( model.schema.checkAttribute( [ '$clipboardHolder', '$text' ], 'language' ) ).to.be.true; } ); - it( 'its attribute is marked with a copOnEnter property', () => { + it( 'its attribute is marked with a copyOnEnter property', () => { expect( model.schema.getAttributeProperties( 'language' ) ).to.include( { copyOnEnter: true } ); @@ -125,4 +125,3 @@ describe( 'TextFragmentLanguageEditing', () => { } } ); } ); - diff --git a/packages/ckeditor5-utils/src/language.js b/packages/ckeditor5-utils/src/language.js index 561a96c95d5..ddc86921bf5 100644 --- a/packages/ckeditor5-utils/src/language.js +++ b/packages/ckeditor5-utils/src/language.js @@ -19,7 +19,7 @@ const RTL_LANGUAGE_CODES = [ * Helps determine whether a language text direction is LTR or RTL. * * @param {String} language The ISO 639 language code. - * @returns {String} 'ltr' or 'rtl + * @returns {'ltr'|'rtl'} */ export function getLanguageDirection( languageCode ) { return RTL_LANGUAGE_CODES.includes( languageCode ) ? 'rtl' : 'ltr'; From 221c0d4d5cd000ead9527b374638b3c50caeb897 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Fri, 5 Mar 2021 10:54:38 +0100 Subject: [PATCH 27/36] Updated attribute regexp. --- packages/ckeditor5-language/src/textfragmentlanguageediting.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/ckeditor5-language/src/textfragmentlanguageediting.js b/packages/ckeditor5-language/src/textfragmentlanguageediting.js index 11cc8087535..f433d022ad1 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguageediting.js +++ b/packages/ckeditor5-language/src/textfragmentlanguageediting.js @@ -80,7 +80,7 @@ export default class TextFragmentLanguageEditing extends Plugin { }, view: { name: 'span', - attributes: { lang: /[^]/ } + attributes: { lang: /[\s\S]+/ } } } ); From 76dcb43fc0a9946c4c8da10e2347d4196411aab9 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Fri, 5 Mar 2021 11:33:19 +0100 Subject: [PATCH 28/36] Corrected tests. --- .../tests/textfragmentlanguagecommand.js | 3 +- .../tests/textfragmentlanguageediting.js | 30 +++++++++---------- .../tests/textfragmentlanguageui.js | 5 ++-- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js b/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js index d8c9503dc06..f1194ea5d9f 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js @@ -4,9 +4,10 @@ */ import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor'; -import TextFragmentLanguageCommand from '../src/textfragmentlanguagecommand'; import { setData, getData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; +import TextFragmentLanguageCommand from '../src/textfragmentlanguagecommand'; + describe( 'TextFragmentLanguageCommand', () => { const attrKey = 'language'; let editor, command, model, doc, root; diff --git a/packages/ckeditor5-language/tests/textfragmentlanguageediting.js b/packages/ckeditor5-language/tests/textfragmentlanguageediting.js index a3d482be791..d290f2eda47 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguageediting.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguageediting.js @@ -4,12 +4,13 @@ */ import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; -import TextFragmentLanguageEditing from '../src/textfragmentlanguageediting'; -import TextFragmentLanguageCommand from '../src/textfragmentlanguagecommand'; import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor'; import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view'; +import TextFragmentLanguageEditing from '../src/textfragmentlanguageediting'; +import TextFragmentLanguageCommand from '../src/textfragmentlanguagecommand'; + describe( 'TextFragmentLanguageEditing', () => { let editor, model; @@ -24,6 +25,10 @@ describe( 'TextFragmentLanguageEditing', () => { } ); } ); + afterEach( async () => { + await editor.destroy(); + } ); + it( 'should have pluginName', () => { expect( TextFragmentLanguageEditing.pluginName ).to.equal( 'TextFragmentLanguageEditing' ); } ); @@ -107,21 +112,14 @@ describe( 'TextFragmentLanguageEditing', () => { ] }; - await createCustomConfigEditor( languageConfig ); + const customEditor = await VirtualTestEditor.create( { + plugins: [ TextFragmentLanguageEditing ], + language: languageConfig + } ); - expect( editor.config.get( 'language' ) ).to.deep.equal( languageConfig ); - } ); + expect( customEditor.config.get( 'language' ) ).to.deep.equal( languageConfig ); - function createCustomConfigEditor( languageConfig ) { - return VirtualTestEditor - .create( { - plugins: [ TextFragmentLanguageEditing, Paragraph ], - language: languageConfig - } ) - .then( newEditor => { - editor = newEditor; - model = editor.model; - } ); - } + customEditor.destroy(); + } ); } ); } ); diff --git a/packages/ckeditor5-language/tests/textfragmentlanguageui.js b/packages/ckeditor5-language/tests/textfragmentlanguageui.js index 9af850ddf99..ffee2443b8b 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguageui.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguageui.js @@ -7,12 +7,13 @@ import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; -import TextFragmentLanguageEditing from '../src/textfragmentlanguageediting'; -import TextFragmentLanguageUI from '../src/textfragmentlanguageui'; import DropdownView from '@ckeditor/ckeditor5-ui/src/dropdown/dropdownview'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; +import TextFragmentLanguageEditing from '../src/textfragmentlanguageediting'; +import TextFragmentLanguageUI from '../src/textfragmentlanguageui'; + describe( 'TextFragmentLanguageUI', () => { let editor, editorElement, dropdown, command; From f73c8f759582eca84790b58620109c3f00fd6ecc Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Fri, 5 Mar 2021 11:37:14 +0100 Subject: [PATCH 29/36] Use plain text instead of const for language attribute. --- .../src/textfragmentlanguagecommand.js | 20 +++++++++---------- .../src/textfragmentlanguageediting.js | 10 ++++------ .../tests/textfragmentlanguagecommand.js | 7 +++---- 3 files changed, 16 insertions(+), 21 deletions(-) diff --git a/packages/ckeditor5-language/src/textfragmentlanguagecommand.js b/packages/ckeditor5-language/src/textfragmentlanguagecommand.js index 6fad3103386..2809c8448c8 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguagecommand.js +++ b/packages/ckeditor5-language/src/textfragmentlanguagecommand.js @@ -10,8 +10,6 @@ import { Command } from 'ckeditor5/src/core'; import { stringifyLanguageAttribute } from './utils'; -const ATTRIBUTE_KEY = 'language'; - /** * The text fragment language command plugin. * @@ -45,7 +43,7 @@ export default class TextFragmentLanguageCommand extends Command { const doc = model.document; this.value = this._getValueFromFirstAllowedNode(); - this.isEnabled = model.schema.checkAttributeInSelection( doc.selection, ATTRIBUTE_KEY ); + this.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'language' ); } /** @@ -78,18 +76,18 @@ export default class TextFragmentLanguageCommand extends Command { model.change( writer => { if ( selection.isCollapsed ) { if ( value ) { - writer.setSelectionAttribute( ATTRIBUTE_KEY, value ); + writer.setSelectionAttribute( 'language', value ); } else { - writer.removeSelectionAttribute( ATTRIBUTE_KEY ); + writer.removeSelectionAttribute( 'language' ); } } else { - const ranges = model.schema.getValidRanges( selection.getRanges(), ATTRIBUTE_KEY ); + const ranges = model.schema.getValidRanges( selection.getRanges(), 'language' ); for ( const range of ranges ) { if ( value ) { - writer.setAttribute( ATTRIBUTE_KEY, value, range ); + writer.setAttribute( 'language', value, range ); } else { - writer.removeAttribute( ATTRIBUTE_KEY, range ); + writer.removeAttribute( 'language', range ); } } } @@ -109,13 +107,13 @@ export default class TextFragmentLanguageCommand extends Command { const selection = model.document.selection; if ( selection.isCollapsed ) { - return selection.getAttribute( ATTRIBUTE_KEY ) || false; + return selection.getAttribute( 'language' ) || false; } for ( const range of selection.getRanges() ) { for ( const item of range.getItems() ) { - if ( schema.checkAttribute( item, ATTRIBUTE_KEY ) ) { - return item.getAttribute( ATTRIBUTE_KEY ) || false; + if ( schema.checkAttribute( item, 'language' ) ) { + return item.getAttribute( 'language' ) || false; } } } diff --git a/packages/ckeditor5-language/src/textfragmentlanguageediting.js b/packages/ckeditor5-language/src/textfragmentlanguageediting.js index f433d022ad1..fc5d85c6387 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguageediting.js +++ b/packages/ckeditor5-language/src/textfragmentlanguageediting.js @@ -11,8 +11,6 @@ import { Plugin } from 'ckeditor5/src/core'; import TextFragmentLanguageCommand from './textfragmentlanguagecommand'; import { stringifyLanguageAttribute, parseLanguageAttribute } from './utils'; -const ATTRIBUTE_KEY = 'language'; - /** * The text fragment language editing. * @@ -52,8 +50,8 @@ export default class TextFragmentLanguageEditing extends Plugin { init() { const editor = this.editor; - editor.model.schema.extend( '$text', { allowAttributes: ATTRIBUTE_KEY } ); - editor.model.schema.setAttributeProperties( ATTRIBUTE_KEY, { + editor.model.schema.extend( '$text', { allowAttributes: 'language' } ); + editor.model.schema.setAttributeProperties( 'language', { copyOnEnter: true } ); @@ -70,7 +68,7 @@ export default class TextFragmentLanguageEditing extends Plugin { conversion.for( 'upcast' ).elementToAttribute( { model: { - key: ATTRIBUTE_KEY, + key: 'language', value: viewElement => { const languageCode = viewElement.getAttribute( 'lang' ); const textDirection = viewElement.getAttribute( 'dir' ); @@ -85,7 +83,7 @@ export default class TextFragmentLanguageEditing extends Plugin { } ); conversion.for( 'downcast' ).attributeToElement( { - model: ATTRIBUTE_KEY, + model: 'language', view: ( attributeValue, { writer } ) => { if ( !attributeValue ) { return; diff --git a/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js b/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js index f1194ea5d9f..3e28521b47e 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js @@ -9,7 +9,6 @@ import { setData, getData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model import TextFragmentLanguageCommand from '../src/textfragmentlanguagecommand'; describe( 'TextFragmentLanguageCommand', () => { - const attrKey = 'language'; let editor, command, model, doc, root; beforeEach( () => { @@ -48,7 +47,7 @@ describe( 'TextFragmentLanguageCommand', () => { describe( 'value', () => { it( 'includes language when collapsed selection has the attribute', () => { model.change( writer => { - writer.setSelectionAttribute( attrKey, 'fr:ltr' ); + writer.setSelectionAttribute( 'language', 'fr:ltr' ); } ); expect( command.value ).to.equal( 'fr:ltr' ); @@ -56,11 +55,11 @@ describe( 'TextFragmentLanguageCommand', () => { it( 'is false when collapsed selection does not have the attribute', () => { model.change( writer => { - writer.setSelectionAttribute( attrKey, 'fr:ltr' ); + writer.setSelectionAttribute( 'language', 'fr:ltr' ); } ); model.change( writer => { - writer.removeSelectionAttribute( attrKey ); + writer.removeSelectionAttribute( 'language' ); } ); expect( command.value ).to.be.false; From ad0d6797fd9c1e33987ebde44e49e7be46d4fa58 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 10 Mar 2021 08:22:20 +0100 Subject: [PATCH 30/36] Unified lang ISO. --- .../ckeditor5-language/src/textfragmentlanguage.js | 4 +--- .../src/textfragmentlanguagecommand.js | 2 +- packages/ckeditor5-language/src/utils.js | 10 +++++----- packages/ckeditor5-utils/src/language.js | 2 +- 4 files changed, 8 insertions(+), 10 deletions(-) diff --git a/packages/ckeditor5-language/src/textfragmentlanguage.js b/packages/ckeditor5-language/src/textfragmentlanguage.js index 2973c0c61d9..0412035441c 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguage.js +++ b/packages/ckeditor5-language/src/textfragmentlanguage.js @@ -65,9 +65,7 @@ export default class TextFragmentLanguage extends Plugin { * * The `title` property will be used by the text fragment language dropdown to render available options. * - * The `languageCode` property is used for the lang attribute in ISO 639 format. Language codes can be found - * [here](http://www.loc.gov/standards/iso639-2/php/English_list.php). You can use both 2-letter ISO-639-1 codes - * and 3-letter ISO-639-2 codes, though for consistency it is recommended to stick to ISO-639-1 2-letter codes. + * The `languageCode` property is used for the lang attribute in [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. * * You can also specify optional `textDirection` property indicating the reading direction of the language. * Correct values are `ltr` and `rtl`. When `textDirection` property is missing, the text fragment language feature will diff --git a/packages/ckeditor5-language/src/textfragmentlanguagecommand.js b/packages/ckeditor5-language/src/textfragmentlanguagecommand.js index 2809c8448c8..83fa956de32 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguagecommand.js +++ b/packages/ckeditor5-language/src/textfragmentlanguagecommand.js @@ -22,7 +22,7 @@ export default class TextFragmentLanguageCommand extends Command { * * : * - * * `languageCode` - The language code used for the lang attribute in ISO 639 format. + * * `languageCode` - The language code used for the lang attribute in [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. * * `textDirection` - One of the following values: `rtl` or `ltr`, indicating the reading direction of the language. * * See {@link module:core/editor/editorconfig~LanguageConfig#textFragmentLanguage text fragment config} diff --git a/packages/ckeditor5-language/src/utils.js b/packages/ckeditor5-language/src/utils.js index 54c21d46868..87536363c55 100644 --- a/packages/ckeditor5-language/src/utils.js +++ b/packages/ckeditor5-language/src/utils.js @@ -14,7 +14,7 @@ import { getLanguageDirection } from 'ckeditor5/src/utils'; * * : * - * * `languageCode` - The language code used for the lang attribute in ISO 639 format. + * * `languageCode` - The language code used for the lang attribute in [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. * * `textDirection` - One of the following values: `rtl` or `ltr`, indicating the reading direction of the language. * * See {@link module:core/editor/editorconfig~LanguageConfig#textFragmentLanguage text fragment config} @@ -22,7 +22,7 @@ import { getLanguageDirection } from 'ckeditor5/src/utils'; * * If `textDirection` argument is omitted, it will be automatically detected based on `languageCode`. * - * @param {String} languageCode The language code in ISO 639 format. + * @param {String} languageCode The language code in ISO 639-1 format. * @param {'ltr'|'rtl'} [textDirection] Language text direction. Automatically detected if omitted. * @returns {String} */ @@ -41,7 +41,7 @@ export function stringifyLanguageAttribute( languageCode, textDirection ) { * @returns {String} result.textDirection Language text direction. */ export function parseLanguageAttribute( str ) { - const [ languageCode, textDirection ] = str.split( ':' ); - - return { languageCode, textDirection }; + const [ languageCode, textDirection ] = str.split( ':' ); + + return { languageCode, textDirection }; } diff --git a/packages/ckeditor5-utils/src/language.js b/packages/ckeditor5-utils/src/language.js index ddc86921bf5..ab5bd0032df 100644 --- a/packages/ckeditor5-utils/src/language.js +++ b/packages/ckeditor5-utils/src/language.js @@ -18,7 +18,7 @@ const RTL_LANGUAGE_CODES = [ /** * Helps determine whether a language text direction is LTR or RTL. * - * @param {String} language The ISO 639 language code. + * @param {String} language The ISO 639-1 or ISO 639-2 language code. * @returns {'ltr'|'rtl'} */ export function getLanguageDirection( languageCode ) { From f194e57db2e8630e3ae0789f985228a2c423be35 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 10 Mar 2021 09:27:12 +0100 Subject: [PATCH 31/36] Added api docs. --- .../ckeditor5-language/docs/api/language.md | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) create mode 100644 packages/ckeditor5-language/docs/api/language.md diff --git a/packages/ckeditor5-language/docs/api/language.md b/packages/ckeditor5-language/docs/api/language.md new file mode 100644 index 00000000000..9f2cf24b95a --- /dev/null +++ b/packages/ckeditor5-language/docs/api/language.md @@ -0,0 +1,26 @@ +--- +category: api-reference +--- + +# CKEditor 5 Language feature + +[![npm version](https://badge.fury.io/js/%40ckeditor%2Fckeditor5-language.svg)](https://www.npmjs.com/package/@ckeditor/ckeditor5-language) + +This package implements language features support for CKEditor 5. + +## Installation + +``` +npm install --save @ckeditor/ckeditor5-language +``` + +## Contribute + +The source code of this package is available on GitHub in https://github.com/ckeditor/ckeditor5/tree/master/packages/ckeditor5-language. + +## External links + +* [`@ckeditor/ckeditor5-language` on npm](https://www.npmjs.com/package/@ckeditor/ckeditor5-language) +* [`ckeditor/ckeditor5-language` on GitHub](https://github.com/ckeditor/ckeditor5/tree/master/packages/ckeditor5-language) +* [Issue tracker](https://github.com/ckeditor/ckeditor5/issues) +* [Changelog](https://github.com/ckeditor/ckeditor5/blob/master/CHANGELOG.md) From d4aa3de37719556b7a9c9f11c2f01425e5d251d7 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Wed, 10 Mar 2021 09:48:56 +0100 Subject: [PATCH 32/36] Fixed API links. --- .../src/textfragmentlanguage.js | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/packages/ckeditor5-language/src/textfragmentlanguage.js b/packages/ckeditor5-language/src/textfragmentlanguage.js index 0412035441c..17e0b7e4aaa 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguage.js +++ b/packages/ckeditor5-language/src/textfragmentlanguage.js @@ -13,21 +13,6 @@ import TextFragmentLanguageEditing from './textfragmentlanguageediting'; import TextFragmentLanguageUI from './textfragmentlanguageui'; /** - * The text fragment language plugin. - * - * This feature allows setting language of parts of the content using simple dropdown button. For example, - * use it when you would like to indicate that the specific quote is in different language than the rest of the content. - * Refer to [WCAG 3.1.2 Language of Parts](https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html) specification - * to learn more. - * - * To change UI editor language, refer to {@glink features/ui-language setting the UI language} guide. - * - * For more information about this feature check the {@glink api/textfragmentlanguage package page}. - * - * This is a "glue" plugin which loads the {@link module:language/textfragmentlanguageediting~TextFragmentLanguageEditing - * text fragment language editing feature} and - * {@link module:language/textfragmentlanguageui~TextFragmentLanguageUI text fragment language UI feature}. - * * @extends module:core/plugin~Plugin */ export default class TextFragmentLanguage extends Plugin { @@ -47,8 +32,8 @@ export default class TextFragmentLanguage extends Plugin { } /** - * The available {@link module:language/textfragmentlanguage~TextFragmentLanguage -} options allowing setting language of parts of the content. + * The available {@link module:language/textfragmentlanguage~TextFragmentLanguage} + * options allowing setting language of parts of the content. * * Refer to [WCAG 3.1.2 Language of Parts](https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html) specification * to learn more. From ad2938cca7b7506e128fe8adbdc5d97e446a0b59 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Mon, 15 Mar 2021 09:15:10 +0100 Subject: [PATCH 33/36] Corrected docs. --- .../src/textfragmentlanguage.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/ckeditor5-language/src/textfragmentlanguage.js b/packages/ckeditor5-language/src/textfragmentlanguage.js index 17e0b7e4aaa..f91423a3d68 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguage.js +++ b/packages/ckeditor5-language/src/textfragmentlanguage.js @@ -13,6 +13,19 @@ import TextFragmentLanguageEditing from './textfragmentlanguageediting'; import TextFragmentLanguageUI from './textfragmentlanguageui'; /** + * The text fragment language feature. + * + * This feature allows setting a language of the editor's text part to support + * [WCAG 3.1.2 Language of Parts](https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html) specification. + * + * To change UI editor language, refer to {@glink features/ui-language setting the UI language} guide. + * + * For more information about this feature check the {@glink api/language package page}. + * + * This is a "glue" plugin which loads the + * {@link module:language/textfragmentlanguageediting~TextFragmentLanguageEditing text fragment editing feature} + * and {@link module:language/textfragmentlanguageui~TextFragmentLanguageUI text fragment language UI feature}. + * * @extends module:core/plugin~Plugin */ export default class TextFragmentLanguage extends Plugin { @@ -35,6 +48,8 @@ export default class TextFragmentLanguage extends Plugin { * The available {@link module:language/textfragmentlanguage~TextFragmentLanguage} * options allowing setting language of parts of the content. * + * This configuration option is available only with {@glink api/language language feature} enabled. + * * Refer to [WCAG 3.1.2 Language of Parts](https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html) specification * to learn more. * From 8b65b9b3c3e2fa0f44fce10d413ffac808c3367a Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Mon, 15 Mar 2021 09:25:47 +0100 Subject: [PATCH 34/36] Updated tests. --- .../tests/textfragmentlanguagecommand.js | 3 +++ .../ckeditor5-language/tests/textfragmentlanguageui.js | 10 +++++----- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js b/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js index 3e28521b47e..9b5a77622ba 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js @@ -4,6 +4,7 @@ */ import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor'; +import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import { setData, getData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import TextFragmentLanguageCommand from '../src/textfragmentlanguagecommand'; @@ -11,6 +12,8 @@ import TextFragmentLanguageCommand from '../src/textfragmentlanguagecommand'; describe( 'TextFragmentLanguageCommand', () => { let editor, command, model, doc, root; + testUtils.createSinonSandbox(); + beforeEach( () => { return ModelTestEditor .create() diff --git a/packages/ckeditor5-language/tests/textfragmentlanguageui.js b/packages/ckeditor5-language/tests/textfragmentlanguageui.js index ffee2443b8b..6f920e84c3f 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguageui.js +++ b/packages/ckeditor5-language/tests/textfragmentlanguageui.js @@ -137,9 +137,9 @@ describe( 'TextFragmentLanguageUI', () => { } ); } ); } ); -} ); -function getListViewItems( listView ) { - // Let's drop separator. - return listView.items.filter( item => item.children ); -} + function getListViewItems( listView ) { + // Let's drop separator. + return listView.items.filter( item => item.children ); + } +} ); From 9b5a0969caf99d53dabc478f6f0f818edc405a53 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Mon, 15 Mar 2021 13:22:52 +0100 Subject: [PATCH 35/36] Renamed feature to 'text part'. --- .../ckeditor5-clipboard/tests/dragdrop.js | 2 +- .../ckeditor5-language/lang/contexts.json | 6 ++-- packages/ckeditor5-language/src/index.js | 12 +++---- ...ragmentlanguage.js => textpartlanguage.js} | 32 +++++++++---------- ...ecommand.js => textpartlanguagecommand.js} | 8 ++--- ...eediting.js => textpartlanguageediting.js} | 18 +++++------ ...entlanguageui.js => textpartlanguageui.js} | 14 ++++---- packages/ckeditor5-language/src/utils.js | 2 +- ...entlanguage.html => textpartlanguage.html} | 0 ...ragmentlanguage.js => textpartlanguage.js} | 6 ++-- ...ragmentlanguage.md => textpartlanguage.md} | 2 +- .../tests/textfragmentlanguage.js | 18 ----------- .../tests/textpartlanguage.js | 18 +++++++++++ ...ecommand.js => textpartlanguagecommand.js} | 6 ++-- ...eediting.js => textpartlanguageediting.js} | 24 +++++++------- ...entlanguageui.js => textpartlanguageui.js} | 28 ++++++++-------- 16 files changed, 98 insertions(+), 98 deletions(-) rename packages/ckeditor5-language/src/{textfragmentlanguage.js => textpartlanguage.js} (64%) rename packages/ckeditor5-language/src/{textfragmentlanguagecommand.js => textpartlanguagecommand.js} (95%) rename packages/ckeditor5-language/src/{textfragmentlanguageediting.js => textpartlanguageediting.js} (77%) rename packages/ckeditor5-language/src/{textfragmentlanguageui.js => textpartlanguageui.js} (86%) rename packages/ckeditor5-language/tests/manual/{textfragmentlanguage.html => textpartlanguage.html} (100%) rename packages/ckeditor5-language/tests/manual/{textfragmentlanguage.js => textpartlanguage.js} (73%) rename packages/ckeditor5-language/tests/manual/{textfragmentlanguage.md => textpartlanguage.md} (91%) delete mode 100644 packages/ckeditor5-language/tests/textfragmentlanguage.js create mode 100644 packages/ckeditor5-language/tests/textpartlanguage.js rename packages/ckeditor5-language/tests/{textfragmentlanguagecommand.js => textpartlanguagecommand.js} (98%) rename packages/ckeditor5-language/tests/{textfragmentlanguageediting.js => textpartlanguageediting.js} (80%) rename packages/ckeditor5-language/tests/{textfragmentlanguageui.js => textpartlanguageui.js} (78%) diff --git a/packages/ckeditor5-clipboard/tests/dragdrop.js b/packages/ckeditor5-clipboard/tests/dragdrop.js index 40f4398dd91..cbe8744d4b2 100644 --- a/packages/ckeditor5-clipboard/tests/dragdrop.js +++ b/packages/ckeditor5-clipboard/tests/dragdrop.js @@ -809,7 +809,7 @@ describe( 'Drag and Drop', () => { ); } ); - it( 'should start dragging the selected text fragment', () => { + it( 'should start dragging the selected text part', () => { setModelData( model, '[foo]bar' ); diff --git a/packages/ckeditor5-language/lang/contexts.json b/packages/ckeditor5-language/lang/contexts.json index 4153131779a..6354c22ec7c 100644 --- a/packages/ckeditor5-language/lang/contexts.json +++ b/packages/ckeditor5-language/lang/contexts.json @@ -1,5 +1,5 @@ { - "Language": "Toolbar button tooltip for the text fragment language feature.", - "Choose language": "Default label for the text fragment language dropdown.", - "Remove language": "The label of the remove language option for the text fragment language dropdown." + "Language": "Toolbar button tooltip for the text part language feature.", + "Choose language": "Default label for the text part language dropdown.", + "Remove language": "The label of the remove language option for the text part language dropdown." } diff --git a/packages/ckeditor5-language/src/index.js b/packages/ckeditor5-language/src/index.js index 8d9c334e876..c8efa458dbe 100644 --- a/packages/ckeditor5-language/src/index.js +++ b/packages/ckeditor5-language/src/index.js @@ -7,12 +7,12 @@ * @module language */ -import TextFragmentLanguage from './textfragmentlanguage'; -import TextFragmentLanguageEditing from './textfragmentlanguageediting'; -import TextFragmentLanguageUI from './textfragmentlanguageui'; +import TextPartLanguage from './textpartlanguage'; +import TextPartLanguageEditing from './textpartlanguageediting'; +import TextPartLanguageUI from './textpartlanguageui'; export default { - TextFragmentLanguage, - TextFragmentLanguageEditing, - TextFragmentLanguageUI + TextPartLanguage, + TextPartLanguageEditing, + TextPartLanguageUI }; diff --git a/packages/ckeditor5-language/src/textfragmentlanguage.js b/packages/ckeditor5-language/src/textpartlanguage.js similarity index 64% rename from packages/ckeditor5-language/src/textfragmentlanguage.js rename to packages/ckeditor5-language/src/textpartlanguage.js index f91423a3d68..c05b35ac1a8 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguage.js +++ b/packages/ckeditor5-language/src/textpartlanguage.js @@ -4,16 +4,16 @@ */ /** - * @module language/textfragmentlanguage + * @module language/textpartlanguage */ import { Plugin } from 'ckeditor5/src/core'; -import TextFragmentLanguageEditing from './textfragmentlanguageediting'; -import TextFragmentLanguageUI from './textfragmentlanguageui'; +import TextPartLanguageEditing from './textpartlanguageediting'; +import TextPartLanguageUI from './textpartlanguageui'; /** - * The text fragment language feature. + * The text part language feature. * * This feature allows setting a language of the editor's text part to support * [WCAG 3.1.2 Language of Parts](https://www.w3.org/TR/UNDERSTANDING-WCAG20/meaning-other-lang-id.html) specification. @@ -23,29 +23,29 @@ import TextFragmentLanguageUI from './textfragmentlanguageui'; * For more information about this feature check the {@glink api/language package page}. * * This is a "glue" plugin which loads the - * {@link module:language/textfragmentlanguageediting~TextFragmentLanguageEditing text fragment editing feature} - * and {@link module:language/textfragmentlanguageui~TextFragmentLanguageUI text fragment language UI feature}. + * {@link module:language/textpartlanguageediting~TextPartLanguageEditing text part editing feature} + * and {@link module:language/textpartlanguageui~TextPartLanguageUI text part language UI feature}. * * @extends module:core/plugin~Plugin */ -export default class TextFragmentLanguage extends Plugin { +export default class TextPartLanguage extends Plugin { /** * @inheritDoc */ static get requires() { - return [ TextFragmentLanguageEditing, TextFragmentLanguageUI ]; + return [ TextPartLanguageEditing, TextPartLanguageUI ]; } /** * @inheritDoc */ static get pluginName() { - return 'TextFragmentLanguage'; + return 'TextPartLanguage'; } } /** - * The available {@link module:language/textfragmentlanguage~TextFragmentLanguage} + * The available {@link module:language/textpartlanguage~TextPartLanguage} * options allowing setting language of parts of the content. * * This configuration option is available only with {@glink api/language language feature} enabled. @@ -63,22 +63,22 @@ export default class TextFragmentLanguage extends Plugin { * { title: 'Spanish', languageCode: 'es' } * ]; * - * The `title` property will be used by the text fragment language dropdown to render available options. + * The `title` property will be used by the text part language dropdown to render available options. * * The `languageCode` property is used for the lang attribute in [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. * * You can also specify optional `textDirection` property indicating the reading direction of the language. - * Correct values are `ltr` and `rtl`. When `textDirection` property is missing, the text fragment language feature will + * Correct values are `ltr` and `rtl`. When `textDirection` property is missing, the text part language feature will * specify text direction by itself. * - * @member {Array.} - * module:core/editor/editorconfig~LanguageConfig#textFragmentLanguage + * @member {Array.} + * module:core/editor/editorconfig~LanguageConfig#textPartLanguage */ /** - * Text fragment language feature option descriptor. + * Text part language feature option descriptor. * - * @typedef {Object} module:language/textfragmentlanguage~TextFragmentLanguageOption + * @typedef {Object} module:language/textpartlanguage~TextPartLanguageOption * @property {String} title The user-readable title of the option. * @property {String} languageCode The language code in ISO 639 format. * @property {'ltr'|'rtl'} [textDirection] The language text direction. Automatically detected if omitted. diff --git a/packages/ckeditor5-language/src/textfragmentlanguagecommand.js b/packages/ckeditor5-language/src/textpartlanguagecommand.js similarity index 95% rename from packages/ckeditor5-language/src/textfragmentlanguagecommand.js rename to packages/ckeditor5-language/src/textpartlanguagecommand.js index 83fa956de32..349125fd5dc 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguagecommand.js +++ b/packages/ckeditor5-language/src/textpartlanguagecommand.js @@ -4,18 +4,18 @@ */ /** - * @module language/textfragmentlanguagecommand + * @module language/textpartlanguagecommand */ import { Command } from 'ckeditor5/src/core'; import { stringifyLanguageAttribute } from './utils'; /** - * The text fragment language command plugin. + * The text part language command plugin. * * @extends module:core/command~Command */ -export default class TextFragmentLanguageCommand extends Command { +export default class TextPartLanguageCommand extends Command { /** * If the selection starts in a language attribute the value is set to * the value of that language in a format: @@ -25,7 +25,7 @@ export default class TextFragmentLanguageCommand extends Command { * * `languageCode` - The language code used for the lang attribute in [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. * * `textDirection` - One of the following values: `rtl` or `ltr`, indicating the reading direction of the language. * - * See {@link module:core/editor/editorconfig~LanguageConfig#textFragmentLanguage text fragment config} + * See {@link module:core/editor/editorconfig~LanguageConfig#textPartLanguage text part config} * for more information about language properties. * * It is set to `false` otherwise. diff --git a/packages/ckeditor5-language/src/textfragmentlanguageediting.js b/packages/ckeditor5-language/src/textpartlanguageediting.js similarity index 77% rename from packages/ckeditor5-language/src/textfragmentlanguageediting.js rename to packages/ckeditor5-language/src/textpartlanguageediting.js index fc5d85c6387..2791a33f36f 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguageediting.js +++ b/packages/ckeditor5-language/src/textpartlanguageediting.js @@ -4,26 +4,26 @@ */ /** - * @module language/textfragmentlanguageediting + * @module language/textpartlanguageediting */ import { Plugin } from 'ckeditor5/src/core'; -import TextFragmentLanguageCommand from './textfragmentlanguagecommand'; +import TextPartLanguageCommand from './textpartlanguagecommand'; import { stringifyLanguageAttribute, parseLanguageAttribute } from './utils'; /** - * The text fragment language editing. + * The text part language editing. * - * Introduces the `'textFragmentLanguage'` command and the `'language'` model element attribute. + * Introduces the `'textPartLanguage'` command and the `'language'` model element attribute. * * @extends module:core/plugin~Plugin */ -export default class TextFragmentLanguageEditing extends Plugin { +export default class TextPartLanguageEditing extends Plugin { /** * @inheritDoc */ static get pluginName() { - return 'TextFragmentLanguageEditing'; + return 'TextPartLanguageEditing'; } /** @@ -32,11 +32,11 @@ export default class TextFragmentLanguageEditing extends Plugin { constructor( editor ) { super( editor ); - // Text fragment language options are only used to ensure that the feature works by default. + // Text part language options are only used to ensure that the feature works by default. // In the real usage it should be reconfigured by a developer. We are not providing // translations for `title` properties on purpose, as it's only an example configuration. editor.config.define( 'language', { - textFragmentLanguage: [ + textPartLanguage: [ { title: 'Arabic', languageCode: 'ar' }, { title: 'French', languageCode: 'fr' }, { title: 'Spanish', languageCode: 'es' } @@ -57,7 +57,7 @@ export default class TextFragmentLanguageEditing extends Plugin { this._defineConverters(); - editor.commands.add( 'textFragmentLanguage', new TextFragmentLanguageCommand( editor ) ); + editor.commands.add( 'textPartLanguage', new TextPartLanguageCommand( editor ) ); } /** diff --git a/packages/ckeditor5-language/src/textfragmentlanguageui.js b/packages/ckeditor5-language/src/textpartlanguageui.js similarity index 86% rename from packages/ckeditor5-language/src/textfragmentlanguageui.js rename to packages/ckeditor5-language/src/textpartlanguageui.js index 147e6c9e038..3607b632d1f 100644 --- a/packages/ckeditor5-language/src/textfragmentlanguageui.js +++ b/packages/ckeditor5-language/src/textpartlanguageui.js @@ -4,7 +4,7 @@ */ /** - * @module language/textfragmentlanguageui + * @module language/textpartlanguageui */ import { Plugin } from 'ckeditor5/src/core'; @@ -15,18 +15,18 @@ import { stringifyLanguageAttribute } from './utils'; import '../theme/language.css'; /** - * The text fragment language UI plugin. + * The text part language UI plugin. * * It introduces the `'language'` dropdown. * * @extends module:core/plugin~Plugin */ -export default class TextFragmentLanguageUI extends Plugin { +export default class TextPartLanguageUI extends Plugin { /** * @inheritDoc */ static get pluginName() { - return 'TextFragmentLanguageUI'; + return 'TextPartLanguageUI'; } /** @@ -35,17 +35,17 @@ export default class TextFragmentLanguageUI extends Plugin { init() { const editor = this.editor; const t = editor.t; - const options = editor.config.get( 'language.textFragmentLanguage' ); + const options = editor.config.get( 'language.textPartLanguage' ); const defaultTitle = t( 'Choose language' ); const removeTitle = t( 'Remove language' ); const dropdownTooltip = t( 'Language' ); // Register UI component. - editor.ui.componentFactory.add( 'textFragmentLanguage', locale => { + editor.ui.componentFactory.add( 'textPartLanguage', locale => { const itemDefinitions = new Collection(); const titles = {}; - const languageCommand = editor.commands.get( 'textFragmentLanguage' ); + const languageCommand = editor.commands.get( 'textPartLanguage' ); for ( const option of options ) { const def = { diff --git a/packages/ckeditor5-language/src/utils.js b/packages/ckeditor5-language/src/utils.js index 87536363c55..f50e4f2e602 100644 --- a/packages/ckeditor5-language/src/utils.js +++ b/packages/ckeditor5-language/src/utils.js @@ -17,7 +17,7 @@ import { getLanguageDirection } from 'ckeditor5/src/utils'; * * `languageCode` - The language code used for the lang attribute in [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. * * `textDirection` - One of the following values: `rtl` or `ltr`, indicating the reading direction of the language. * - * See {@link module:core/editor/editorconfig~LanguageConfig#textFragmentLanguage text fragment config} + * See {@link module:core/editor/editorconfig~LanguageConfig#textPartLanguage text part config} * for more information about language properties. * * If `textDirection` argument is omitted, it will be automatically detected based on `languageCode`. diff --git a/packages/ckeditor5-language/tests/manual/textfragmentlanguage.html b/packages/ckeditor5-language/tests/manual/textpartlanguage.html similarity index 100% rename from packages/ckeditor5-language/tests/manual/textfragmentlanguage.html rename to packages/ckeditor5-language/tests/manual/textpartlanguage.html diff --git a/packages/ckeditor5-language/tests/manual/textfragmentlanguage.js b/packages/ckeditor5-language/tests/manual/textpartlanguage.js similarity index 73% rename from packages/ckeditor5-language/tests/manual/textfragmentlanguage.js rename to packages/ckeditor5-language/tests/manual/textpartlanguage.js index b85eedf9543..2a00e82cdf3 100644 --- a/packages/ckeditor5-language/tests/manual/textfragmentlanguage.js +++ b/packages/ckeditor5-language/tests/manual/textpartlanguage.js @@ -7,15 +7,15 @@ import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor'; import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset'; -import TextFragmentLanguage from '../../src/textfragmentlanguage'; +import TextPartLanguage from '../../src/textpartlanguage'; ClassicEditor .create( document.querySelector( '#editor' ), { plugins: [ ArticlePluginSet, - TextFragmentLanguage + TextPartLanguage ], - toolbar: [ 'textFragmentLanguage', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ] + toolbar: [ 'textPartLanguage', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ] } ) .then( editor => { window.editor = editor; diff --git a/packages/ckeditor5-language/tests/manual/textfragmentlanguage.md b/packages/ckeditor5-language/tests/manual/textpartlanguage.md similarity index 91% rename from packages/ckeditor5-language/tests/manual/textfragmentlanguage.md rename to packages/ckeditor5-language/tests/manual/textpartlanguage.md index 18e1f752a81..8798aa43a9f 100644 --- a/packages/ckeditor5-language/tests/manual/textfragmentlanguage.md +++ b/packages/ckeditor5-language/tests/manual/textpartlanguage.md @@ -1,4 +1,4 @@ -## Text fragment language feature +## Text part language feature 1. The data should be loaded with four paragraph. Each paragraph style with applied language should be italic. 2. Put selection in each paragraph and check if language dropdown label is changing properly. diff --git a/packages/ckeditor5-language/tests/textfragmentlanguage.js b/packages/ckeditor5-language/tests/textfragmentlanguage.js deleted file mode 100644 index 2a800e967a5..00000000000 --- a/packages/ckeditor5-language/tests/textfragmentlanguage.js +++ /dev/null @@ -1,18 +0,0 @@ -/** - * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - -import TextFragmentLanguage from '../src/textfragmentlanguage'; -import TextFragmentLanguageEditing from '../src/textfragmentlanguageediting'; -import TextFragmentLanguageUI from '../src/textfragmentlanguageui'; - -describe( 'TextFragmentLanguage', () => { - it( 'should require TextFragmentLanguageEditing and TextFragmentLanguageUI', () => { - expect( TextFragmentLanguage.requires ).to.deep.equal( [ TextFragmentLanguageEditing, TextFragmentLanguageUI ] ); - } ); - - it( 'should be named', () => { - expect( TextFragmentLanguage.pluginName ).to.equal( 'TextFragmentLanguage' ); - } ); -} ); diff --git a/packages/ckeditor5-language/tests/textpartlanguage.js b/packages/ckeditor5-language/tests/textpartlanguage.js new file mode 100644 index 00000000000..2635237b635 --- /dev/null +++ b/packages/ckeditor5-language/tests/textpartlanguage.js @@ -0,0 +1,18 @@ +/** + * @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +import TextPartLanguage from '../src/textpartlanguage'; +import TextPartLanguageEditing from '../src/textpartlanguageediting'; +import TextPartLanguageUI from '../src/textpartlanguageui'; + +describe( 'TextPartLanguage', () => { + it( 'should require TextPartLanguageEditing and TextPartLanguageUI', () => { + expect( TextPartLanguage.requires ).to.deep.equal( [ TextPartLanguageEditing, TextPartLanguageUI ] ); + } ); + + it( 'should be named', () => { + expect( TextPartLanguage.pluginName ).to.equal( 'TextPartLanguage' ); + } ); +} ); diff --git a/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js b/packages/ckeditor5-language/tests/textpartlanguagecommand.js similarity index 98% rename from packages/ckeditor5-language/tests/textfragmentlanguagecommand.js rename to packages/ckeditor5-language/tests/textpartlanguagecommand.js index 9b5a77622ba..662945e9ab6 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguagecommand.js +++ b/packages/ckeditor5-language/tests/textpartlanguagecommand.js @@ -7,9 +7,9 @@ import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltestedit import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import { setData, getData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; -import TextFragmentLanguageCommand from '../src/textfragmentlanguagecommand'; +import TextPartLanguageCommand from '../src/textpartlanguagecommand'; -describe( 'TextFragmentLanguageCommand', () => { +describe( 'TextPartLanguageCommand', () => { let editor, command, model, doc, root; testUtils.createSinonSandbox(); @@ -23,7 +23,7 @@ describe( 'TextFragmentLanguageCommand', () => { doc = model.document; root = doc.getRoot(); - command = new TextFragmentLanguageCommand( editor ); + command = new TextPartLanguageCommand( editor ); model.schema.register( 'p', { inheritAllFrom: '$block' } ); model.schema.register( 'h1', { inheritAllFrom: '$block' } ); diff --git a/packages/ckeditor5-language/tests/textfragmentlanguageediting.js b/packages/ckeditor5-language/tests/textpartlanguageediting.js similarity index 80% rename from packages/ckeditor5-language/tests/textfragmentlanguageediting.js rename to packages/ckeditor5-language/tests/textpartlanguageediting.js index d290f2eda47..0d3a829b11a 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguageediting.js +++ b/packages/ckeditor5-language/tests/textpartlanguageediting.js @@ -8,16 +8,16 @@ import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtest import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view'; -import TextFragmentLanguageEditing from '../src/textfragmentlanguageediting'; -import TextFragmentLanguageCommand from '../src/textfragmentlanguagecommand'; +import TextPartLanguageEditing from '../src/textpartlanguageediting'; +import TextPartLanguageCommand from '../src/textpartlanguagecommand'; -describe( 'TextFragmentLanguageEditing', () => { +describe( 'TextPartLanguageEditing', () => { let editor, model; beforeEach( () => { return VirtualTestEditor .create( { - plugins: [ TextFragmentLanguageEditing, Paragraph ] + plugins: [ TextPartLanguageEditing, Paragraph ] } ) .then( newEditor => { editor = newEditor; @@ -30,11 +30,11 @@ describe( 'TextFragmentLanguageEditing', () => { } ); it( 'should have pluginName', () => { - expect( TextFragmentLanguageEditing.pluginName ).to.equal( 'TextFragmentLanguageEditing' ); + expect( TextPartLanguageEditing.pluginName ).to.equal( 'TextPartLanguageEditing' ); } ); it( 'should be loaded', () => { - expect( editor.plugins.get( TextFragmentLanguageEditing ) ).to.be.instanceOf( TextFragmentLanguageEditing ); + expect( editor.plugins.get( TextPartLanguageEditing ) ).to.be.instanceOf( TextPartLanguageEditing ); } ); it( 'should set proper schema rules', () => { @@ -49,9 +49,9 @@ describe( 'TextFragmentLanguageEditing', () => { } ); describe( 'command', () => { - it( 'should register textFragmentLanguage command', () => { - const command = editor.commands.get( 'textFragmentLanguage' ); - expect( command ).to.be.instanceOf( TextFragmentLanguageCommand ); + it( 'should register textPartLanguage command', () => { + const command = editor.commands.get( 'textPartLanguage' ); + expect( command ).to.be.instanceOf( TextPartLanguageCommand ); } ); } ); @@ -95,7 +95,7 @@ describe( 'TextFragmentLanguageEditing', () => { describe( 'config', () => { it( 'should be set', () => { - expect( editor.config.get( 'language.textFragmentLanguage' ) ).to.deep.equal( [ + expect( editor.config.get( 'language.textPartLanguage' ) ).to.deep.equal( [ { title: 'Arabic', languageCode: 'ar' }, { title: 'French', languageCode: 'fr' }, { title: 'Spanish', languageCode: 'es' } @@ -106,14 +106,14 @@ describe( 'TextFragmentLanguageEditing', () => { const languageConfig = { ui: 'pl', content: 'pl', - textFragmentLanguage: [ + textPartLanguage: [ { title: 'Hebrew', languageCode: 'he' }, { title: 'Polish', languageCode: 'pl' } ] }; const customEditor = await VirtualTestEditor.create( { - plugins: [ TextFragmentLanguageEditing ], + plugins: [ TextPartLanguageEditing ], language: languageConfig } ); diff --git a/packages/ckeditor5-language/tests/textfragmentlanguageui.js b/packages/ckeditor5-language/tests/textpartlanguageui.js similarity index 78% rename from packages/ckeditor5-language/tests/textfragmentlanguageui.js rename to packages/ckeditor5-language/tests/textpartlanguageui.js index 6f920e84c3f..fd082feb25c 100644 --- a/packages/ckeditor5-language/tests/textfragmentlanguageui.js +++ b/packages/ckeditor5-language/tests/textpartlanguageui.js @@ -11,10 +11,10 @@ import DropdownView from '@ckeditor/ckeditor5-ui/src/dropdown/dropdownview'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; import { setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; -import TextFragmentLanguageEditing from '../src/textfragmentlanguageediting'; -import TextFragmentLanguageUI from '../src/textfragmentlanguageui'; +import TextPartLanguageEditing from '../src/textpartlanguageediting'; +import TextPartLanguageUI from '../src/textpartlanguageui'; -describe( 'TextFragmentLanguageUI', () => { +describe( 'TextPartLanguageUI', () => { let editor, editorElement, dropdown, command; testUtils.createSinonSandbox(); @@ -25,14 +25,14 @@ describe( 'TextFragmentLanguageUI', () => { return ClassicTestEditor .create( editorElement, { - plugins: [ TextFragmentLanguageUI, TextFragmentLanguageEditing, Paragraph ], - toolbar: [ 'textFragmentLanguage' ] + plugins: [ TextPartLanguageUI, TextPartLanguageEditing, Paragraph ], + toolbar: [ 'textPartLanguage' ] } ) .then( newEditor => { editor = newEditor; - dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); + dropdown = editor.ui.componentFactory.create( 'textPartLanguage' ); - command = editor.commands.get( 'textFragmentLanguage' ); + command = editor.commands.get( 'textPartLanguage' ); // Set data so the commands will be enabled. setData( editor.model, '[foo]' ); @@ -47,7 +47,7 @@ describe( 'TextFragmentLanguageUI', () => { describe( 'init()', () => { it( 'should register options feature component', () => { - const dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); + const dropdown = editor.ui.componentFactory.create( 'textPartLanguage' ); expect( dropdown ).to.be.instanceOf( DropdownView ); expect( dropdown.buttonView.isEnabled ).to.be.true; @@ -56,9 +56,9 @@ describe( 'TextFragmentLanguageUI', () => { expect( dropdown.buttonView.tooltip ).to.equal( 'Language' ); } ); - it( 'should execute textFragmentLanguage command on model (no language selected)', () => { + it( 'should execute textPartLanguage command on model (no language selected)', () => { const executeSpy = testUtils.sinon.spy( command, 'execute' ); - const dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); + const dropdown = editor.ui.componentFactory.create( 'textPartLanguage' ); dropdown.fire( 'execute' ); @@ -67,9 +67,9 @@ describe( 'TextFragmentLanguageUI', () => { { languageCode: undefined, textDirection: undefined } ); } ); - it( 'should execute textFragmentLanguage command on model (language selected)', () => { + it( 'should execute textPartLanguage command on model (language selected)', () => { const executeSpy = testUtils.sinon.spy( command, 'execute' ); - const dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); + const dropdown = editor.ui.componentFactory.create( 'textPartLanguage' ); dropdown.languageCode = 'fr'; dropdown.textDirection = 'ltr'; @@ -82,7 +82,7 @@ describe( 'TextFragmentLanguageUI', () => { it( 'should focus view after command execution', () => { const focusSpy = testUtils.sinon.spy( editor.editing.view, 'focus' ); - const dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); + const dropdown = editor.ui.componentFactory.create( 'textPartLanguage' ); dropdown.languageCode = 'fr'; dropdown.fire( 'execute' ); @@ -91,7 +91,7 @@ describe( 'TextFragmentLanguageUI', () => { } ); it( 'should add custom CSS class to dropdown', () => { - const dropdown = editor.ui.componentFactory.create( 'textFragmentLanguage' ); + const dropdown = editor.ui.componentFactory.create( 'textPartLanguage' ); dropdown.render(); From d63ec7c3b8ddeecf3a0db9abc41d5ea5830d9c55 Mon Sep 17 00:00:00 2001 From: Jacek Bogdanski Date: Mon, 15 Mar 2021 13:35:21 +0100 Subject: [PATCH 36/36] Post renaming fixes. --- packages/ckeditor5-clipboard/tests/dragdrop.js | 2 +- packages/ckeditor5-language/src/textpartlanguagecommand.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/ckeditor5-clipboard/tests/dragdrop.js b/packages/ckeditor5-clipboard/tests/dragdrop.js index cbe8744d4b2..40f4398dd91 100644 --- a/packages/ckeditor5-clipboard/tests/dragdrop.js +++ b/packages/ckeditor5-clipboard/tests/dragdrop.js @@ -809,7 +809,7 @@ describe( 'Drag and Drop', () => { ); } ); - it( 'should start dragging the selected text part', () => { + it( 'should start dragging the selected text fragment', () => { setModelData( model, '[foo]bar' ); diff --git a/packages/ckeditor5-language/src/textpartlanguagecommand.js b/packages/ckeditor5-language/src/textpartlanguagecommand.js index 349125fd5dc..c277697d682 100644 --- a/packages/ckeditor5-language/src/textpartlanguagecommand.js +++ b/packages/ckeditor5-language/src/textpartlanguagecommand.js @@ -25,7 +25,7 @@ export default class TextPartLanguageCommand extends Command { * * `languageCode` - The language code used for the lang attribute in [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) format. * * `textDirection` - One of the following values: `rtl` or `ltr`, indicating the reading direction of the language. * - * See {@link module:core/editor/editorconfig~LanguageConfig#textPartLanguage text part config} + * See {@link module:core/editor/editorconfig~LanguageConfig#textPartLanguage text part language config} * for more information about language properties. * * It is set to `false` otherwise.