File: //home/arjun/projects/buyercall/node_modules/@ckeditor/ckeditor5-table/src/converters/downcast.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 table/converters/downcast
*/
import TableWalker from './../tablewalker';
import { toWidget, toWidgetEditable } from 'ckeditor5/src/widget';
/**
* Model table element to view table element conversion helper.
*
* @param {module:table/tableutils~TableUtils} tableUtils The `TableUtils` plugin instance.
* @param {Object} [options]
* @param {Boolean} [options.asWidget] If set to `true`, the downcast conversion will produce a widget.
* @returns {Function} Element creator.
*/
export function downcastTable( tableUtils, options = {} ) {
return ( table, { writer } ) => {
const headingRows = table.getAttribute( 'headingRows' ) || 0;
const tableSections = [];
// Table head slot.
if ( headingRows > 0 ) {
tableSections.push(
writer.createContainerElement( 'thead', null,
writer.createSlot( element => element.is( 'element', 'tableRow' ) && element.index < headingRows )
)
);
}
// Table body slot.
if ( headingRows < tableUtils.getRows( table ) ) {
tableSections.push(
writer.createContainerElement( 'tbody', null,
writer.createSlot( element => element.is( 'element', 'tableRow' ) && element.index >= headingRows )
)
);
}
const figureElement = writer.createContainerElement( 'figure', { class: 'table' }, [
// Table with proper sections (thead, tbody).
writer.createContainerElement( 'table', null, tableSections ),
// Slot for the rest (for example caption).
writer.createSlot( element => !element.is( 'element', 'tableRow' ) )
] );
return options.asWidget ? toTableWidget( figureElement, writer ) : figureElement;
};
}
/**
* Model table row element to view `<tr>` element conversion helper.
*
* @returns {Function} Element creator.
*/
export function downcastRow() {
return ( tableRow, { writer } ) => {
return tableRow.isEmpty ?
writer.createEmptyElement( 'tr' ) :
writer.createContainerElement( 'tr' );
};
}
/**
* Model table cell element to view `<td>` or `<th>` element conversion helper.
*
* This conversion helper will create proper `<th>` elements for table cells that are in the heading section (heading row or column)
* and `<td>` otherwise.
*
* @param {Object} [options]
* @param {Boolean} [options.asWidget] If set to `true`, the downcast conversion will produce a widget.
* @returns {Function} Element creator.
*/
export function downcastCell( options = {} ) {
return ( tableCell, { writer } ) => {
const tableRow = tableCell.parent;
const table = tableRow.parent;
const rowIndex = table.getChildIndex( tableRow );
const tableWalker = new TableWalker( table, { row: rowIndex } );
const headingRows = table.getAttribute( 'headingRows' ) || 0;
const headingColumns = table.getAttribute( 'headingColumns' ) || 0;
// We need to iterate over a table in order to get proper row & column values from a walker.
for ( const tableSlot of tableWalker ) {
if ( tableSlot.cell == tableCell ) {
const isHeading = tableSlot.row < headingRows || tableSlot.column < headingColumns;
const cellElementName = isHeading ? 'th' : 'td';
return options.asWidget ?
toWidgetEditable( writer.createEditableElement( cellElementName ), writer ) :
writer.createContainerElement( cellElementName );
}
}
};
}
/**
* Overrides paragraph inside table cell conversion.
*
* This converter:
* * should be used to override default paragraph conversion.
* * It will only convert `<paragraph>` placed directly inside `<tableCell>`.
* * For a single paragraph without attributes it returns `<span>` to simulate data table.
* * For all other cases it returns `<p>` element.
*
* @param {Object} [options]
* @param {Boolean} [options.asWidget] If set to `true`, the downcast conversion will produce a widget.
* @returns {Function} Element creator.
*/
export function convertParagraphInTableCell( options = {} ) {
return ( modelElement, { writer, consumable, mapper } ) => {
if ( !modelElement.parent.is( 'element', 'tableCell' ) ) {
return;
}
if ( !isSingleParagraphWithoutAttributes( modelElement ) ) {
return;
}
if ( options.asWidget ) {
return writer.createContainerElement( 'span', { class: 'ck-table-bogus-paragraph' } );
} else {
// Additional requirement for data pipeline to have backward compatible data tables.
consumable.consume( modelElement, 'insert' );
mapper.bindElements( modelElement, mapper.toViewElement( modelElement.parent ) );
}
};
}
/**
* Checks if given model `<paragraph>` is an only child of a parent (`<tableCell>`) and if it has any attribute set.
*
* The paragraph should be converted in the editing view to:
*
* * If returned `true` - to a `<span class="ck-table-bogus-paragraph">`
* * If returned `false` - to a `<p>`
*
* @param {module:engine/model/element~Element} modelElement
* @returns {Boolean}
*/
export function isSingleParagraphWithoutAttributes( modelElement ) {
const tableCell = modelElement.parent;
const isSingleParagraph = tableCell.childCount == 1;
return isSingleParagraph && !hasAnyAttribute( modelElement );
}
// Converts a given {@link module:engine/view/element~Element} to a table widget:
// * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to recognize the table widget element.
// * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator.
//
// @param {module:engine/view/element~Element} viewElement
// @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer.
// @param {String} label The element's label. It will be concatenated with the table `alt` attribute if one is present.
// @returns {module:engine/view/element~Element}
function toTableWidget( viewElement, writer ) {
writer.setCustomProperty( 'table', true, viewElement );
return toWidget( viewElement, writer, { hasSelectionHandle: true } );
}
// Checks if an element has any attributes set.
//
// @param {module:engine/model/element~Element element
// @returns {Boolean}
function hasAnyAttribute( element ) {
return !![ ...element.getAttributeKeys() ].length;
}