File: //home/arjun/projects/buyercall/node_modules/@ckeditor/ckeditor5-html-support/src/dataschema.js
/**
* @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved.
* For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
*/
/**
* @module html-support/dataschema
*/
import { Plugin } from 'ckeditor5/src/core';
import { toArray } from 'ckeditor5/src/utils';
import defaultConfig from './schemadefinitions';
import { mergeWith } from 'lodash-es';
/**
* Holds representation of the extended HTML document type definitions to be used by the
* editor in HTML support.
*
* Data schema is represented by data schema definitions.
*
* To add new definition for block element,
* use {@link module:html-support/dataschema~DataSchema#registerBlockElement} method:
*
* dataSchema.registerBlockElement( {
* view: 'section',
* model: 'my-section',
* modelSchema: {
* inheritAllFrom: '$block'
* }
* } );
*
* To add new definition for inline element,
* use {@link module:html-support/dataschema~DataSchema#registerInlineElement} method:
*
* dataSchema.registerInlineElement( {
* view: 'span',
* model: 'my-span',
* attributeProperties: {
* copyOnEnter: true
* }
* } );
*
* @extends module:core/plugin~Plugin
*/
export default class DataSchema extends Plugin {
constructor( editor ) {
super( editor );
/**
* A map of registered data schema definitions.
*
* @readonly
* @private
* @member {Map.<String, module:html-support/dataschema~DataSchemaDefinition>} #_definitions
*/
this._definitions = new Map();
}
/**
* @inheritDoc
*/
static get pluginName() {
return 'DataSchema';
}
/**
* @inheritDoc
*/
init() {
for ( const definition of defaultConfig.block ) {
this.registerBlockElement( definition );
}
for ( const definition of defaultConfig.inline ) {
this.registerInlineElement( definition );
}
}
/**
* Add new data schema definition describing block element.
*
* @param {module:html-support/dataschema~DataSchemaBlockElementDefinition} definition
*/
registerBlockElement( definition ) {
this._definitions.set( definition.model, { ...definition, isBlock: true } );
}
/**
* Add new data schema definition describing inline element.
*
* @param {module:html-support/dataschema~DataSchemaInlineElementDefinition} definition
*/
registerInlineElement( definition ) {
this._definitions.set( definition.model, { ...definition, isInline: true } );
}
/**
* Updates schema definition describing block element with new properties.
*
* Creates new scheme if it doesn't exist.
* Array properties are concatenated with original values.
*
* @param {module:html-support/dataschema~DataSchemaBlockElementDefinition} definition Definition update.
*/
extendBlockElement( definition ) {
this._extendDefinition( { ...definition, isBlock: true } );
}
/**
* Updates schema definition describing inline element with new properties.
*
* Creates new scheme if it doesn't exist.
* Array properties are concatenated with original values.
*
* @param {module:html-support/dataschema~DataSchemaInlineElementDefinition} definition Definition update.
*/
extendInlineElement( definition ) {
this._extendDefinition( { ...definition, isInline: true } );
}
/**
* Returns all definitions matching the given view name.
*
* @param {String|RegExp} viewName
* @param {Boolean} [includeReferences] Indicates if this method should also include definitions of referenced models.
* @returns {Set.<module:html-support/dataschema~DataSchemaDefinition>}
*/
getDefinitionsForView( viewName, includeReferences ) {
const definitions = new Set();
for ( const definition of this._getMatchingViewDefinitions( viewName ) ) {
if ( includeReferences ) {
for ( const reference of this._getReferences( definition.model ) ) {
definitions.add( reference );
}
}
definitions.add( definition );
}
return definitions;
}
/**
* Returns definitions matching the given view name.
*
* @private
* @param {String|RegExp} viewName
* @returns {Array.<module:html-support/dataschema~DataSchemaDefinition>}
*/
_getMatchingViewDefinitions( viewName ) {
return Array.from( this._definitions.values() )
.filter( def => def.view && testViewName( viewName, def.view ) );
}
/**
* Resolves all definition references registered for the given data schema definition.
*
* @private
* @param {String} modelName Data schema model name.
* @returns {Iterable.<module:html-support/dataschema~DataSchemaDefinition>}
*/
* _getReferences( modelName ) {
const { modelSchema } = this._definitions.get( modelName );
if ( !modelSchema ) {
return;
}
const inheritProperties = [ 'inheritAllFrom', 'inheritTypesFrom', 'allowWhere', 'allowContentOf', 'allowAttributesOf' ];
for ( const property of inheritProperties ) {
for ( const referenceName of toArray( modelSchema[ property ] || [] ) ) {
const definition = this._definitions.get( referenceName );
if ( referenceName !== modelName && definition ) {
yield* this._getReferences( definition.model );
yield definition;
}
}
}
}
/**
* Updates schema definition with new properties.
*
* Creates new scheme if it doesn't exist.
* Array properties are concatenated with original values.
*
* @private
* @param {module:html-support/dataschema~DataSchemaDefinition} definition Definition update.
*/
_extendDefinition( definition ) {
const currentDefinition = this._definitions.get( definition.model );
const mergedDefinition = mergeWith( {}, currentDefinition, definition, ( target, source ) => {
return Array.isArray( target ) ? target.concat( source ) : undefined;
} );
this._definitions.set( definition.model, mergedDefinition );
}
}
// Test view name against the given pattern.
//
// @private
// @param {String|RegExp} pattern
// @param {String} viewName
// @returns {Boolean}
function testViewName( pattern, viewName ) {
if ( typeof pattern === 'string' ) {
return pattern === viewName;
}
if ( pattern instanceof RegExp ) {
return pattern.test( viewName );
}
return false;
}
/**
* A base definition of {@link module:html-support/dataschema~DataSchema data schema}.
*
* @typedef {Object} module:html-support/dataschema~DataSchemaDefinition
* @property {String} model Name of the model.
* @property {String} [view] Name of the view element.
* @property {Boolean} [isObject] Indicates that the definition describes object element.
* @property {module:engine/model/schema~SchemaItemDefinition} [modelSchema] The model schema item definition describing registered model.
*/
/**
* A definition of {@link module:html-support/dataschema~DataSchema data schema} for block elements.
*
* @typedef {Object} module:html-support/dataschema~DataSchemaBlockElementDefinition
* @property {Boolean} isBlock Indicates that the definition describes block element.
* Set by {@link module:html-support/dataschema~DataSchema#registerBlockElement} method.
* @property {String} [paragraphLikeModel] Should be used when an element can behave both as a sectioning element (e.g. article) and
* element accepting only inline content (e.g. paragraph).
* If an element contains only inline content, this option will be used as a model
* name.
* @extends module:html-support/dataschema~DataSchemaDefinition
*/
/**
* A definition of {@link module:html-support/dataschema~DataSchema data schema} for inline elements.
*
* @typedef {Object} module:html-support/dataschema~DataSchemaInlineElementDefinition
* @property {module:engine/model/schema~AttributeProperties} [attributeProperties] Additional metadata describing the model attribute.
* @property {Boolean} isInline Indicates that the definition describes inline element.
* @property {Number} [priority] Element priority. Decides in what order elements are wrapped by
* {@link module:engine/view/downcastwriter~DowncastWriter}.
* Set by {@link module:html-support/dataschema~DataSchema#registerInlineElement} method.
* @extends module:html-support/dataschema~DataSchemaDefinition
*/