Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for nested tables #3232

Closed
Reinmar opened this issue Sep 24, 2018 · 12 comments · Fixed by #9362
Closed

Support for nested tables #3232

Reinmar opened this issue Sep 24, 2018 · 12 comments · Fixed by #9362
Assignees
Labels
domain:v4-compatibility This issue reports a CKEditor 4 feature/option that's missing in CKEditor 5. package:table support:2 An issue reported by a commercially licensed client. type:feature This issue reports a feature request (an idea for a new functionality or a missing option).

Comments

@Reinmar
Copy link
Member

Reinmar commented Sep 24, 2018

Add support for nesting one table inside another.

This feature wasn't on our roadmap yet, but let's gather a feedback if this is a common requirement.

NOTE: It is possible to enable support for nested tables. See https://github.com/ckeditor/ckeditor5-table/issues/121#issuecomment-528251188 for how to do that.


If you'd like this to be officially supported add 👍 to this ticket.

@Reinmar
Copy link
Member Author

Reinmar commented Sep 24, 2018

Quote from #1260 (comment)

We do not "need" this feature for editing. But we have to handle incoming mails with our application. I found this nested table in a mail signature.

@AustinMutschler
Copy link

AustinMutschler commented Jul 24, 2019

@Reinmar I have a specific use case that would require editing nested tables. This would be a must have feature for my team so if there is anyway to put it on the roadmap that would be very much appreciated.

Many of our current users are used to using Microsoft Word, so to properly convert some of these files to a web editing interface they would need to be able to nest tables inside of table like their current documents support.

@AustinMutschler
Copy link

@Reinmar is there any update on supporting a table in table feature?

@AustinMutschler
Copy link

AustinMutschler commented Sep 4, 2019

@Reinmar I hate to keep bugging you about this but is there anyway for me to help implement this. Is there documentation I can read to try to help contribute to this project so I can attempt to add table in table support. This is a very important feature for my team to have for our specific use case.

@Reinmar
Copy link
Member Author

Reinmar commented Sep 5, 2019

Hi Austin!

The good news is that nested tables are actually supported, but this is disabled for simplicity via the schema. We had to reduce the scope initially, but from what I can see it's working quite fine.

To enable tables inside tables, you need to override the schema check which disables them. This check is a callback to Schema#checkChild event and you can add another callback to override that one:

editor.model.schema.on( 'checkChild', ( evt, args ) => {
	const context = args[ 0 ];
	const childDefinition = args[ 1 ];

	if ( context.endsWith( 'tableCell' ) && childDefinition && childDefinition.name == 'table' ) {
		// Prevent next listeners from being called.
		evt.stop();
		// Set the checkChild()'s return value.
		evt.return = true;
	}
}, { priority: 'highest' } );

image

You will need to wrap this code with function and pass it to config.extraPlugins because this code needs to be executed before the editor loads data.

The bad news is that there's not much interest in this so far, so if there will be some issues, we're not going to prioritize them at the moment. If you'd like help with resolving them you can always contact us.

@jodator
Copy link
Contributor

jodator commented Sep 5, 2019

@Reinmar, unfortunately, there are some minor issues with selecting the table inside the table with a mouse - it will select the uppermost table.

@AustinMutschler
Copy link

AustinMutschler commented Sep 6, 2019

@Reinmar This helps a lot. Thank you for spending time to teach me how to enable this feature. I will be testing it extensively in a development and production environment and can hopefully help solve bugs and any issues that arise.

Update 1:
I am using CKEditor 5 with React and it appears that the onInit prop does not execute before the data is passed in because I can create a table within a table but when I refresh the page it converts it back to the weird text format.

Update 2:
I was able to overcome the issue in Update 1 by setting a flag that waited for my function in onInit to run before adding data to the data tag.

@mlewand mlewand transferred this issue from ckeditor/ckeditor5-table Oct 9, 2019
@mlewand mlewand added this to the backlog milestone Oct 9, 2019
@mlewand mlewand added status:confirmed type:feature This issue reports a feature request (an idea for a new functionality or a missing option). package:table labels Oct 9, 2019
@lslowikowska lslowikowska added the support:2 An issue reported by a commercially licensed client. label Apr 16, 2020
@aaroncalderon
Copy link

aaroncalderon commented Jul 9, 2020

@Reinmar I looked into this and based off the sample Chat with mentions I was able to figure out what you ment by:

You will need to wrap this code with function and pass it to config.extraPlugins...

