Skip to content

Commit

Permalink
Merge pull request #14271 from ckeditor/ck/14216-rename-htmlAttribute…
Browse files Browse the repository at this point in the history
…s-to-htmlXAttributes

Other (html-support): Change `htmlAttributes` to `htmlXAttributes` where X represents the name of the view element. See #14216.

MINOR BREAKING CHANGE (html-support): The `htmlAttributes` model property has been replaced by `htmlXAttributes`, where "X" represents the name of the view element. Clients will need to modify their code accordingly by replacing all instances of `htmlAttributes` with `htmlXAttributes` for the respective view elements.
  • Loading branch information
arkflpc committed May 30, 2023
2 parents 53f0dc2 + 82877ea commit a04cbd3
Show file tree
Hide file tree
Showing 27 changed files with 570 additions and 493 deletions.
45 changes: 30 additions & 15 deletions packages/ckeditor5-html-support/src/converters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import {
setViewAttributes,
mergeViewElementAttributes,
updateViewAttributes,
getHtmlAttributeName,
type GHSViewAttributes
} from './utils';
import type DataFilter from './datafilter';
Expand Down Expand Up @@ -62,7 +63,7 @@ export function toObjectWidgetConverter(
const widgetLabel = t( 'HTML object' );

const viewElement = createObjectView( viewName!, modelElement, writer );
const viewAttributes = modelElement.getAttribute( 'htmlAttributes' );
const viewAttributes = modelElement.getAttribute( getHtmlAttributeName( viewName! ) );

writer.addClass( 'html-object-embed__content', viewElement );

Expand Down Expand Up @@ -162,7 +163,7 @@ export function attributeToViewInlineConverter( { priority, view: viewName }: Da
/**
* View-to-model conversion helper preserving allowed attributes on block element.
*
* All matched attributes will be preserved on `htmlAttributes` attribute.
* All matched attributes will be preserved on `html*Attributes` attribute.
*
* @returns Returns a conversion callback.
*/
Expand All @@ -179,31 +180,45 @@ export function viewToModelBlockAttributeConverter( { view: viewName }: DataSche

const viewAttributes = dataFilter.processViewAttributes( data.viewItem, conversionApi );

if ( viewAttributes ) {
conversionApi.writer.setAttribute( 'htmlAttributes', viewAttributes, data.modelRange );
if ( !viewAttributes ) {
return;
}

conversionApi.writer.setAttribute(
getHtmlAttributeName( data.viewItem.name ),
viewAttributes,
data.modelRange
);
}, { priority: 'low' } );
};
}

/**
* Model-to-view conversion helper applying attributes preserved in `htmlAttributes` attribute
* Model-to-view conversion helper applying attributes preserved in `html*Attributes` attribute
* for block elements.
*
* @returns Returns a conversion callback.
*/
export function modelToViewBlockAttributeConverter( { model: modelName }: DataSchemaBlockElementDefinition ) {
export function modelToViewBlockAttributeConverter( { view: viewName, model: modelName }: DataSchemaBlockElementDefinition ) {
return ( dispatcher: DowncastDispatcher ): void => {
dispatcher.on<DowncastAttributeEvent>( `attribute:htmlAttributes:${ modelName }`, ( evt, data, conversionApi ) => {
if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
return;
}
dispatcher.on<DowncastAttributeEvent>(
`attribute:${ getHtmlAttributeName( viewName! ) }:${ modelName }`,
( evt, data, conversionApi ) => {
if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
return;
}

const { attributeOldValue, attributeNewValue } = data;
const viewWriter = conversionApi.writer;
const viewElement = conversionApi.mapper.toViewElement( data.item as Element )!;
const { attributeOldValue, attributeNewValue } = data;
const viewWriter = conversionApi.writer;
const viewElement = conversionApi.mapper.toViewElement( data.item as Element )!;

updateViewAttributes( viewWriter, attributeOldValue as GHSViewAttributes, attributeNewValue as GHSViewAttributes, viewElement );
} );
updateViewAttributes(
viewWriter,
attributeOldValue as GHSViewAttributes,
attributeNewValue as GHSViewAttributes,
viewElement
);
}
);
};
}
13 changes: 7 additions & 6 deletions packages/ckeditor5-html-support/src/datafilter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,10 @@ import {
type DataSchemaInlineElementDefinition
} from './dataschema';

