@rickx/ckeditor5-line-height
Version:
LineHeight plugin for CKEditor5
273 lines (264 loc) • 10.1 kB
JavaScript
import { Command, first, Plugin, createDropdown, addListToDropdown, Collection, ViewModel } from 'ckeditor5';
var lineHeightIcon = "xml version=\"1.0\" standalone=\"no\"?>getOptionDefinition(item)).filter((option)=>!!option);
}
function buildDefinition(modelAttributeKey, options) {
const definition = {
model: {
key: modelAttributeKey,
values: []
},
view: {}
};
for (const option of options){
definition.model.values.push(option.model);
definition.view[option.model] = {
key: 'style',
value: {
'line-height': option.model
}
};
}
return definition;
}
/**
* We treat `definition` as completed if it is an object that contains `title`, `model` and `view` values.
*/ function isFullItemDefinition(definition) {
return definition.title && definition.model && definition.view;
}
/**
* The lineHeight command plugin.
*/ class LineHeightCommand extends Command {
static get pluginName() {
return 'LineHeightEditing';
}
constructor(editor){
super(editor);
}
refresh() {
const model = this.editor.model;
const document = model.document;
const firstBlock = first(document.selection.getSelectedBlocks());
// As first check whether to enable or disable the command as the value will always be false if the command cannot be enabled.
this.isEnabled = !!firstBlock && this._canSetLineHeight(firstBlock);
this.value = this.isEnabled && firstBlock.hasAttribute(LINE_HEIGHT) ? firstBlock.getAttribute(LINE_HEIGHT) : 'default';
}
execute(options = {}) {
const editor = this.editor;
const model = editor.model;
const document = model.document;
const value = options.value;
model.change((writer)=>{
const blocks = Array.from(document.selection.getSelectedBlocks()).filter((block)=>this._canSetLineHeight(block));
const currentLineHeight = blocks[0].getAttribute(LINE_HEIGHT);
const removeLineHeight = currentLineHeight === value || !value;
if (removeLineHeight) removeLineHeightFromSelection(blocks, writer);
else setLineHeightOnSelection(blocks, writer, value);
});
}
_canSetLineHeight(block) {
return this.editor.model.schema.checkAttribute(block, LINE_HEIGHT);
}
}
function removeLineHeightFromSelection(blocks, writer) {
for (const block of blocks)writer.removeAttribute(LINE_HEIGHT, block);
}
function setLineHeightOnSelection(blocks, writer, lineHeight) {
for (const block of blocks)writer.setAttribute(LINE_HEIGHT, lineHeight, block);
}
class LineHeightEditing extends Plugin {
static get pluginName() {
return 'LineHeightEditing';
}
constructor(editor){
super(editor);
// Define default configuration using named presets.
editor.config.define(LINE_HEIGHT, {
options: [
'default',
1,
1.1,
1.2,
1.3,
1.4,
1.5,
1.6,
2,
2.5
],
supportAllValues: false
});
}
init() {
const editor = this.editor;
const schema = editor.model.schema;
const supportAllValues = editor.config.get('lineHeight.supportAllValues');
const options = normalizeOptions(editor.config.get('lineHeight.options')).filter((option)=>option.model);
// Allow LineHeight attribute on all blocks.
schema.extend('$block', {
allowAttributes: LINE_HEIGHT
});
editor.model.schema.setAttributeProperties(LINE_HEIGHT, {
isFormatting: true
});
// Define view to model conversion.
const definition = buildDefinition(LINE_HEIGHT, options);
if (supportAllValues) {
this._prepareAnyValueConverters();
} else {
editor.conversion.attributeToAttribute(definition);
}
// Add LineHeight Command.
editor.commands.add(LINE_HEIGHT, new LineHeightCommand(editor));
}
/**
* These converters enable keeping any value found as `style="line-height: *"` as a value of an attribute on a text even
* if it is not defined in the plugin configuration.
*/ _prepareAnyValueConverters() {
const editor = this.editor;
editor.conversion.for('downcast').attributeToAttribute({
model: LINE_HEIGHT,
view: (attributeValue)=>({
key: 'style',
value: {
'line-height': attributeValue
}
})
});
editor.conversion.for('upcast').elementToAttribute({
model: {
key: LINE_HEIGHT,
value: (viewElement)=>viewElement.getStyle('line-height')
},
view: {
name: 'p',
styles: {
'line-height': /.*/
}
}
});
}
}
class LineHeightUI extends Plugin {
static get pluginName() {
return 'LineHeightUI';
}
init() {
const editor = this.editor;
const componentFactory = editor.ui.componentFactory;
const t = editor.t;
const options = this._getLocalizedOptions();
const command = editor.commands.get(LINE_HEIGHT);
// Register UI component.
componentFactory.add(LINE_HEIGHT, (locale)=>{
const dropdownView = createDropdown(locale);
addListToDropdown(dropdownView, _prepareListOptions(options, command));
// Create dropdown model.
dropdownView.buttonView.set({
label: t('Line Height'),
icon: lineHeightIcon,
tooltip: true
});
dropdownView.extendTemplate({
attributes: {
class: [
'ck-line-height-dropdown'
]
}
});
dropdownView.bind('isEnabled').to(command);
// Execute command when an item from the dropdown is selected.
this.listenTo(dropdownView, 'execute', (evt)=>{
editor.execute(evt.source.commandName, {
value: evt.source.commandParam
});
editor.editing.view.focus();
});
return dropdownView;
});
}
_getLocalizedOptions() {
const editor = this.editor;
const t = editor.t;
const localizedTitles = {
Default: t('Default')
};
const options = normalizeOptions(editor.config.get(LINE_HEIGHT).options);
return options.map((option)=>{
const title = localizedTitles[option.title];
if (title && title !== option.title) {
// Clone the option to avoid altering the original `namedPresets` from `./utils.js`.
option = Object.assign({}, option, {
title
});
}
return option;
});
}
}
// Prepares LineHeight dropdown items.
function _prepareListOptions(options, command) {
const itemDefinitions = new Collection();
for (const option of options){
const def = {
type: 'button',
model: new ViewModel({
commandName: LINE_HEIGHT,
commandParam: option.model,
label: option.title,
class: 'ck-line-height-option',
withText: true
})
};
def.model.bind('isOn').to(command, 'value', (value)=>{
return value === option.model;
});
// Add the option to the collection.
itemDefinitions.add(def);
}
return itemDefinitions;
}
class LineHeight extends Plugin {
static get requires() {
return [
LineHeightEditing,
LineHeightUI
];
}
static get pluginName() {
return 'LineHeight';
}
}
const icons = {
lineHeight: lineHeightIcon
};
export { LINE_HEIGHT, LineHeight, LineHeightEditing, LineHeightUI, icons };
//# sourceMappingURL=index.js.map