JavaScript Snippet below:

  ClassicEditor
    .create(document.querySelector('.editor'), {
      extraPlugins: [allowNestedTables], // this is the missing link
      toolbar: {
        items: [
          'heading',
          '|',
          'fontFamily',
          'fontBackgroundColor',
          'fontColor',
          'bold',
          //...
        ]
      },
      //...
    })
    .then(editor => {
      window.editor = editor;
    })
    .catch(error => {
      console.error('Oops, something gone wrong!');
      console.error(
        'Please, report the following error in the https://github.com/ckeditor/ckeditor5 with the build id and the error stack trace:'
      );
      console.warn('Build id: kwgdr5ln3fje-waex6uolg10x');
      console.error(error);
    });

  // here we create the function
  function allowNestedTables ( editor ) {
    editor.model.schema.on('checkChild', (evt, args) => {
        const context = args[0];
        const childDefinition = args[1];

        if (context.endsWith('tableCell') && childDefinition && childDefinition.name == 'table') {
          // Prevent next listeners from being called.
          evt.stop();
          // Set the checkChild()'s return value.
          evt.return = true;
        }
      }, {
        priority: 'highest'
      });
  }

2020/07/14 - Updated code for brevity

@athuldom
Copy link

athuldom commented Aug 4, 2020

i have seen the above code snippet. I am using this editor in my react project. Can any one show me how to solve the issues with the above mentioned code in a react class component. As i am new to this, a help will be great full.
Thank you

@aaroncalderon
Copy link

@athuldom so, I googled for ckeditor react component and the first link I got was Rich text editor component for React. So, it has a configuration property. All you have to do is add the configuration as shown above to include the extraPlugins and allowNestedTables bit.

@Mgsy Mgsy added squad:compat and removed squad:core Issue to be handled by the Core team. labels Jan 14, 2021
@deepaksm1
Copy link

deepaksm1 commented Jan 27, 2021

How to implement this in Angular, I tried below code but not working

ClassicEditor.extraPlugins = [ allowNestedTables ]

import ClassicEditorBase from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';

import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
//	import UploadAdapter from '@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter';
import Autoformat from '@ckeditor/ckeditor5-autoformat/src/autoformat';
import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
import BlockQuote from '@ckeditor/ckeditor5-block-quote/src/blockquote';
//	import CKFinder from '@ckeditor/ckeditor5-ckfinder/src/ckfinder';
import EasyImage from '@ckeditor/ckeditor5-easy-image/src/easyimage';
import Heading from '@ckeditor/ckeditor5-heading/src/heading';
import Image from '@ckeditor/ckeditor5-image/src/image';
import ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption';
import ImageStyle from '@ckeditor/ckeditor5-image/src/imagestyle';
//	import ImageToolbar from '@ckeditor/ckeditor5-image/src/imagetoolbar';
import ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload';
import ImageResize from '@ckeditor/ckeditor5-image/src/imageresize';
import Indent from '@ckeditor/ckeditor5-indent/src/indent';
//	import Link from '@ckeditor/ckeditor5-link/src/link';
import List from '@ckeditor/ckeditor5-list/src/list';
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
import PasteFromOffice from '@ckeditor/ckeditor5-paste-from-office/src/pastefromoffice';
import Table from '@ckeditor/ckeditor5-table/src/table';
import TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar';
import TextTransformation from '@ckeditor/ckeditor5-typing/src/texttransformation';

import TableProperties from '@ckeditor/ckeditor5-table/src/tableproperties';
import TableCellProperties from '@ckeditor/ckeditor5-table/src/tablecellproperties';

export default class ClassicEditor extends ClassicEditorBase { }

// Plugins to include in the build.
ClassicEditor.builtinPlugins = [
	Essentials,
	//	UploadAdapter,
	Autoformat,
	Bold,
	Italic,
	BlockQuote,
	//	CKFinder,
	EasyImage,
	Heading,
	Image,
	ImageCaption,
	ImageStyle,
	//	ImageToolbar,
	ImageResize,
	ImageUpload,
	Indent,
	List,
	Paragraph,
	PasteFromOffice,
	Table,
	TableToolbar,
	TextTransformation,
	TableProperties,
	TableCellProperties
];
ClassicEditor.extraPlugins = [ allowNestedTables ]
// Editor configuration.
ClassicEditor.defaultConfig = {
	toolbar: {
		items: [
			'heading',
			'|',
			'bold',
			'italic',
			'bulletedList',
			'numberedList',
			'|',
			'indent',
			'outdent',
			'|',
			'imageUpload',
			'blockQuote',
			'insertTable',
			'undo',
			'redo'
		]
	},
	image: {
		toolbar: [
			'imageStyle:full',
			'imageStyle:side',
			'|',
			'imageTextAlternative'
		]
	},
	table: {
		contentToolbar: [
			'tableColumn',
			'tableRow',
			'mergeTableCells',
			'tableProperties', 'tableCellProperties'
		]
	},
	// This value must be kept in sync with the language defined in webpack.config.js.
	language: 'en'
};

function allowNestedTables ( editor ) {
    editor.model.schema.on('checkChild', (evt, args) => {
        const context = args[0];
        const childDefinition = args[1];
        if (context.endsWith('tableCell') && childDefinition && childDefinition.name == 'table') {
          // Prevent next listeners from being called.
          evt.stop();
          // Set the checkChild()'s return value.
          evt.return = true;
        }
      }, {
        priority: 'highest'
      });
  }

