diff --git a/.gitignore b/.gitignore index 575b07fcd7f..03e9b7e136a 100644 --- a/.gitignore +++ b/.gitignore @@ -42,6 +42,7 @@ packages/ckeditor5-engine/src/**/*.js packages/ckeditor5-enter/src/**/*.js packages/ckeditor5-essentials/src/**/*.js packages/ckeditor5-heading/src/**/*.js +packages/ckeditor5-highlight/src/**/*.js packages/ckeditor5-horizontal-line/src/**/*.js packages/ckeditor5-language/src/**/*.js packages/ckeditor5-list/src/**/*.js diff --git a/packages/ckeditor5-engine/src/index.ts b/packages/ckeditor5-engine/src/index.ts index 2b48279d17d..da87dba9efa 100644 --- a/packages/ckeditor5-engine/src/index.ts +++ b/packages/ckeditor5-engine/src/index.ts @@ -64,7 +64,7 @@ export { default as Range } from './model/range'; export { default as LiveRange } from './model/liverange'; export { default as LivePosition } from './model/liveposition'; export { default as Model } from './model/model'; -export { default as TreeWalker } from './model/treewalker'; +export { default as TreeWalker, type TreeWalkerValue } from './model/treewalker'; export { default as Element } from './model/element'; export { default as Position } from './model/position'; export { default as DocumentFragment } from './model/documentfragment'; diff --git a/packages/ckeditor5-highlight/src/highlight.js b/packages/ckeditor5-highlight/_src/highlight.js similarity index 100% rename from packages/ckeditor5-highlight/src/highlight.js rename to packages/ckeditor5-highlight/_src/highlight.js diff --git a/packages/ckeditor5-highlight/src/highlightcommand.js b/packages/ckeditor5-highlight/_src/highlightcommand.js similarity index 100% rename from packages/ckeditor5-highlight/src/highlightcommand.js rename to packages/ckeditor5-highlight/_src/highlightcommand.js diff --git a/packages/ckeditor5-highlight/src/highlightediting.js b/packages/ckeditor5-highlight/_src/highlightediting.js similarity index 100% rename from packages/ckeditor5-highlight/src/highlightediting.js rename to packages/ckeditor5-highlight/_src/highlightediting.js diff --git a/packages/ckeditor5-highlight/src/highlightui.js b/packages/ckeditor5-highlight/_src/highlightui.js similarity index 100% rename from packages/ckeditor5-highlight/src/highlightui.js rename to packages/ckeditor5-highlight/_src/highlightui.js diff --git a/packages/ckeditor5-highlight/src/index.js b/packages/ckeditor5-highlight/_src/index.js similarity index 100% rename from packages/ckeditor5-highlight/src/index.js rename to packages/ckeditor5-highlight/_src/index.js diff --git a/packages/ckeditor5-highlight/package.json b/packages/ckeditor5-highlight/package.json index 356ef883f04..44fc3ff43b5 100644 --- a/packages/ckeditor5-highlight/package.json +++ b/packages/ckeditor5-highlight/package.json @@ -10,7 +10,7 @@ "ckeditor5-plugin", "ckeditor5-dll" ], - "main": "src/index.js", + "main": "src/index.ts", "dependencies": { "ckeditor5": "^35.4.0" }, @@ -28,6 +28,7 @@ "@ckeditor/ckeditor5-theme-lark": "^35.4.0", "@ckeditor/ckeditor5-typing": "^35.4.0", "@ckeditor/ckeditor5-utils": "^35.4.0", + "typescript": "^4.8.4", "webpack": "^5.58.1", "webpack-cli": "^4.9.0" }, @@ -47,12 +48,16 @@ "files": [ "lang", "src", + "src/**/*.js", + "src/**/*.d.ts", "theme", "build", "ckeditor5-metadata.json", "CHANGELOG.md" ], "scripts": { - "dll:build": "webpack" + "dll:build": "webpack", + "build": "tsc -p ./tsconfig.release.json", + "postversion": "npm run build" } } diff --git a/packages/ckeditor5-highlight/src/highlight.ts b/packages/ckeditor5-highlight/src/highlight.ts new file mode 100644 index 00000000000..5ccd7b66c38 --- /dev/null +++ b/packages/ckeditor5-highlight/src/highlight.ts @@ -0,0 +1,225 @@ +/** + * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module highlight/highlight + */ + +import { Plugin, type PluginDependencies } from 'ckeditor5/src/core'; + +import HighlightEditing from './highlightediting'; +import HighlightUI from './highlightui'; + +/** + * The highlight plugin. + * + * For a detailed overview, check the {@glink features/highlight Highlight feature} documentation. + * + * This is a "glue" plugin which loads the {@link module:highlight/highlightediting~HighlightEditing} and + * {@link module:highlight/highlightui~HighlightUI} plugins. + */ +export default class Highlight extends Plugin { + /** + * @inheritDoc + */ + public static get requires(): PluginDependencies { + return [ HighlightEditing, HighlightUI ]; + } + + /** + * @inheritDoc + */ + public static get pluginName(): 'Highlight' { + return 'Highlight'; + } +} + +/** + * The highlight option descriptor. See {@link module:highlight/highlight~HighlightConfig} to learn more. + * + * ```ts + * { + * model: 'pinkMarker', + * class: 'marker-pink', + * title: 'Pink Marker', + * color: 'var(--ck-highlight-marker-pink)', + * type: 'marker' + * } + * ``` + */ +export interface HighlightOption { + + /** + * The user-readable title of the option. + */ + title: string; + + /** + * The unique attribute value in the model. + */ + model: string; + + /** + * The CSS `var()` used for the highlighter. The color is used in the user interface to represent the highlighter. + * There is a possibility to use the default color format like rgb, hex or hsl, but you need to care about the color of `` + * by adding CSS classes definition. + */ + color: string; + + /** + * The CSS class used on the `` element in the view. It should match the `color` setting. + */ + class: string; + + /** + * The type of highlighter: + * + * * `'marker'` – Uses the `color` as the `background-color` style, + * * `'pen'` – Uses the `color` as the font `color` style. + */ + type: 'marker' | 'pen'; +} + +/** + * The configuration of the {@link module:highlight/highlight~Highlight highlight feature}. + * ```ts + * ClassicEditor + * .create( editorElement, { + * highlight: ... // Highlight feature configuration. + * } ) + * .then( ... ) + * .catch( ... ); + * ``` + * See {@link module:core/editor/editorconfig~EditorConfig all editor options}. + */ +export interface HighlightConfig { + + /** + * The available highlight options. The default value is: + * ```ts + * options: [ + * { + * model: 'yellowMarker', + * class: 'marker-yellow', + * title: 'Yellow marker', + * color: 'var(--ck-highlight-marker-yellow)', + * type: 'marker' + * }, + * { + * model: 'greenMarker', + * class: 'marker-green', + * title: 'Green marker', + * color: 'var(--ck-highlight-marker-green)', + * type: 'marker' + * }, + * { + * model: 'pinkMarker', + * class: 'marker-pink', + * title: 'Pink marker', + * color: 'var(--ck-highlight-marker-pink)', + * type: 'marker' + * }, + * { + * model: 'blueMarker', + * class: 'marker-blue', + * title: 'Blue marker', + * color: 'var(--ck-highlight-marker-blue)', + * type: 'marker' + * }, + * { + * model: 'redPen', + * class: 'pen-red', + * title: 'Red pen', + * color: 'var(--ck-highlight-pen-red)', + * type: 'pen' + * }, + * { + * model: 'greenPen', + * class: 'pen-green', + * title: 'Green pen', + * color: 'var(--ck-highlight-pen-green)', + * type: 'pen' + * } + * ] + * ``` + * + * There are two types of highlighters available: + * + * * `'marker'` – Rendered as a `` element, styled with the `background-color`. + * * `'pen'` – Rendered as a `` element, styled with the font `color`. + * + * **Note**: The highlight feature provides a stylesheet with the CSS classes and corresponding colors defined + * as CSS variables. + * + * ```ts + * :root { + * --ck-highlight-marker-yellow: #fdfd77; + * --ck-highlight-marker-green: #63f963; + * --ck-highlight-marker-pink: #fc7999; + * --ck-highlight-marker-blue: #72cdfd; + * --ck-highlight-pen-red: #e91313; + * --ck-highlight-pen-green: #118800; + * } + * + * .marker-yellow { ... } + * .marker-green { ... } + * .marker-pink { ... } + * .marker-blue { ... } + * .pen-red { ... } + * .pen-green { ... } + * ``` + * + * It is possible to define the `color` property directly as `rgba(R, G, B, A)`, + * `#RRGGBB[AA]` or `hsla(H, S, L, A)`. In such situation, the color will **only** apply to the UI of + * the editor and the `` elements in the content must be styled by custom classes provided by + * a dedicated stylesheet. + * + * **Note**: It is recommended for the `color` property to correspond to the class in the content + * stylesheet because it represents the highlighter in the user interface of the editor. + * + * ```ts + * ClassicEditor + * .create( editorElement, { + * highlight: { + * options: [ + * { + * model: 'pinkMarker', + * class: 'marker-pink', + * title: 'Pink Marker', + * color: 'var(--ck-highlight-marker-pink)', + * type: 'marker' + * }, + * { + * model: 'redPen', + * class: 'pen-red', + * title: 'Red Pen', + * color: 'var(--ck-highlight-pen-red)', + * type: 'pen' + * }, + * ] + * } + * } ) + * .then( ... ) + * .catch( ... ); + * ``` + */ + options: Array; +} + +declare module '@ckeditor/ckeditor5-core' { + interface PluginsMap { + [ Highlight.pluginName ]: Highlight; + } + + interface EditorConfig { + + /** + * The configuration of the {@link module:highlight/highlight~Highlight} feature. + * + * Read more in {@link module:highlight/highlight~HighlightConfig}. + */ + highlight?: HighlightConfig; + } +} diff --git a/packages/ckeditor5-highlight/src/highlightcommand.ts b/packages/ckeditor5-highlight/src/highlightcommand.ts new file mode 100644 index 00000000000..5a6cd4e42b4 --- /dev/null +++ b/packages/ckeditor5-highlight/src/highlightcommand.ts @@ -0,0 +1,113 @@ +/** + * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module highlight/highlightcommand + */ + +import { Command } from 'ckeditor5/src/core'; +import type { TreeWalkerValue } from 'ckeditor5/src/engine'; + +/** + * The highlight command. It is used by the {@link module:highlight/highlightediting~HighlightEditing highlight feature} + * to apply the text highlighting. + * + * ```ts + * editor.execute( 'highlight', { value: 'greenMarker' } ); + * ``` + * + * **Note**: Executing the command without a value removes the attribute from the model. If the selection is collapsed + * inside a text with the highlight attribute, the command will remove the attribute from the entire range + * of that text. + */ +export default class HighlightCommand extends Command { + /** + * A value indicating whether the command is active. If the selection has some highlight attribute, + * it corresponds to the value of that attribute. + * + * @observable + * @readonly + */ + declare public value: string | undefined; + + /** + * @inheritDoc + */ + public override refresh(): void { + const model = this.editor.model; + const doc = model.document; + + this.value = doc.selection.getAttribute( 'highlight' ) as string | undefined; + this.isEnabled = model.schema.checkAttributeInSelection( doc.selection, 'highlight' ); + } + + /** + * Executes the command. + * + * @param options Options for the executed command. + * @param options.value The value to apply. + * + * @fires execute + */ + public override execute( options: { value?: string | null } = {} ): void { + const model = this.editor.model; + const document = model.document; + const selection = document.selection; + + const highlighter = options.value; + + model.change( writer => { + if ( selection.isCollapsed ) { + const position = selection.getFirstPosition()!; + + // When selection is inside text with `highlight` attribute. + if ( selection.hasAttribute( 'highlight' ) ) { + // Find the full highlighted range. + const isSameHighlight = ( value: TreeWalkerValue ) => { + return value.item.hasAttribute( 'highlight' ) && value.item.getAttribute( 'highlight' ) === this.value; + }; + + const highlightStart = position.getLastMatchingPosition( isSameHighlight, { direction: 'backward' } ); + const highlightEnd = position.getLastMatchingPosition( isSameHighlight ); + + const highlightRange = writer.createRange( highlightStart, highlightEnd ); + + // Then depending on current value... + if ( !highlighter || this.value === highlighter ) { + // ...remove attribute when passing highlighter different then current or executing "eraser". + + // If we're at the end of the highlighted range, we don't want to remove highlight of the range. + if ( !position.isEqual( highlightEnd ) ) { + writer.removeAttribute( 'highlight', highlightRange ); + } + + writer.removeSelectionAttribute( 'highlight' ); + } else { + // ...update `highlight` value. + + // If we're at the end of the highlighted range, we don't want to change the highlight of the range. + if ( !position.isEqual( highlightEnd ) ) { + writer.setAttribute( 'highlight', highlighter, highlightRange ); + } + + writer.setSelectionAttribute( 'highlight', highlighter ); + } + } else if ( highlighter ) { + writer.setSelectionAttribute( 'highlight', highlighter ); + } + } else { + const ranges = model.schema.getValidRanges( selection.getRanges(), 'highlight' ); + + for ( const range of ranges ) { + if ( highlighter ) { + writer.setAttribute( 'highlight', highlighter, range ); + } else { + writer.removeAttribute( 'highlight', range ); + } + } + } + } ); + } +} diff --git a/packages/ckeditor5-highlight/src/highlightediting.ts b/packages/ckeditor5-highlight/src/highlightediting.ts new file mode 100644 index 00000000000..9c4d26327c0 --- /dev/null +++ b/packages/ckeditor5-highlight/src/highlightediting.ts @@ -0,0 +1,139 @@ +/** + * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module highlight/highlightediting + */ + +import { Plugin, type Editor } from 'ckeditor5/src/core'; + +import HighlightCommand from './highlightcommand'; +import type { HighlightOption } from './highlight'; + +/** + * The highlight editing feature. It introduces the {@link module:highlight/highlightcommand~HighlightCommand command} and the `highlight` + * attribute in the {@link module:engine/model/model~Model model} which renders in the {@link module:engine/view/view view} + * as a `` element with a `class` attribute (`...`) depending + * on the {@link module:highlight/highlight~HighlightConfig configuration}. + */ +export default class HighlightEditing extends Plugin { + /** + * @inheritDoc + */ + public static get pluginName(): 'HighlightEditing' { + return 'HighlightEditing'; + } + + /** + * @inheritDoc + */ + constructor( editor: Editor ) { + super( editor ); + + editor.config.define( 'highlight', { + options: [ + { + model: 'yellowMarker', + class: 'marker-yellow', + title: 'Yellow marker', + color: 'var(--ck-highlight-marker-yellow)', + type: 'marker' + }, + { + model: 'greenMarker', + class: 'marker-green', + title: 'Green marker', + color: 'var(--ck-highlight-marker-green)', + type: 'marker' + }, + { + model: 'pinkMarker', + class: 'marker-pink', + title: 'Pink marker', + color: 'var(--ck-highlight-marker-pink)', + type: 'marker' + }, + { + model: 'blueMarker', + class: 'marker-blue', + title: 'Blue marker', + color: 'var(--ck-highlight-marker-blue)', + type: 'marker' + }, + { + model: 'redPen', + class: 'pen-red', + title: 'Red pen', + color: 'var(--ck-highlight-pen-red)', + type: 'pen' + }, + { + model: 'greenPen', + class: 'pen-green', + title: 'Green pen', + color: 'var(--ck-highlight-pen-green)', + type: 'pen' + } + ] + } ); + } + + /** + * @inheritDoc + */ + public init(): void { + const editor = this.editor; + + // Allow highlight attribute on text nodes. + editor.model.schema.extend( '$text', { allowAttributes: 'highlight' } ); + + const options = editor.config.get( 'highlight.options' )!; + + // Set-up the two-way conversion. + editor.conversion.attributeToElement( _buildDefinition( options ) ); + + editor.commands.add( 'highlight', new HighlightCommand( editor ) ); + } +} + +/** + * Converts the options array to a converter definition. + * + * @param options An array with configured options. + */ +function _buildDefinition( options: Array ): HighlightConverterDefinition { + const definition: HighlightConverterDefinition = { + model: { + key: 'highlight', + values: [] + }, + view: {} + }; + + for ( const option of options ) { + definition.model.values.push( option.model ); + definition.view[ option.model ] = { + name: 'mark', + classes: option.class + }; + } + + return definition; +} + +type HighlightConverterDefinition = { + model: { key: string; values: Array }; + view: Record; +}; + +declare module '@ckeditor/ckeditor5-core' { + interface CommandsMap { + highlight: HighlightCommand; + } + + interface PluginsMap { + [ HighlightEditing.pluginName ]: HighlightEditing; + } +} diff --git a/packages/ckeditor5-highlight/src/highlightui.ts b/packages/ckeditor5-highlight/src/highlightui.ts new file mode 100644 index 00000000000..fbde64d1361 --- /dev/null +++ b/packages/ckeditor5-highlight/src/highlightui.ts @@ -0,0 +1,282 @@ +/** + * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module highlight/highlightui + */ + +import { Plugin, icons } from 'ckeditor5/src/core'; +import { + ButtonView, + SplitButtonView, + ToolbarSeparatorView, + createDropdown, + addToolbarToDropdown, + type DropdownView +} from 'ckeditor5/src/ui'; + +import markerIcon from './../theme/icons/marker.svg'; +import penIcon from './../theme/icons/pen.svg'; +import type { HighlightOption } from './highlight'; + +import './../theme/highlight.css'; + +/** + * The default highlight UI plugin. It introduces: + * + * * The `'highlight'` dropdown, + * * The `'removeHighlight'` and `'highlight:*'` buttons. + * + * The default configuration includes the following buttons: + * + * * `'highlight:yellowMarker'` + * * `'highlight:greenMarker'` + * * `'highlight:pinkMarker'` + * * `'highlight:blueMarker'` + * * `'highlight:redPen'` + * * `'highlight:greenPen'` + * + * See the {@link module:highlight/highlight~HighlightConfig#options configuration} to learn more + * about the defaults. + */ +export default class HighlightUI extends Plugin { + /** + * Returns the localized option titles provided by the plugin. + * + * The following localized titles corresponding with default + * {@link module:highlight/highlight~HighlightConfig#options} are available: + * + * * `'Yellow marker'`, + * * `'Green marker'`, + * * `'Pink marker'`, + * * `'Blue marker'`, + * * `'Red pen'`, + * * `'Green pen'`. + */ + public get localizedOptionTitles(): Record { + const t = this.editor.t; + + return { + 'Yellow marker': t( 'Yellow marker' ), + 'Green marker': t( 'Green marker' ), + 'Pink marker': t( 'Pink marker' ), + 'Blue marker': t( 'Blue marker' ), + 'Red pen': t( 'Red pen' ), + 'Green pen': t( 'Green pen' ) + }; + } + + /** + * @inheritDoc + */ + public static get pluginName(): 'HighlightUI' { + return 'HighlightUI'; + } + + /** + * @inheritDoc + */ + public init(): void { + const options = this.editor.config.get( 'highlight.options' )!; + + for ( const option of options ) { + this._addHighlighterButton( option ); + } + + this._addRemoveHighlightButton(); + + this._addDropdown( options ); + } + + /** + * Creates the "Remove highlight" button. + */ + private _addRemoveHighlightButton(): void { + const t = this.editor.t; + const command = this.editor.commands.get( 'highlight' )!; + + this._addButton( 'removeHighlight', t( 'Remove highlight' ), icons.eraser, null, button => { + button.bind( 'isEnabled' ).to( command, 'isEnabled' ); + } ); + } + + /** + * Creates a toolbar button from the provided highlight option. + */ + private _addHighlighterButton( option: HighlightOption ) { + const command = this.editor.commands.get( 'highlight' )!; + + // TODO: change naming + this._addButton( 'highlight:' + option.model, option.title, getIconForType( option.type ), option.model, decorateHighlightButton ); + + function decorateHighlightButton( button: ButtonView ) { + button.bind( 'isEnabled' ).to( command, 'isEnabled' ); + button.bind( 'isOn' ).to( command, 'value', value => value === option.model ); + button.iconView.fillColor = option.color; + button.isToggleable = true; + } + } + + /** + * Internal method for creating highlight buttons. + * + * @param name The name of the button. + * @param label The label for the button. + * @param icon The button icon. + * @param value The `value` property passed to the executed command. + * @param decorateButton A callback getting ButtonView instance so that it can be further customized. + */ + private _addButton( name: string, label: string, icon: string, value: string | null, decorateButton: ( button: ButtonView ) => void ) { + const editor = this.editor; + + editor.ui.componentFactory.add( name, locale => { + const buttonView = new ButtonView( locale ); + + const localized = this.localizedOptionTitles[ label ] ? this.localizedOptionTitles[ label ] : label; + + buttonView.set( { + label: localized, + icon, + tooltip: true + } ); + + buttonView.on( 'execute', () => { + editor.execute( 'highlight', { value } ); + editor.editing.view.focus(); + } ); + + // Add additional behavior for buttonView. + decorateButton( buttonView ); + + return buttonView; + } ); + } + + /** + * Creates the split button dropdown UI from the provided highlight options. + */ + private _addDropdown( options: Array ) { + const editor = this.editor; + const t = editor.t; + const componentFactory = editor.ui.componentFactory; + + const startingHighlighter = options[ 0 ]; + + const optionsMap = options.reduce( ( retVal, option ) => { + retVal[ option.model ] = option; + + return retVal; + }, {} as Record ); + + componentFactory.add( 'highlight', locale => { + const command = editor.commands.get( 'highlight' )!; + const dropdownView = createDropdown( locale, SplitButtonView ); + const splitButtonView = dropdownView.buttonView as HighlightSplitButtonView; + + splitButtonView.set( { + label: t( 'Highlight' ), + tooltip: true, + // Holds last executed highlighter. + lastExecuted: startingHighlighter.model, + // Holds current highlighter to execute (might be different then last used). + commandValue: startingHighlighter.model, + isToggleable: true + } ); + + // Dropdown button changes to selection (command.value): + // - If selection is in highlight it get active highlight appearance (icon, color) and is activated. + // - Otherwise it gets appearance (icon, color) of last executed highlight. + splitButtonView.bind( 'icon' ).to( command, 'value', value => getIconForType( getActiveOption( value, 'type' ) ) ); + splitButtonView.bind( 'color' ).to( command, 'value', value => getActiveOption( value, 'color' ) ); + splitButtonView.bind( 'commandValue' ).to( command, 'value', value => getActiveOption( value, 'model' ) ); + splitButtonView.bind( 'isOn' ).to( command, 'value', value => !!value ); + + splitButtonView.delegate( 'execute' ).to( dropdownView ); + + // Create buttons array. + const buttonsCreator = () => { + const buttons = options.map( option => { + // Get existing highlighter button. + const buttonView = componentFactory.create( 'highlight:' + option.model ); + + // Update lastExecutedHighlight on execute. + this.listenTo( buttonView, 'execute', () => { + ( dropdownView.buttonView as HighlightSplitButtonView ).set( { lastExecuted: option.model } ); + } ); + + return buttonView; + } ); + + // Add separator and eraser buttons to dropdown. + buttons.push( new ToolbarSeparatorView() ); + buttons.push( componentFactory.create( 'removeHighlight' ) ); + + return buttons; + }; + + // Make toolbar button enabled when any button in dropdown is enabled before adding separator and eraser. + dropdownView.bind( 'isEnabled' ).to( command, 'isEnabled' ); + + addToolbarToDropdown( dropdownView, buttonsCreator, { + enableActiveItemFocusOnDropdownOpen: true, + ariaLabel: t( 'Text highlight toolbar' ) + } ); + bindToolbarIconStyleToActiveColor( dropdownView ); + + // Execute current action from dropdown's split button action button. + splitButtonView.on( 'execute', () => { + editor.execute( 'highlight', { value: splitButtonView.commandValue } ); + } ); + + // Focus the editable after executing the command. + // It overrides a default behaviour where the focus is moved to the dropdown button (#12125). + this.listenTo( dropdownView, 'execute', () => { + editor.editing.view.focus(); + } ); + + /** + * Returns active highlighter option depending on current command value. + * If current is not set or it is the same as last execute this method will return the option key (like icon or color) + * of last executed highlighter. Otherwise it will return option key for current one. + */ + function getActiveOption( current: string | undefined, key: Key ): HighlightOption[ Key ] { + const whichHighlighter = !current || + current === splitButtonView.lastExecuted ? splitButtonView.lastExecuted : current; + + return optionsMap[ whichHighlighter! ][ key ]; + } + + return dropdownView; + } ); + } +} + +/** + * Extends split button icon style to reflect last used button style. + */ +function bindToolbarIconStyleToActiveColor( dropdownView: DropdownView ): void { + const actionView = ( dropdownView.buttonView as HighlightSplitButtonView ).actionView; + + actionView.iconView.bind( 'fillColor' ).to( ( dropdownView.buttonView! as HighlightSplitButtonView ), 'color' ); +} + +/** + * Returns icon for given highlighter type. + */ +function getIconForType( type: 'marker' | 'pen' ) { + return type === 'marker' ? markerIcon : penIcon; +} + +type HighlightSplitButtonView = SplitButtonView & { + lastExecuted: string; + commandValue: string; + color: string; +}; + +declare module '@ckeditor/ckeditor5-core' { + interface PluginsMap { + [ HighlightUI.pluginName ]: HighlightUI; + } +} diff --git a/packages/ckeditor5-highlight/src/index.ts b/packages/ckeditor5-highlight/src/index.ts new file mode 100644 index 00000000000..ef13f1557b0 --- /dev/null +++ b/packages/ckeditor5-highlight/src/index.ts @@ -0,0 +1,12 @@ +/** + * @license Copyright (c) 2003-2023, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module highlight + */ + +export { default as Highlight } from './highlight'; +export { default as HighlightEditing } from './highlightediting'; +export { default as HighlightUI } from './highlightui'; diff --git a/packages/ckeditor5-highlight/tsconfig.json b/packages/ckeditor5-highlight/tsconfig.json new file mode 100644 index 00000000000..9d4c891939c --- /dev/null +++ b/packages/ckeditor5-highlight/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "ckeditor5/tsconfig.json", + "include": [ + "src", + "../../typings" + ] +} diff --git a/packages/ckeditor5-highlight/tsconfig.release.json b/packages/ckeditor5-highlight/tsconfig.release.json new file mode 100644 index 00000000000..6d2d43909f9 --- /dev/null +++ b/packages/ckeditor5-highlight/tsconfig.release.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.release.json", + "include": [ + "./src/", + "../../typings/" + ], + "exclude": [ + "./tests/" + ] +}