import type { GHSViewAttributes } from './utils';
import {
getHtmlAttributeName,
type GHSViewAttributes
} from './utils';

import { isPlainObject, pull as removeItemFromArray } from 'lodash-es';

Expand Down Expand Up @@ -498,7 +501,7 @@ export default class DataFilter extends Plugin {
}

schema.extend( definition.model, {
allowAttributes: [ 'htmlAttributes', 'htmlContent' ]
allowAttributes: [ getHtmlAttributeName( viewName ), 'htmlContent' ]
} );

// Store element content in special `$rawContent` custom property to
Expand All @@ -519,9 +522,7 @@ export default class DataFilter extends Plugin {
conversion.for( 'editingDowncast' ).elementToStructure( {
model: {
name: modelName,
attributes: [
'htmlAttributes'
]
attributes: [ getHtmlAttributeName( viewName ) ]
},
view: toObjectWidgetConverter( editor, definition as DataSchemaInlineElementDefinition )
} );
Expand Down Expand Up @@ -570,7 +571,7 @@ export default class DataFilter extends Plugin {
}

schema.extend( definition.model, {
allowAttributes: 'htmlAttributes'
allowAttributes: getHtmlAttributeName( viewName )
} );

conversion.for( 'upcast' ).add( viewToModelBlockAttributeConverter( definition, this ) );
Expand Down
6 changes: 3 additions & 3 deletions packages/ckeditor5-html-support/src/generalhtmlsupport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ import StyleElementSupport from './integrations/style';
import DocumentListElementSupport from './integrations/documentlist';
import CustomElementSupport from './integrations/customelement';
import type { DataSchemaInlineElementDefinition } from './dataschema';
import type { DocumentSelection, Item, Model, Range, Selectable, Writer } from 'ckeditor5/src/engine';
import { modifyGhsAttribute } from './utils';
import type { DocumentSelection, Item, Model, Range, Selectable } from 'ckeditor5/src/engine';
import { getHtmlAttributeName, modifyGhsAttribute } from './utils';
// eslint-disable-next-line @typescript-eslint/no-unused-vars
import type { GeneralHtmlSupportConfig } from './generalhtmlsupportconfig';

Expand Down Expand Up @@ -90,7 +90,7 @@ export default class GeneralHtmlSupport extends Plugin {
return inlineDefinition.model;
}

return 'htmlAttributes';
return getHtmlAttributeName( viewElementName );
}

/**
Expand Down
13 changes: 8 additions & 5 deletions packages/ckeditor5-html-support/src/integrations/codeblock.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,10 @@ import type {
} from 'ckeditor5/src/engine';
import { Plugin } from 'ckeditor5/src/core';

import { updateViewAttributes, type GHSViewAttributes } from '../utils';
import {
updateViewAttributes,
type GHSViewAttributes
} from '../utils';
import DataFilter, { type DataFilterRegisterEvent } from '../datafilter';

/**
Expand Down Expand Up @@ -59,7 +62,7 @@ export default class CodeBlockElementSupport extends Plugin {

// Extend codeBlock to allow attributes required by attribute filtration.
schema.extend( 'codeBlock', {
allowAttributes: [ 'htmlAttributes', 'htmlContentAttributes' ]
allowAttributes: [ 'htmlPreAttributes', 'htmlContentAttributes' ]
} );

conversion.for( 'upcast' ).add( viewToModelCodeBlockAttributeConverter( dataFilter ) );
Expand All @@ -74,7 +77,7 @@ export default class CodeBlockElementSupport extends Plugin {
* View-to-model conversion helper preserving allowed attributes on {@link module:code-block/codeblock~CodeBlock Code Block}
* feature model element.
*
* Attributes are preserved as a value of `htmlAttributes` model attribute.
* Attributes are preserved as a value of `html*Attributes` model attribute.
* @param dataFilter
* @returns Returns a conversion callback.
*/
Expand All @@ -88,7 +91,7 @@ function viewToModelCodeBlockAttributeConverter( dataFilter: DataFilter ) {
return;
}