@deepaksm1
Copy link

How to implement this in Angular, I tried below code but not working

ClassicEditor.extraPlugins = [ allowNestedTables ]

import ClassicEditorBase from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';

import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
//	import UploadAdapter from '@ckeditor/ckeditor5-adapter-ckfinder/src/uploadadapter';
import Autoformat from '@ckeditor/ckeditor5-autoformat/src/autoformat';
import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
import BlockQuote from '@ckeditor/ckeditor5-block-quote/src/blockquote';
//	import CKFinder from '@ckeditor/ckeditor5-ckfinder/src/ckfinder';
import EasyImage from '@ckeditor/ckeditor5-easy-image/src/easyimage';
import Heading from '@ckeditor/ckeditor5-heading/src/heading';
import Image from '@ckeditor/ckeditor5-image/src/image';
import ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption';
import ImageStyle from '@ckeditor/ckeditor5-image/src/imagestyle';
//	import ImageToolbar from '@ckeditor/ckeditor5-image/src/imagetoolbar';
import ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload';
import ImageResize from '@ckeditor/ckeditor5-image/src/imageresize';
import Indent from '@ckeditor/ckeditor5-indent/src/indent';
//	import Link from '@ckeditor/ckeditor5-link/src/link';
import List from '@ckeditor/ckeditor5-list/src/list';
import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
import PasteFromOffice from '@ckeditor/ckeditor5-paste-from-office/src/pastefromoffice';
import Table from '@ckeditor/ckeditor5-table/src/table';
import TableToolbar from '@ckeditor/ckeditor5-table/src/tabletoolbar';
import TextTransformation from '@ckeditor/ckeditor5-typing/src/texttransformation';

import TableProperties from '@ckeditor/ckeditor5-table/src/tableproperties';
import TableCellProperties from '@ckeditor/ckeditor5-table/src/tablecellproperties';

export default class ClassicEditor extends ClassicEditorBase { }

// Plugins to include in the build.
ClassicEditor.builtinPlugins = [
	Essentials,
	//	UploadAdapter,
	Autoformat,
	Bold,
	Italic,
	BlockQuote,
	//	CKFinder,
	EasyImage,
	Heading,
	Image,
	ImageCaption,
	ImageStyle,
	//	ImageToolbar,
	ImageResize,
	ImageUpload,
	Indent,
	List,
	Paragraph,
	PasteFromOffice,
	Table,
	TableToolbar,
	TextTransformation,
	TableProperties,
	TableCellProperties
];
ClassicEditor.extraPlugins = [ allowNestedTables ]
// Editor configuration.
ClassicEditor.defaultConfig = {
	toolbar: {
		items: [
			'heading',
			'|',
			'bold',
			'italic',
			'bulletedList',
			'numberedList',
			'|',
			'indent',
			'outdent',
			'|',
			'imageUpload',
			'blockQuote',
			'insertTable',
			'undo',
			'redo'
		]
	},
	image: {
		toolbar: [
			'imageStyle:full',
			'imageStyle:side',
			'|',
			'imageTextAlternative'
		]
	},
	table: {
		contentToolbar: [
			'tableColumn',
			'tableRow',
			'mergeTableCells',
			'tableProperties', 'tableCellProperties'
		]
	},
	// This value must be kept in sync with the language defined in webpack.config.js.
	language: 'en'
};

function allowNestedTables ( editor ) {
    editor.model.schema.on('checkChild', (evt, args) => {
        const context = args[0];
        const childDefinition = args[1];
        if (context.endsWith('tableCell') && childDefinition && childDefinition.name == 'table') {
          // Prevent next listeners from being called.
          evt.stop();
          // Set the checkChild()'s return value.
          evt.return = true;
        }
      }, {
        priority: 'highest'
      });
  }

Solved this shifted extra plugins in

ClassicEditor.defaultConfig = {
	extraPlugins: [allowNestedTables], ....

@Reinmar Reinmar added domain:v4-compatibilty domain:v4-compatibility This issue reports a CKEditor 4 feature/option that's missing in CKEditor 5. and removed domain:v4-compatibilty labels Mar 9, 2021
@Mgsy Mgsy modified the milestones: backlog, iteration 41 Mar 11, 2021
Reinmar added a commit that referenced this issue Apr 3, 2021
Feature (table): Enabled support for nested tables. Check out the migration guide for how to disable it again if you do not want to allow nested tables. Closes #3232.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
domain:v4-compatibility This issue reports a CKEditor 4 feature/option that's missing in CKEditor 5. package:table support:2 An issue reported by a commercially licensed client. type:feature This issue reports a feature request (an idea for a new functionality or a missing option).
Projects
None yet
Development

Successfully merging a pull request may close this issue.