| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354 |
- /**
- * @license Copyright (c) 2003-2020, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license
- */
- /**
- * @module table/tableui
- */
- import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
- import { addListToDropdown, createDropdown } from '@ckeditor/ckeditor5-ui/src/dropdown/utils';
- import SplitButtonView from '@ckeditor/ckeditor5-ui/src/dropdown/button/splitbuttonview';
- import Model from '@ckeditor/ckeditor5-ui/src/model';
- import Collection from '@ckeditor/ckeditor5-utils/src/collection';
- import InsertTableView from './ui/inserttableview';
- import tableIcon from './../theme/icons/table.svg';
- import tableColumnIcon from './../theme/icons/table-column.svg';
- import tableRowIcon from './../theme/icons/table-row.svg';
- import tableMergeCellIcon from './../theme/icons/table-merge-cell.svg';
- /**
- * The table UI plugin. It introduces:
- *
- * * The `'insertTable'` dropdown,
- * * The `'tableColumn'` dropdown,
- * * The `'tableRow'` dropdown,
- * * The `'mergeTableCells'` split button.
- *
- * The `'tableColumn'`, `'tableRow'` and `'mergeTableCells'` dropdowns work best with {@link module:table/tabletoolbar~TableToolbar}.
- *
- * @extends module:core/plugin~Plugin
- */
- export default class TableUI extends Plugin {
- /**
- * @inheritDoc
- */
- init() {
- const editor = this.editor;
- const t = this.editor.t;
- const contentLanguageDirection = editor.locale.contentLanguageDirection;
- const isContentLtr = contentLanguageDirection === 'ltr';
- editor.ui.componentFactory.add( 'insertTable', locale => {
- const command = editor.commands.get( 'insertTable' );
- const dropdownView = createDropdown( locale );
- dropdownView.bind( 'isEnabled' ).to( command );
- // Decorate dropdown's button.
- dropdownView.buttonView.set( {
- icon: tableIcon,
- label: t( 'Insert table' ),
- tooltip: true
- } );
- let insertTableView;
- dropdownView.on( 'change:isOpen', () => {
- if ( insertTableView ) {
- return;
- }
- // Prepare custom view for dropdown's panel.
- insertTableView = new InsertTableView( locale );
- dropdownView.panelView.children.add( insertTableView );
- insertTableView.delegate( 'execute' ).to( dropdownView );
- dropdownView.buttonView.on( 'open', () => {
- // Reset the chooser before showing it to the user.
- insertTableView.rows = 0;
- insertTableView.columns = 0;
- } );
- dropdownView.on( 'execute', () => {
- editor.execute( 'insertTable', { rows: insertTableView.rows, columns: insertTableView.columns } );
- editor.editing.view.focus();
- } );
- } );
- return dropdownView;
- } );
- editor.ui.componentFactory.add( 'tableColumn', locale => {
- const options = [
- {
- type: 'switchbutton',
- model: {
- commandName: 'setTableColumnHeader',
- label: t( 'Header column' ),
- bindIsOn: true
- }
- },
- { type: 'separator' },
- {
- type: 'button',
- model: {
- commandName: isContentLtr ? 'insertTableColumnLeft' : 'insertTableColumnRight',
- label: t( 'Insert column left' )
- }
- },
- {
- type: 'button',
- model: {
- commandName: isContentLtr ? 'insertTableColumnRight' : 'insertTableColumnLeft',
- label: t( 'Insert column right' )
- }
- },
- {
- type: 'button',
- model: {
- commandName: 'removeTableColumn',
- label: t( 'Delete column' )
- }
- },
- {
- type: 'button',
- model: {
- commandName: 'selectTableColumn',
- label: t( 'Select column' )
- }
- }
- ];
- return this._prepareDropdown( t( 'Column' ), tableColumnIcon, options, locale );
- } );
- editor.ui.componentFactory.add( 'tableRow', locale => {
- const options = [
- {
- type: 'switchbutton',
- model: {
- commandName: 'setTableRowHeader',
- label: t( 'Header row' ),
- bindIsOn: true
- }
- },
- { type: 'separator' },
- {
- type: 'button',
- model: {
- commandName: 'insertTableRowAbove',
- label: t( 'Insert row above' )
- }
- },
- {
- type: 'button',
- model: {
- commandName: 'insertTableRowBelow',
- label: t( 'Insert row below' )
- }
- },
- {
- type: 'button',
- model: {
- commandName: 'removeTableRow',
- label: t( 'Delete row' )
- }
- },
- {
- type: 'button',
- model: {
- commandName: 'selectTableRow',
- label: t( 'Select row' )
- }
- }
- ];
- return this._prepareDropdown( t( 'Row' ), tableRowIcon, options, locale );
- } );
- editor.ui.componentFactory.add( 'mergeTableCells', locale => {
- const options = [
- {
- type: 'button',
- model: {
- commandName: 'mergeTableCellUp',
- label: t( 'Merge cell up' )
- }
- },
- {
- type: 'button',
- model: {
- commandName: isContentLtr ? 'mergeTableCellRight' : 'mergeTableCellLeft',
- label: t( 'Merge cell right' )
- }
- },
- {
- type: 'button',
- model: {
- commandName: 'mergeTableCellDown',
- label: t( 'Merge cell down' )
- }
- },
- {
- type: 'button',
- model: {
- commandName: isContentLtr ? 'mergeTableCellLeft' : 'mergeTableCellRight',
- label: t( 'Merge cell left' )
- }
- },
- { type: 'separator' },
- {
- type: 'button',
- model: {
- commandName: 'splitTableCellVertically',
- label: t( 'Split cell vertically' )
- }
- },
- {
- type: 'button',
- model: {
- commandName: 'splitTableCellHorizontally',
- label: t( 'Split cell horizontally' )
- }
- }
- ];
- return this._prepareMergeSplitButtonDropdown( t( 'Merge cells' ), tableMergeCellIcon, options, locale );
- } );
- }
- /**
- * Creates a dropdown view from a set of options.
- *
- * @private
- * @param {String} label The dropdown button label.
- * @param {String} icon An icon for the dropdown button.
- * @param {Array.<module:ui/dropdown/utils~ListDropdownItemDefinition>} options The list of options for the dropdown.
- * @param {module:utils/locale~Locale} locale
- * @returns {module:ui/dropdown/dropdownview~DropdownView}
- */
- _prepareDropdown( label, icon, options, locale ) {
- const editor = this.editor;
- const dropdownView = createDropdown( locale );
- const commands = this._fillDropdownWithListOptions( dropdownView, options );
- // Decorate dropdown's button.
- dropdownView.buttonView.set( {
- label,
- icon,
- tooltip: true
- } );
- // Make dropdown button disabled when all options are disabled.
- dropdownView.bind( 'isEnabled' ).toMany( commands, 'isEnabled', ( ...areEnabled ) => {
- return areEnabled.some( isEnabled => isEnabled );
- } );
- this.listenTo( dropdownView, 'execute', evt => {
- editor.execute( evt.source.commandName );
- editor.editing.view.focus();
- } );
- return dropdownView;
- }
- /**
- * Creates a dropdown view with a {@link module:ui/dropdown/button/splitbuttonview~SplitButtonView} for
- * merge (and split)–related commands.
- *
- * @private
- * @param {String} label The dropdown button label.
- * @param {String} icon An icon for the dropdown button.
- * @param {Array.<module:ui/dropdown/utils~ListDropdownItemDefinition>} options The list of options for the dropdown.
- * @param {module:utils/locale~Locale} locale
- * @returns {module:ui/dropdown/dropdownview~DropdownView}
- */
- _prepareMergeSplitButtonDropdown( label, icon, options, locale ) {
- const editor = this.editor;
- const dropdownView = createDropdown( locale, SplitButtonView );
- const mergeCommandName = 'mergeTableCells';
- this._fillDropdownWithListOptions( dropdownView, options );
- dropdownView.buttonView.set( {
- label,
- icon,
- tooltip: true,
- isEnabled: true
- } );
- // Merge selected table cells when the main part of the split button is clicked.
- this.listenTo( dropdownView.buttonView, 'execute', () => {
- editor.execute( mergeCommandName );
- editor.editing.view.focus();
- } );
- // Execute commands for events coming from the list in the dropdown panel.
- this.listenTo( dropdownView, 'execute', evt => {
- editor.execute( evt.source.commandName );
- editor.editing.view.focus();
- } );
- return dropdownView;
- }
- /**
- * Injects a {@link module:ui/list/listview~ListView} into the passed dropdown with buttons
- * which execute editor commands as configured in passed options.
- *
- * @private
- * @param {module:ui/dropdown/dropdownview~DropdownView} dropdownView
- * @param {Array.<module:ui/dropdown/utils~ListDropdownItemDefinition>} options The list of options for the dropdown.
- * @returns {Array.<module:core/command~Command>} Commands the list options are interacting with.
- */
- _fillDropdownWithListOptions( dropdownView, options ) {
- const editor = this.editor;
- const commands = [];
- const itemDefinitions = new Collection();
- for ( const option of options ) {
- addListOption( option, editor, commands, itemDefinitions );
- }
- addListToDropdown( dropdownView, itemDefinitions, editor.ui.componentFactory );
- return commands;
- }
- }
- // Adds an option to a list view.
- //
- // @param {module:table/tableui~DropdownOption} option A configuration option.
- // @param {module:core/editor/editor~Editor} editor
- // @param {Array.<module:core/command~Command>} commands The list of commands to update.
- // @param {Iterable.<module:ui/dropdown/utils~ListDropdownItemDefinition>} itemDefinitions
- // A collection of dropdown items to update with the given option.
- function addListOption( option, editor, commands, itemDefinitions ) {
- const model = option.model = new Model( option.model );
- const { commandName, bindIsOn } = option.model;
- if ( option.type === 'button' || option.type === 'switchbutton' ) {
- const command = editor.commands.get( commandName );
- commands.push( command );
- model.set( { commandName } );
- model.bind( 'isEnabled' ).to( command );
- if ( bindIsOn ) {
- model.bind( 'isOn' ).to( command, 'value' );
- }
- }
- model.set( {
- withText: true
- } );
- itemDefinitions.add( option );
- }
|