@ckeditor/ckeditor5-remove-format
Version:
Remove format feature for CKEditor 5.
196 lines (190 loc) • 6.59 kB
JavaScript
/**
* @license Copyright (c) 2003-2025, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-licensing-options
*/
import { Plugin, Command } from '@ckeditor/ckeditor5-core/dist/index.js';
import { IconRemoveFormat } from '@ckeditor/ckeditor5-icons/dist/index.js';
import { ButtonView, MenuBarMenuListItemButtonView } from '@ckeditor/ckeditor5-ui/dist/index.js';
import { first } from '@ckeditor/ckeditor5-utils/dist/index.js';
const REMOVE_FORMAT = 'removeFormat';
/**
* The remove format UI plugin. It registers the `'removeFormat'` button which can be
* used in the toolbar.
*/ class RemoveFormatUI extends Plugin {
/**
* @inheritDoc
*/ static get pluginName() {
return 'RemoveFormatUI';
}
/**
* @inheritDoc
*/ static get isOfficialPlugin() {
return true;
}
/**
* @inheritDoc
*/ init() {
const editor = this.editor;
editor.ui.componentFactory.add(REMOVE_FORMAT, ()=>{
const view = this._createButton(ButtonView);
view.set({
tooltip: true
});
return view;
});
editor.ui.componentFactory.add(`menuBar:${REMOVE_FORMAT}`, ()=>this._createButton(MenuBarMenuListItemButtonView));
}
/**
* Creates a button for remove format command to use either in toolbar or in menu bar.
*/ _createButton(ButtonClass) {
const editor = this.editor;
const locale = editor.locale;
const command = editor.commands.get(REMOVE_FORMAT);
const view = new ButtonClass(editor.locale);
const t = locale.t;
view.set({
label: t('Remove Format'),
icon: IconRemoveFormat
});
view.bind('isEnabled').to(command, 'isEnabled');
// Execute the command.
this.listenTo(view, 'execute', ()=>{
editor.execute(REMOVE_FORMAT);
editor.editing.view.focus();
});
return view;
}
}
/**
* The remove format command.
*
* It is used by the {@link module:remove-format/removeformat~RemoveFormat remove format feature}
* to clear the formatting in the selection.
*
* ```ts
* editor.execute( 'removeFormat' );
* ```
*/ class RemoveFormatCommand extends Command {
/**
* @inheritDoc
*/ refresh() {
const model = this.editor.model;
this.isEnabled = !!first(this._getFormattingItems(model.document.selection, model.schema));
}
/**
* @inheritDoc
*/ execute() {
const model = this.editor.model;
const schema = model.schema;
model.change((writer)=>{
for (const item of this._getFormattingItems(model.document.selection, schema)){
if (item.is('selection')) {
for (const attributeName of this._getFormattingAttributes(item, schema)){
writer.removeSelectionAttribute(attributeName);
}
} else {
// Workaround for items with multiple removable attributes. See
// https://github.com/ckeditor/ckeditor5-remove-format/pull/1#pullrequestreview-220515609
const itemRange = writer.createRangeOn(item);
for (const attributeName of this._getFormattingAttributes(item, schema)){
writer.removeAttribute(attributeName, itemRange);
}
}
}
});
}
/**
* Returns an iterable of items in a selection (including the selection itself) that have formatting model
* attributes to be removed by the feature.
*
* @param schema The schema describing the item.
*/ *_getFormattingItems(selection, schema) {
const itemHasRemovableFormatting = (item)=>{
return !!first(this._getFormattingAttributes(item, schema));
};
// Check formatting on selected items that are not blocks.
for (const curRange of selection.getRanges()){
for (const item of curRange.getItems()){
if (!schema.isBlock(item) && itemHasRemovableFormatting(item)) {
yield item;
}
}
}
// Check formatting from selected blocks.
for (const block of selection.getSelectedBlocks()){
if (itemHasRemovableFormatting(block)) {
yield block;
}
}
// Finally the selection might be formatted as well, so make sure to check it.
if (itemHasRemovableFormatting(selection)) {
yield selection;
}
}
/**
* Returns an iterable of formatting attributes of a given model item.
*
* **Note:** Formatting items have the `isFormatting` property set to `true`.
*
* @param schema The schema describing the item.
* @returns The names of formatting attributes found in a given item.
*/ *_getFormattingAttributes(item, schema) {
for (const [attributeName] of item.getAttributes()){
const attributeProperties = schema.getAttributeProperties(attributeName);
if (attributeProperties && attributeProperties.isFormatting) {
yield attributeName;
}
}
}
}
/**
* The remove format editing plugin.
*
* It registers the {@link module:remove-format/removeformatcommand~RemoveFormatCommand removeFormat} command.
*/ class RemoveFormatEditing extends Plugin {
/**
* @inheritDoc
*/ static get pluginName() {
return 'RemoveFormatEditing';
}
/**
* @inheritDoc
*/ static get isOfficialPlugin() {
return true;
}
/**
* @inheritDoc
*/ init() {
const editor = this.editor;
editor.commands.add('removeFormat', new RemoveFormatCommand(editor));
}
}
/**
* The remove format plugin.
*
* This is a "glue" plugin which loads the {@link module:remove-format/removeformatediting~RemoveFormatEditing}
* and {@link module:remove-format/removeformatui~RemoveFormatUI} plugins.
*
* For a detailed overview, check out the {@glink features/remove-format remove format} feature documentation.
*/ class RemoveFormat extends Plugin {
/**
* @inheritDoc
*/ static get requires() {
return [
RemoveFormatEditing,
RemoveFormatUI
];
}
/**
* @inheritDoc
*/ static get pluginName() {
return 'RemoveFormat';
}
/**
* @inheritDoc
*/ static get isOfficialPlugin() {
return true;
}
}
export { RemoveFormat, RemoveFormatEditing, RemoveFormatUI };
//# sourceMappingURL=index.js.map