preserveElementAttributes( viewPreElement, 'htmlAttributes' );
preserveElementAttributes( viewPreElement, 'htmlPreAttributes' );
preserveElementAttributes( viewCodeElement, 'htmlContentAttributes' );

function preserveElementAttributes( viewElement: ViewElement, attributeName: string ) {
Expand All @@ -109,7 +112,7 @@ function viewToModelCodeBlockAttributeConverter( dataFilter: DataFilter ) {
*/
function modelToViewCodeBlockAttributeConverter() {
return ( dispatcher: DowncastDispatcher ) => {
dispatcher.on<DowncastAttributeEvent>( 'attribute:htmlAttributes:codeBlock', ( evt, data, conversionApi ) => {
dispatcher.on<DowncastAttributeEvent>( 'attribute:htmlPreAttributes:codeBlock', ( evt, data, conversionApi ) => {
if ( !conversionApi.consumable.consume( data.item, evt.name ) ) {
return;
}
Expand Down
24 changes: 16 additions & 8 deletions packages/ckeditor5-html-support/src/integrations/customelement.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ export default class CustomElementSupport extends Plugin {

schema.register( definition.model, definition.modelSchema );
schema.extend( definition.model, {
allowAttributes: [ 'htmlElementName', 'htmlAttributes', 'htmlContent' ],
allowAttributes: [ 'htmlElementName', 'htmlCustomElementAttributes', 'htmlContent' ],
isContent: true
} );

Expand Down Expand Up @@ -92,7 +92,7 @@ export default class CustomElementSupport extends Plugin {
const htmlAttributes = dataFilter.processViewAttributes( viewElement, conversionApi );

if ( htmlAttributes ) {
conversionApi.writer.setAttribute( 'htmlAttributes', htmlAttributes, modelElement );
conversionApi.writer.setAttribute( 'htmlCustomElementAttributes', htmlAttributes, modelElement );
}

// Store the whole element in the attribute so that DomConverter will be able to use the pre like element context.
Expand All @@ -117,14 +117,18 @@ export default class CustomElementSupport extends Plugin {
conversion.for( 'editingDowncast' ).elementToElement( {
model: {
name: definition.model,
attributes: [ 'htmlElementName', 'htmlAttributes', 'htmlContent' ]
attributes: [ 'htmlElementName', 'htmlCustomElementAttributes', 'htmlContent' ]
},
view: ( modelElement, { writer } ) => {
const viewName = modelElement.getAttribute( 'htmlElementName' ) as string;
const viewElement = writer.createRawElement( viewName );

if ( modelElement.hasAttribute( 'htmlAttributes' ) ) {
setViewAttributes( writer, modelElement.getAttribute( 'htmlAttributes' ) as GHSViewAttributes, viewElement );
if ( modelElement.hasAttribute( 'htmlCustomElementAttributes' ) ) {
setViewAttributes(
writer,
modelElement.getAttribute( 'htmlCustomElementAttributes' ) as GHSViewAttributes,
viewElement
);
}

return viewElement;
Expand All @@ -134,7 +138,7 @@ export default class CustomElementSupport extends Plugin {
conversion.for( 'dataDowncast' ).elementToElement( {
model: {
name: definition.model,
attributes: [ 'htmlElementName', 'htmlAttributes', 'htmlContent' ]
attributes: [ 'htmlElementName', 'htmlCustomElementAttributes', 'htmlContent' ]
},
view: ( modelElement, { writer } ) => {
const viewName = modelElement.getAttribute( 'htmlElementName' ) as string;
Expand All @@ -154,8 +158,12 @@ export default class CustomElementSupport extends Plugin {
}
} );

if ( modelElement.hasAttribute( 'htmlAttributes' ) ) {
setViewAttributes( writer, modelElement.getAttribute( 'htmlAttributes' ) as GHSViewAttributes, viewElement );
if ( modelElement.hasAttribute( 'htmlCustomElementAttributes' ) ) {
setViewAttributes(
writer,
modelElement.getAttribute( 'htmlCustomElementAttributes' ) as GHSViewAttributes,
viewElement
);
}

return viewElement;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {
} from '../converters';
import DataFilter, { type DataFilterRegisterEvent } from '../datafilter';
import type { DataSchemaBlockElementDefinition } from '../dataschema';
import { getHtmlAttributeName } from '../utils';

/**
* Provides the General HTML Support integration for elements which can behave like sectioning element (e.g. article) or
Expand Down Expand Up @@ -139,7 +140,7 @@ export default class DualContentModelElementSupport extends Plugin {
const dataFilter = editor.plugins.get( DataFilter );

editor.model.schema.extend( definition.model, {
allowAttributes: 'htmlAttributes'
allowAttributes: getHtmlAttributeName( definition.view! )
} );

conversion.for( 'upcast' ).add( viewToModelBlockAttributeConverter( definition, dataFilter ) );
Expand Down
11 changes: 6 additions & 5 deletions packages/ckeditor5-html-support/src/integrations/heading.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ import {
} from 'ckeditor5/src/enter';

import DataSchema from '../dataschema';
import { modifyGhsAttribute } from '../utils';
import { getHtmlAttributeName, modifyGhsAttribute } from '../utils';
import type { HeadingElementOption } from '@ckeditor/ckeditor5-heading/src/headingconfig';

/**
* Provides the General HTML Support integration with {@link module:heading/heading~Heading Heading} feature.
Expand Down Expand Up @@ -80,20 +81,20 @@ export default class HeadingElementSupport extends Plugin {
}

/**
* Removes css classes from "htmlAttributes" of new paragraph created when hitting "enter" in heading.
* Removes css classes from "html*Attributes" of new paragraph created when hitting "enter" in heading.
*/
private removeClassesOnEnter( editor: Editor, options: Array<HeadingOption> ): void {
const enterCommand: EnterCommand = editor.commands.get( 'enter' )!;

this.listenTo<EnterCommandAfterExecuteEvent>( enterCommand, 'afterExecute', ( evt, data ) => {
const positionParent = editor.model.document.selection.getFirstPosition()!.parent;
const isHeading = options.some( option => positionParent.is( 'element', option.model ) );
const heading = options.find( ( option ): option is HeadingElementOption => positionParent.is( 'element', option.model ) );

if ( isHeading && positionParent.childCount === 0 ) {
if ( heading && positionParent.childCount === 0 ) {
modifyGhsAttribute(
data.writer,
positionParent as Item,
'htmlAttributes',
getHtmlAttributeName( heading.view as string ),
'classes',
classes => classes.clear()
);
Expand Down
12 changes: 6 additions & 6 deletions packages/ckeditor5-html-support/src/integrations/image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import type {
ViewElement } from 'ckeditor5/src/engine';

import DataFilter, { type DataFilterRegisterEvent } from '../datafilter';
import { type GHSViewAttributes, setViewAttributes, updateViewAttributes } from '../utils';
import { type GHSViewAttributes, setViewAttributes, updateViewAttributes, getHtmlAttributeName } from '../utils';
import { getDescendantElement } from './integrationutils';

/**
Expand Down Expand Up @@ -64,7 +64,7 @@ export default class ImageElementSupport extends Plugin {
if ( schema.isRegistered( 'imageBlock' ) ) {
schema.extend( 'imageBlock', {
allowAttributes: [
'htmlAttributes',
'htmlImgAttributes',
// Figure and Link don't have model counterpart.
// We will preserve attributes on image model element using these attribute keys.
'htmlFigureAttributes',
Expand All @@ -78,7 +78,7 @@ export default class ImageElementSupport extends Plugin {
allowAttributes: [
// `htmlA` is needed for standard GHS link integration.
'htmlA',
'htmlAttributes'
'htmlImgAttributes'
]
} );
}
Expand Down Expand Up @@ -107,7 +107,7 @@ function viewToModelImageAttributeConverter( dataFilter: DataFilter ) {
const viewImageElement = data.viewItem;
const viewContainerElement = viewImageElement.parent;

preserveElementAttributes( viewImageElement, 'htmlAttributes' );
preserveElementAttributes( viewImageElement, 'htmlImgAttributes' );

if ( viewContainerElement.is( 'element', 'a' ) ) {
preserveLinkAttributes( viewContainerElement );
Expand Down Expand Up @@ -161,9 +161,9 @@ function viewToModelFigureAttributeConverter( dataFilter: DataFilter ) {
*/
function modelToViewImageAttributeConverter() {
return ( dispatcher: DowncastDispatcher ) => {
addInlineAttributeConversion( 'htmlAttributes' );
addInlineAttributeConversion( 'htmlImgAttributes' );

addBlockAttributeConversion( 'img', 'htmlAttributes' );
addBlockAttributeConversion( 'img', 'htmlImgAttributes' );
addBlockAttributeConversion( 'figure', 'htmlFigureAttributes' );
addBlockAttributeConversion( 'a', 'htmlLinkAttributes' );

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { Plugin } from 'ckeditor5/src/core';

import DataFilter, { type DataFilterRegisterEvent } from '../datafilter';
import DataSchema from '../dataschema';
import { updateViewAttributes, type GHSViewAttributes } from '../utils';
import { updateViewAttributes, type GHSViewAttributes, getHtmlAttributeName } from '../utils';
import type {
DowncastAttributeEvent,
DowncastDispatcher,
Expand Down Expand Up @@ -75,7 +75,7 @@ export default class MediaEmbedElementSupport extends Plugin {

schema.extend( 'media', {
allowAttributes: [
'htmlAttributes',
getHtmlAttributeName( mediaElementName ),
'htmlFigureAttributes'
]
} );
Expand All @@ -92,7 +92,7 @@ function viewToModelMediaAttributesConverter( dataFilter: DataFilter, mediaEleme
const upcastMedia: GetCallback<UpcastElementEvent> = ( evt, data, conversionApi ) => {
const viewMediaElement = data.viewItem;

preserveElementAttributes( viewMediaElement, 'htmlAttributes' );
preserveElementAttributes( viewMediaElement, getHtmlAttributeName( mediaElementName ) );

function preserveElementAttributes( viewElement: ViewElement, attributeName: string ) {
const viewAttributes = dataFilter.processViewAttributes( viewElement, conversionApi );
Expand Down Expand Up @@ -133,7 +133,7 @@ function viewToModelFigureAttributesConverter( dataFilter: DataFilter ) {

function modelToViewMediaAttributeConverter( mediaElementName: string ) {
return ( dispatcher: DowncastDispatcher ) => {
addAttributeConversionDispatcherHandler( mediaElementName, 'htmlAttributes' );
addAttributeConversionDispatcherHandler( mediaElementName, getHtmlAttributeName( mediaElementName ) );
addAttributeConversionDispatcherHandler( 'figure', 'htmlFigureAttributes' );

function addAttributeConversionDispatcherHandler( elementName: string, attributeName: string ) {
Expand Down

0 comments on commit a04cbd3

Please sign in to comment.