Bläddra i källkod

Merge branch 'master' into t/ckeditor5/1265

Kamil Piechaczek 7 år sedan
förälder
incheckning
0763045a1f
25 ändrade filer med 1444 tillägg och 152 borttagningar
  1. 3 0
      packages/ckeditor5-table/.travis.yml
  2. 35 0
      packages/ckeditor5-table/CHANGELOG.md
  3. 78 0
      packages/ckeditor5-table/lang/translations/ar.po
  4. 78 0
      packages/ckeditor5-table/lang/translations/fa.po
  5. 78 0
      packages/ckeditor5-table/lang/translations/fr.po
  6. 78 0
      packages/ckeditor5-table/lang/translations/gl.po
  7. 78 0
      packages/ckeditor5-table/lang/translations/ja.po
  8. 78 0
      packages/ckeditor5-table/lang/translations/ku.po
  9. 78 0
      packages/ckeditor5-table/lang/translations/ne.po
  10. 78 0
      packages/ckeditor5-table/lang/translations/no.po
  11. 78 0
      packages/ckeditor5-table/lang/translations/pl.po
  12. 8 8
      packages/ckeditor5-table/lang/translations/pt-br.po
  13. 78 0
      packages/ckeditor5-table/lang/translations/ru.po
  14. 78 0
      packages/ckeditor5-table/lang/translations/sk.po
  15. 78 0
      packages/ckeditor5-table/lang/translations/sq.po
  16. 16 16
      packages/ckeditor5-table/package.json
  17. 112 0
      packages/ckeditor5-table/src/converters/table-cell-content-post-fixer.js
  18. 27 28
      packages/ckeditor5-table/src/converters/table-layout-post-fixer.js
  19. 75 68
      packages/ckeditor5-table/src/converters/tablecell-post-fixer.js
  20. 4 2
      packages/ckeditor5-table/src/tableediting.js
  21. 1 1
      packages/ckeditor5-table/src/tabletoolbar.js
  22. 3 1
      packages/ckeditor5-table/tests/_utils/utils.js
  23. 126 0
      packages/ckeditor5-table/tests/converters/table-cell-content-post-fixer.js
  24. 1 1
      packages/ckeditor5-table/tests/converters/table-layout-post-fixer.js
  25. 97 27
      packages/ckeditor5-table/tests/converters/tablecell-post-fixer.js

+ 3 - 0
packages/ckeditor5-table/.travis.yml

@@ -12,6 +12,9 @@ node_js:
 - '8'
 - '8'
 cache:
 cache:
 - node_modules
 - node_modules
+branches:
+   except:
+   - stable
 before_install:
 before_install:
 - export DISPLAY=:99.0
 - export DISPLAY=:99.0
 - sh -e /etc/init.d/xvfb start
 - sh -e /etc/init.d/xvfb start

+ 35 - 0
packages/ckeditor5-table/CHANGELOG.md

@@ -1,6 +1,41 @@
 Changelog
 Changelog
 =========
 =========
 
 
+## [11.0.0](https://github.com/ckeditor/ckeditor5-table/compare/v10.1.0...v11.0.0) (2018-10-08)
+
+### Features
+
+* Implemented the table post–fixer which bulletproofs the feature in various complex use–cases (e.g. pasting and real-time collaborative editing). Closes [#13](https://github.com/ckeditor/ckeditor5-table/issues/13). ([01f9a3b](https://github.com/ckeditor/ckeditor5-table/commit/01f9a3b))
+* Introduced the toolbar for the table widget (previously it was available only for single cells). Changed the toolbar configuration option from `table.toolbar` to `table.contentToolbar`. Closes [#113](https://github.com/ckeditor/ckeditor5-table/issues/113). Closes [#106](https://github.com/ckeditor/ckeditor5-table/issues/106). ([9f9486d](https://github.com/ckeditor/ckeditor5-table/commit/9f9486d))
+
+  Other: `config.table.toolbar` is marked as depracted. Use `config.table.contentToolbar` instead.
+* Introduced a support for block content inside tables. Closes [#56](https://github.com/ckeditor/ckeditor5-table/issues/56). ([cdf718e](https://github.com/ckeditor/ckeditor5-table/commit/cdf718e))
+
+### Bug fixes
+
+* A table cell should always have a `<paragraph>` in the model. Closes [#125](https://github.com/ckeditor/ckeditor5-table/issues/125). ([1eb5d6d](https://github.com/ckeditor/ckeditor5-table/commit/1eb5d6d))
+* Downcast converter for table attributes should work with not converted child elements. Closes [#92](https://github.com/ckeditor/ckeditor5-table/issues/92). ([a3ea18d](https://github.com/ckeditor/ckeditor5-table/commit/a3ea18d))
+* Merging down rowspanned cell from the head with a cell in the body is now disabled. Closes [#86](https://github.com/ckeditor/ckeditor5-table/issues/86). ([cb77e38](https://github.com/ckeditor/ckeditor5-table/commit/cb77e38))
+* The upcast conversion will now properly parse inline content in table cell into single paragraph. Closes [ckeditor/ckeditor5#1246](https://github.com/ckeditor/ckeditor5/issues/1246). ([ea1e16d](https://github.com/ckeditor/ckeditor5-table/commit/ea1e16d))
+* Toggling headers should always include the column or row the selection is anchored to. Closes [#34](https://github.com/ckeditor/ckeditor5-table/issues/34). ([bce6766](https://github.com/ckeditor/ckeditor5-table/commit/bce6766))
+
+### Other changes
+
+* Aligned `TableToolbar` to the widget toolbar repository. Closes [#107](https://github.com/ckeditor/ckeditor5-table/issues/107). ([e276e66](https://github.com/ckeditor/ckeditor5-table/commit/e276e66))
+* Media should not be allowed inside table cells for now. Closes [#124](https://github.com/ckeditor/ckeditor5-table/issues/124). ([2f2fe4a](https://github.com/ckeditor/ckeditor5-table/commit/2f2fe4a))
+* Table feature should insert table the same way as other widget features do. Closes [#27](https://github.com/ckeditor/ckeditor5-table/issues/27). ([77d96a4](https://github.com/ckeditor/ckeditor5-table/commit/77d96a4))
+* The table cell view post-fixer should use changed elements from the view to make fixes. Closes [#130](https://github.com/ckeditor/ckeditor5-table/issues/130). ([efc53c9](https://github.com/ckeditor/ckeditor5-table/commit/efc53c9))
+* Updated the table icon which used to feel bulky with a lighter design. Closes [#117](https://github.com/ckeditor/ckeditor5-table/issues/117). ([cd6f5ff](https://github.com/ckeditor/ckeditor5-table/commit/cd6f5ff))
+* Updated translations. ([de47767](https://github.com/ckeditor/ckeditor5-table/commit/de47767))
+
+### BREAKING CHANGES
+
+* The `config.table.toolbar` was renamed to `config.table.contentToolbar`.
+* The `injectTablePostFixer()` function from  `table/converters/table-post-fixer` is now `injectTableLayoutPostFixer()`and is moved to `table/converters/table-layout-post-fixer` module.
+* The `TableUtils#createTable()` method now accepts model `Writer` instance instead of `Position`. The method no longer inserts created table to the model - use returned value instead.
+* Removed `table/commands/utils~getParentTable()` method. Use `table/commands/utils~findAncestor()` instead.
+
+
 ## [10.1.0](https://github.com/ckeditor/ckeditor5-table/compare/v10.0.0...v10.1.0) (2018-07-18)
 ## [10.1.0](https://github.com/ckeditor/ckeditor5-table/compare/v10.0.0...v10.1.0) (2018-07-18)
 
 
 ### Features
 ### Features

+ 78 - 0
packages/ckeditor5-table/lang/translations/ar.po

@@ -0,0 +1,78 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language-Team: Arabic (https://www.transifex.com/ckeditor/teams/11143/ar/)\n"
+"Language: ar\n"
+"Plural-Forms: nplurals=6; plural=n==0 ? 0 : n==1 ? 1 : n==2 ? 2 : n%100>=3 && n%100<=10 ? 3 : n%100>=11 && n%100<=99 ? 4 : 5;\n"
+
+msgctxt "Label for the insert table toolbar button."
+msgid "Insert table"
+msgstr "إدراج جدول"
+
+msgctxt "Label for the set/unset table header column button."
+msgid "Header column"
+msgstr "عمود عنوان"
+
+msgctxt "Label for the insert table column before the current one button."
+msgid "Insert column before"
+msgstr "ادراج عمود قبل"
+
+msgctxt "Label for the insert table column after the current one button."
+msgid "Insert column after"
+msgstr "ادراج عمود بعد"
+
+msgctxt "Label for the delete table column button."
+msgid "Delete column"
+msgstr "حذف العمود"
+
+msgctxt "Label for the table column dropdown button."
+msgid "Column"
+msgstr "عمود"
+
+msgctxt "Label for the set/unset table header row button."
+msgid "Header row"
+msgstr "صف عنوان"
+
+msgctxt "Label for the insert row below button."
+msgid "Insert row below"
+msgstr "ادراج صف بعد"
+
+msgctxt "Label for the insert row above button."
+msgid "Insert row above"
+msgstr "ادراج صف قبل"
+
+msgctxt "Label for the delete table row button."
+msgid "Delete row"
+msgstr "حذف الصف"
+
+msgctxt "Label for the table row dropdown button."
+msgid "Row"
+msgstr "صف"
+
+msgctxt "Label for the merge table cell up button."
+msgid "Merge cell up"
+msgstr "دمج الخلايا للأعلى"
+
+msgctxt "Label for the merge table cell right button."
+msgid "Merge cell right"
+msgstr "دمج الخلايا لليمين"
+
+msgctxt "Label for the merge table cell down button."
+msgid "Merge cell down"
+msgstr "دمج الخلايا للأسفل"
+
+msgctxt "Label for the merge table cell left button."
+msgid "Merge cell left"
+msgstr "دمج الخلايا لليسار"
+
+msgctxt "Label for the split table cell vertically button."
+msgid "Split cell vertically"
+msgstr "فصل الخلايا بشكل عمودي"
+
+msgctxt "Label for the split table cell horizontally button."
+msgid "Split cell horizontally"
+msgstr "فصل الخلايا بشكل افقي"
+
+msgctxt "Label for the merge table cells button."
+msgid "Merge cells"
+msgstr "دمج الخلايا"

+ 78 - 0
packages/ckeditor5-table/lang/translations/fa.po

@@ -0,0 +1,78 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language-Team: Persian (https://www.transifex.com/ckeditor/teams/11143/fa/)\n"
+"Language: fa\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+msgctxt "Label for the insert table toolbar button."
+msgid "Insert table"
+msgstr "درج جدول"
+
+msgctxt "Label for the set/unset table header column button."
+msgid "Header column"
+msgstr "ستون سربرگ"
+
+msgctxt "Label for the insert table column before the current one button."
+msgid "Insert column before"
+msgstr "درج ستون قبل"
+
+msgctxt "Label for the insert table column after the current one button."
+msgid "Insert column after"
+msgstr "درج ستون بعد"
+
+msgctxt "Label for the delete table column button."
+msgid "Delete column"
+msgstr "حذف ستون"
+
+msgctxt "Label for the table column dropdown button."
+msgid "Column"
+msgstr "ستون"
+
+msgctxt "Label for the set/unset table header row button."
+msgid "Header row"
+msgstr "سطر سربرگ"
+
+msgctxt "Label for the insert row below button."
+msgid "Insert row below"
+msgstr "درج سطر در پایین"
+
+msgctxt "Label for the insert row above button."
+msgid "Insert row above"
+msgstr "درج سطر در بالا"
+
+msgctxt "Label for the delete table row button."
+msgid "Delete row"
+msgstr "حذف سطر"
+
+msgctxt "Label for the table row dropdown button."
+msgid "Row"
+msgstr "سطر"
+
+msgctxt "Label for the merge table cell up button."
+msgid "Merge cell up"
+msgstr "ادغام سلول بالا"
+
+msgctxt "Label for the merge table cell right button."
+msgid "Merge cell right"
+msgstr "ادغام سلول راست"
+
+msgctxt "Label for the merge table cell down button."
+msgid "Merge cell down"
+msgstr "ادغام سلول پایین"
+
+msgctxt "Label for the merge table cell left button."
+msgid "Merge cell left"
+msgstr "ادغام سلول چپ"
+
+msgctxt "Label for the split table cell vertically button."
+msgid "Split cell vertically"
+msgstr "تقسیم عمودی سلول"
+
+msgctxt "Label for the split table cell horizontally button."
+msgid "Split cell horizontally"
+msgstr "تقسیم افقی سلول"
+
+msgctxt "Label for the merge table cells button."
+msgid "Merge cells"
+msgstr "ادغام سلول ها"

+ 78 - 0
packages/ckeditor5-table/lang/translations/fr.po

@@ -0,0 +1,78 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language-Team: French (https://www.transifex.com/ckeditor/teams/11143/fr/)\n"
+"Language: fr\n"
+"Plural-Forms: nplurals=2; plural=(n > 1);\n"
+
+msgctxt "Label for the insert table toolbar button."
+msgid "Insert table"
+msgstr "Insérer un tableau"
+
+msgctxt "Label for the set/unset table header column button."
+msgid "Header column"
+msgstr "Colonne d'entête"
+
+msgctxt "Label for the insert table column before the current one button."
+msgid "Insert column before"
+msgstr "Insérer une colonne avant"
+
+msgctxt "Label for the insert table column after the current one button."
+msgid "Insert column after"
+msgstr "Insérer une colonne après"
+
+msgctxt "Label for the delete table column button."
+msgid "Delete column"
+msgstr "Supprimer la colonne"
+
+msgctxt "Label for the table column dropdown button."
+msgid "Column"
+msgstr "Colonne"
+
+msgctxt "Label for the set/unset table header row button."
+msgid "Header row"
+msgstr "Rangée d'entête"
+
+msgctxt "Label for the insert row below button."
+msgid "Insert row below"
+msgstr "Insérer une rangée en-dessous"
+
+msgctxt "Label for the insert row above button."
+msgid "Insert row above"
+msgstr "Insérer une rangée au-dessus"
+
+msgctxt "Label for the delete table row button."
+msgid "Delete row"
+msgstr "Supprimer la rangée"
+
+msgctxt "Label for the table row dropdown button."
+msgid "Row"
+msgstr "Rangée"
+
+msgctxt "Label for the merge table cell up button."
+msgid "Merge cell up"
+msgstr "Fusionner la cellule au-dessus"
+
+msgctxt "Label for the merge table cell right button."
+msgid "Merge cell right"
+msgstr "Fusionner la cellule à droite"
+
+msgctxt "Label for the merge table cell down button."
+msgid "Merge cell down"
+msgstr "Fusionner la cellule en-dessous"
+
+msgctxt "Label for the merge table cell left button."
+msgid "Merge cell left"
+msgstr "Fusionner la cellule à gauche"
+
+msgctxt "Label for the split table cell vertically button."
+msgid "Split cell vertically"
+msgstr "Séparer la cellule verticalement"
+
+msgctxt "Label for the split table cell horizontally button."
+msgid "Split cell horizontally"
+msgstr "Séparer la cellule horizontalement"
+
+msgctxt "Label for the merge table cells button."
+msgid "Merge cells"
+msgstr "Fusionner les cellules"

+ 78 - 0
packages/ckeditor5-table/lang/translations/gl.po

@@ -0,0 +1,78 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language-Team: Galician (https://www.transifex.com/ckeditor/teams/11143/gl/)\n"
+"Language: gl\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgctxt "Label for the insert table toolbar button."
+msgid "Insert table"
+msgstr "Inserir táboa"
+
+msgctxt "Label for the set/unset table header column button."
+msgid "Header column"
+msgstr "Cabeceira de columna"
+
+msgctxt "Label for the insert table column before the current one button."
+msgid "Insert column before"
+msgstr "Inserir columna á esquerda"
+
+msgctxt "Label for the insert table column after the current one button."
+msgid "Insert column after"
+msgstr "Inserir columna á dereita"
+
+msgctxt "Label for the delete table column button."
+msgid "Delete column"
+msgstr "Eliminar columna"
+
+msgctxt "Label for the table column dropdown button."
+msgid "Column"
+msgstr "Columna"
+
+msgctxt "Label for the set/unset table header row button."
+msgid "Header row"
+msgstr "Cabeceira de fila"
+
+msgctxt "Label for the insert row below button."
+msgid "Insert row below"
+msgstr "Inserir fila embaixo"
+
+msgctxt "Label for the insert row above button."
+msgid "Insert row above"
+msgstr "Inserir fila enriba"
+
+msgctxt "Label for the delete table row button."
+msgid "Delete row"
+msgstr "Eliminar fila"
+
+msgctxt "Label for the table row dropdown button."
+msgid "Row"
+msgstr "Fila"
+
+msgctxt "Label for the merge table cell up button."
+msgid "Merge cell up"
+msgstr "Combinar cela cara arriba"
+
+msgctxt "Label for the merge table cell right button."
+msgid "Merge cell right"
+msgstr "Combinar cela cara a dereita"
+
+msgctxt "Label for the merge table cell down button."
+msgid "Merge cell down"
+msgstr "Combinar cela cara  abaixo"
+
+msgctxt "Label for the merge table cell left button."
+msgid "Merge cell left"
+msgstr "Combinar cela cara a esquerda"
+
+msgctxt "Label for the split table cell vertically button."
+msgid "Split cell vertically"
+msgstr "Dividir cela en vertical"
+
+msgctxt "Label for the split table cell horizontally button."
+msgid "Split cell horizontally"
+msgstr "Dividir cela en horizontal"
+
+msgctxt "Label for the merge table cells button."
+msgid "Merge cells"
+msgstr "Combinar celas"

+ 78 - 0
packages/ckeditor5-table/lang/translations/ja.po

@@ -0,0 +1,78 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language-Team: Japanese (https://www.transifex.com/ckeditor/teams/11143/ja/)\n"
+"Language: ja\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+msgctxt "Label for the insert table toolbar button."
+msgid "Insert table"
+msgstr "表の挿入"
+
+msgctxt "Label for the set/unset table header column button."
+msgid "Header column"
+msgstr "見出し列"
+
+msgctxt "Label for the insert table column before the current one button."
+msgid "Insert column before"
+msgstr "左に列を挿入"
+
+msgctxt "Label for the insert table column after the current one button."
+msgid "Insert column after"
+msgstr "\b右に列を挿入"
+
+msgctxt "Label for the delete table column button."
+msgid "Delete column"
+msgstr "列を削除"
+
+msgctxt "Label for the table column dropdown button."
+msgid "Column"
+msgstr "列"
+
+msgctxt "Label for the set/unset table header row button."
+msgid "Header row"
+msgstr "見出し行"
+
+msgctxt "Label for the insert row below button."
+msgid "Insert row below"
+msgstr "下に行を挿入"
+
+msgctxt "Label for the insert row above button."
+msgid "Insert row above"
+msgstr "上に行を挿入"
+
+msgctxt "Label for the delete table row button."
+msgid "Delete row"
+msgstr "行を削除"
+
+msgctxt "Label for the table row dropdown button."
+msgid "Row"
+msgstr "行"
+
+msgctxt "Label for the merge table cell up button."
+msgid "Merge cell up"
+msgstr "上のセルと結合"
+
+msgctxt "Label for the merge table cell right button."
+msgid "Merge cell right"
+msgstr "右のセルと結合"
+
+msgctxt "Label for the merge table cell down button."
+msgid "Merge cell down"
+msgstr "下のセルと結合"
+
+msgctxt "Label for the merge table cell left button."
+msgid "Merge cell left"
+msgstr "左のセルと結合"
+
+msgctxt "Label for the split table cell vertically button."
+msgid "Split cell vertically"
+msgstr "横にセルを分離"
+
+msgctxt "Label for the split table cell horizontally button."
+msgid "Split cell horizontally"
+msgstr "縦にセルを分離"
+
+msgctxt "Label for the merge table cells button."
+msgid "Merge cells"
+msgstr "セルを結合"

+ 78 - 0
packages/ckeditor5-table/lang/translations/ku.po

@@ -0,0 +1,78 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language-Team: Kurdish (https://www.transifex.com/ckeditor/teams/11143/ku/)\n"
+"Language: ku\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgctxt "Label for the insert table toolbar button."
+msgid "Insert table"
+msgstr "خشتە دابنێ"
+
+msgctxt "Label for the set/unset table header column button."
+msgid "Header column"
+msgstr "ستوونی دەسپێک"
+
+msgctxt "Label for the insert table column before the current one button."
+msgid "Insert column before"
+msgstr "لە پێش دانانی ستوون"
+
+msgctxt "Label for the insert table column after the current one button."
+msgid "Insert column after"
+msgstr "لەدووا دانانی ستوون"
+
+msgctxt "Label for the delete table column button."
+msgid "Delete column"
+msgstr "سڕینەوەی ستوون"
+
+msgctxt "Label for the table column dropdown button."
+msgid "Column"
+msgstr "ستوون"
+
+msgctxt "Label for the set/unset table header row button."
+msgid "Header row"
+msgstr "ڕیزی دەسپێک"
+
+msgctxt "Label for the insert row below button."
+msgid "Insert row below"
+msgstr "دانانی ڕیز لە ژێرەوە"
+
+msgctxt "Label for the insert row above button."
+msgid "Insert row above"
+msgstr "دانانی ڕیز لە سەرەوە"
+
+msgctxt "Label for the delete table row button."
+msgid "Delete row"
+msgstr "سڕینەوەی ڕیز"
+
+msgctxt "Label for the table row dropdown button."
+msgid "Row"
+msgstr "ڕیز"
+
+msgctxt "Label for the merge table cell up button."
+msgid "Merge cell up"
+msgstr "تێکەڵکردنی خانەکان بەرەو سەر"
+
+msgctxt "Label for the merge table cell right button."
+msgid "Merge cell right"
+msgstr "تێکەڵکردنی خانەکان بەرەو ڕاست"
+
+msgctxt "Label for the merge table cell down button."
+msgid "Merge cell down"
+msgstr "تێکەڵکردنی خانەکان بەرەو ژێرەوە"
+
+msgctxt "Label for the merge table cell left button."
+msgid "Merge cell left"
+msgstr "تێکەڵکردنی خانەکان بەرەو چەپ"
+
+msgctxt "Label for the split table cell vertically button."
+msgid "Split cell vertically"
+msgstr "بەشکردنی خانەکان بە ئەستوونی"
+
+msgctxt "Label for the split table cell horizontally button."
+msgid "Split cell horizontally"
+msgstr "بەشکردنی خانەکان بە ئاسۆیی"
+
+msgctxt "Label for the merge table cells button."
+msgid "Merge cells"
+msgstr "تێکەڵکردنی خانەکان"

+ 78 - 0
packages/ckeditor5-table/lang/translations/ne.po

@@ -0,0 +1,78 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language-Team: Nepali (Nepal) (https://www.transifex.com/ckeditor/teams/11143/ne_NP/)\n"
+"Language: ne_NP\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgctxt "Label for the insert table toolbar button."
+msgid "Insert table"
+msgstr "तालिका सम्मिलित गर्नुहोस्"
+
+msgctxt "Label for the set/unset table header column button."
+msgid "Header column"
+msgstr "हेडर स्तम्भ"
+
+msgctxt "Label for the insert table column before the current one button."
+msgid "Insert column before"
+msgstr "अगाडि स्तम्भ सम्मिलित गर्नुहोस्"
+
+msgctxt "Label for the insert table column after the current one button."
+msgid "Insert column after"
+msgstr "पछि स्तम्भ सम्मिलित गर्नुहोस्"
+
+msgctxt "Label for the delete table column button."
+msgid "Delete column"
+msgstr "स्तम्भ मेटाउनुहोस्"
+
+msgctxt "Label for the table column dropdown button."
+msgid "Column"
+msgstr "स्तम्भ"
+
+msgctxt "Label for the set/unset table header row button."
+msgid "Header row"
+msgstr "हेडर पङ्क्ति"
+
+msgctxt "Label for the insert row below button."
+msgid "Insert row below"
+msgstr "तल पंक्ति सम्मिलित गर्नुहोस्"
+
+msgctxt "Label for the insert row above button."
+msgid "Insert row above"
+msgstr "माथि पंक्ति सम्मिलित गर्नुहोस्"
+
+msgctxt "Label for the delete table row button."
+msgid "Delete row"
+msgstr "पङ्क्ति मेटाउनुहोस्"
+
+msgctxt "Label for the table row dropdown button."
+msgid "Row"
+msgstr "पङ्क्ति"
+
+msgctxt "Label for the merge table cell up button."
+msgid "Merge cell up"
+msgstr "कक्ष माथि मर्ज गर्नुहोस्"
+
+msgctxt "Label for the merge table cell right button."
+msgid "Merge cell right"
+msgstr "दायाँ कक्ष मर्ज गर्नुहोस्"
+
+msgctxt "Label for the merge table cell down button."
+msgid "Merge cell down"
+msgstr "कक्ष तल मर्ज गर्नुहोस्"
+
+msgctxt "Label for the merge table cell left button."
+msgid "Merge cell left"
+msgstr "सेल बायाँ मर्ज गर्नुहोस्"
+
+msgctxt "Label for the split table cell vertically button."
+msgid "Split cell vertically"
+msgstr "ठाडो कक्ष विभाजित गर्नुहोस्"
+
+msgctxt "Label for the split table cell horizontally button."
+msgid "Split cell horizontally"
+msgstr "क्षैतिज कक्ष विभाजित गर्नुहोस्"
+
+msgctxt "Label for the merge table cells button."
+msgid "Merge cells"
+msgstr "कक्ष मर्ज गर्नुहोस्"

+ 78 - 0
packages/ckeditor5-table/lang/translations/no.po

@@ -0,0 +1,78 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language-Team: Norwegian (https://www.transifex.com/ckeditor/teams/11143/no/)\n"
+"Language: no\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgctxt "Label for the insert table toolbar button."
+msgid "Insert table"
+msgstr "Sett inn tabell"
+
+msgctxt "Label for the set/unset table header column button."
+msgid "Header column"
+msgstr "Overskriftkolonne"
+
+msgctxt "Label for the insert table column before the current one button."
+msgid "Insert column before"
+msgstr "Sett inn kolonne før"
+
+msgctxt "Label for the insert table column after the current one button."
+msgid "Insert column after"
+msgstr "Sett inn kolonne etter"
+
+msgctxt "Label for the delete table column button."
+msgid "Delete column"
+msgstr "Slett kolonne"
+
+msgctxt "Label for the table column dropdown button."
+msgid "Column"
+msgstr "Kolonne"
+
+msgctxt "Label for the set/unset table header row button."
+msgid "Header row"
+msgstr "Overskriftrad"
+
+msgctxt "Label for the insert row below button."
+msgid "Insert row below"
+msgstr "Sett inn rad under"
+
+msgctxt "Label for the insert row above button."
+msgid "Insert row above"
+msgstr "Sett inn rad over"
+
+msgctxt "Label for the delete table row button."
+msgid "Delete row"
+msgstr "Slett rad"
+
+msgctxt "Label for the table row dropdown button."
+msgid "Row"
+msgstr "Rad"
+
+msgctxt "Label for the merge table cell up button."
+msgid "Merge cell up"
+msgstr "Slå sammen celle over"
+
+msgctxt "Label for the merge table cell right button."
+msgid "Merge cell right"
+msgstr "Slå sammen celle til høyre"
+
+msgctxt "Label for the merge table cell down button."
+msgid "Merge cell down"
+msgstr "Slå sammen celle under"
+
+msgctxt "Label for the merge table cell left button."
+msgid "Merge cell left"
+msgstr "Slå sammen celle til venstre"
+
+msgctxt "Label for the split table cell vertically button."
+msgid "Split cell vertically"
+msgstr "Del opp celle vertikalt"
+
+msgctxt "Label for the split table cell horizontally button."
+msgid "Split cell horizontally"
+msgstr "Del opp celle horisontalt"
+
+msgctxt "Label for the merge table cells button."
+msgid "Merge cells"
+msgstr "Slå sammen celler"

+ 78 - 0
packages/ckeditor5-table/lang/translations/pl.po

@@ -0,0 +1,78 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language-Team: Polish (https://www.transifex.com/ckeditor/teams/11143/pl/)\n"
+"Language: pl\n"
+"Plural-Forms: nplurals=4; plural=(n==1 ? 0 : (n%10>=2 && n%10<=4) && (n%100<12 || n%100>14) ? 1 : n!=1 && (n%10>=0 && n%10<=1) || (n%10>=5 && n%10<=9) || (n%100>=12 && n%100<=14) ? 2 : 3);\n"
+
+msgctxt "Label for the insert table toolbar button."
+msgid "Insert table"
+msgstr "Wstaw tabelę"
+
+msgctxt "Label for the set/unset table header column button."
+msgid "Header column"
+msgstr "Kolumna nagłówka"
+
+msgctxt "Label for the insert table column before the current one button."
+msgid "Insert column before"
+msgstr "Wstaw kolumnę przed"
+
+msgctxt "Label for the insert table column after the current one button."
+msgid "Insert column after"
+msgstr "Wstaw kolumnę po"
+
+msgctxt "Label for the delete table column button."
+msgid "Delete column"
+msgstr "Usuń kolumnę"
+
+msgctxt "Label for the table column dropdown button."
+msgid "Column"
+msgstr "Kolumna"
+
+msgctxt "Label for the set/unset table header row button."
+msgid "Header row"
+msgstr "Wiersz nagłówka"
+
+msgctxt "Label for the insert row below button."
+msgid "Insert row below"
+msgstr "Wstaw wiersz poniżej"
+
+msgctxt "Label for the insert row above button."
+msgid "Insert row above"
+msgstr "Wstaw wiersz ponad"
+
+msgctxt "Label for the delete table row button."
+msgid "Delete row"
+msgstr "Usuń wiersz"
+
+msgctxt "Label for the table row dropdown button."
+msgid "Row"
+msgstr "Wiersz"
+
+msgctxt "Label for the merge table cell up button."
+msgid "Merge cell up"
+msgstr "Scal komórkę w górę"
+
+msgctxt "Label for the merge table cell right button."
+msgid "Merge cell right"
+msgstr "Scal komórkę w prawo"
+
+msgctxt "Label for the merge table cell down button."
+msgid "Merge cell down"
+msgstr "Scal komórkę w dół"
+
+msgctxt "Label for the merge table cell left button."
+msgid "Merge cell left"
+msgstr "Scal komórkę w lewo"
+
+msgctxt "Label for the split table cell vertically button."
+msgid "Split cell vertically"
+msgstr "Podziel komórkę pionowo"
+
+msgctxt "Label for the split table cell horizontally button."
+msgid "Split cell horizontally"
+msgstr "Podziel komórkę poziomo"
+
+msgctxt "Label for the merge table cells button."
+msgid "Merge cells"
+msgstr "Scal komórki"

+ 8 - 8
packages/ckeditor5-table/lang/translations/pt-br.po

@@ -11,7 +11,7 @@ msgstr "Inserir tabela"
 
 
 msgctxt "Label for the set/unset table header column button."
 msgctxt "Label for the set/unset table header column button."
 msgid "Header column"
 msgid "Header column"
-msgstr ""
+msgstr "Coluna de cabeçalho"
 
 
 msgctxt "Label for the insert table column before the current one button."
 msgctxt "Label for the insert table column before the current one button."
 msgid "Insert column before"
 msgid "Insert column before"
@@ -31,7 +31,7 @@ msgstr "Coluna"
 
 
 msgctxt "Label for the set/unset table header row button."
 msgctxt "Label for the set/unset table header row button."
 msgid "Header row"
 msgid "Header row"
-msgstr ""
+msgstr "Linha de cabeçalho"
 
 
 msgctxt "Label for the insert row below button."
 msgctxt "Label for the insert row below button."
 msgid "Insert row below"
 msgid "Insert row below"
@@ -51,27 +51,27 @@ msgstr "Linha"
 
 
 msgctxt "Label for the merge table cell up button."
 msgctxt "Label for the merge table cell up button."
 msgid "Merge cell up"
 msgid "Merge cell up"
-msgstr ""
+msgstr "Mesclar acima"
 
 
 msgctxt "Label for the merge table cell right button."
 msgctxt "Label for the merge table cell right button."
 msgid "Merge cell right"
 msgid "Merge cell right"
-msgstr ""
+msgstr "Mesclar à direita"
 
 
 msgctxt "Label for the merge table cell down button."
 msgctxt "Label for the merge table cell down button."
 msgid "Merge cell down"
 msgid "Merge cell down"
-msgstr ""
+msgstr "Mesclar abaixo"
 
 
 msgctxt "Label for the merge table cell left button."
 msgctxt "Label for the merge table cell left button."
 msgid "Merge cell left"
 msgid "Merge cell left"
-msgstr ""
+msgstr "Mesclar à esquerda"
 
 
 msgctxt "Label for the split table cell vertically button."
 msgctxt "Label for the split table cell vertically button."
 msgid "Split cell vertically"
 msgid "Split cell vertically"
-msgstr ""
+msgstr "Dividir verticalmente"
 
 
 msgctxt "Label for the split table cell horizontally button."
 msgctxt "Label for the split table cell horizontally button."
 msgid "Split cell horizontally"
 msgid "Split cell horizontally"
-msgstr ""
+msgstr "Dividir horizontalmente"
 
 
 msgctxt "Label for the merge table cells button."
 msgctxt "Label for the merge table cells button."
 msgid "Merge cells"
 msgid "Merge cells"

+ 78 - 0
packages/ckeditor5-table/lang/translations/ru.po

@@ -0,0 +1,78 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language-Team: Russian (https://www.transifex.com/ckeditor/teams/11143/ru/)\n"
+"Language: ru\n"
+"Plural-Forms: nplurals=4; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && n%10<=4 && (n%100<12 || n%100>14) ? 1 : n%10==0 || (n%10>=5 && n%10<=9) || (n%100>=11 && n%100<=14)? 2 : 3);\n"
+
+msgctxt "Label for the insert table toolbar button."
+msgid "Insert table"
+msgstr "Вставить таблицу"
+
+msgctxt "Label for the set/unset table header column button."
+msgid "Header column"
+msgstr "Столбец заголовков"
+
+msgctxt "Label for the insert table column before the current one button."
+msgid "Insert column before"
+msgstr "Вставить столбец левее"
+
+msgctxt "Label for the insert table column after the current one button."
+msgid "Insert column after"
+msgstr "Вставить столбец правее"
+
+msgctxt "Label for the delete table column button."
+msgid "Delete column"
+msgstr "Удалить столбец"
+
+msgctxt "Label for the table column dropdown button."
+msgid "Column"
+msgstr "Столбец"
+
+msgctxt "Label for the set/unset table header row button."
+msgid "Header row"
+msgstr "Строка заголовков"
+
+msgctxt "Label for the insert row below button."
+msgid "Insert row below"
+msgstr "Вставить строку выше"
+
+msgctxt "Label for the insert row above button."
+msgid "Insert row above"
+msgstr "Вставить строку ниже"
+
+msgctxt "Label for the delete table row button."
+msgid "Delete row"
+msgstr "Удалить строку"
+
+msgctxt "Label for the table row dropdown button."
+msgid "Row"
+msgstr "Строка"
+
+msgctxt "Label for the merge table cell up button."
+msgid "Merge cell up"
+msgstr "Объединить с ячейкой сверху"
+
+msgctxt "Label for the merge table cell right button."
+msgid "Merge cell right"
+msgstr "Объединить с ячейкой справа"
+
+msgctxt "Label for the merge table cell down button."
+msgid "Merge cell down"
+msgstr "Объединить с ячейкой снизу"
+
+msgctxt "Label for the merge table cell left button."
+msgid "Merge cell left"
+msgstr "Объединить с ячейкой слева"
+
+msgctxt "Label for the split table cell vertically button."
+msgid "Split cell vertically"
+msgstr "Разделить ячейку вертикально"
+
+msgctxt "Label for the split table cell horizontally button."
+msgid "Split cell horizontally"
+msgstr "Разделить ячейку горизонтально"
+
+msgctxt "Label for the merge table cells button."
+msgid "Merge cells"
+msgstr "Объединить ячейки"

+ 78 - 0
packages/ckeditor5-table/lang/translations/sk.po

@@ -0,0 +1,78 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language-Team: Slovak (https://www.transifex.com/ckeditor/teams/11143/sk/)\n"
+"Language: sk\n"
+"Plural-Forms: nplurals=4; plural=(n % 1 == 0 && n == 1 ? 0 : n % 1 == 0 && n >= 2 && n <= 4 ? 1 : n % 1 != 0 ? 2: 3);\n"
+
+msgctxt "Label for the insert table toolbar button."
+msgid "Insert table"
+msgstr "Vložiť tabuľku"
+
+msgctxt "Label for the set/unset table header column button."
+msgid "Header column"
+msgstr "Stĺpec hlavičky"
+
+msgctxt "Label for the insert table column before the current one button."
+msgid "Insert column before"
+msgstr "Vložiť stĺpec vľavo"
+
+msgctxt "Label for the insert table column after the current one button."
+msgid "Insert column after"
+msgstr "Vložiť stĺpec vpravo"
+
+msgctxt "Label for the delete table column button."
+msgid "Delete column"
+msgstr "Odstrániť stĺpec"
+
+msgctxt "Label for the table column dropdown button."
+msgid "Column"
+msgstr "Stĺpec"
+
+msgctxt "Label for the set/unset table header row button."
+msgid "Header row"
+msgstr "Riadok hlavičky"
+
+msgctxt "Label for the insert row below button."
+msgid "Insert row below"
+msgstr "Vložiť riadok pod"
+
+msgctxt "Label for the insert row above button."
+msgid "Insert row above"
+msgstr "Vložiť riadok nad"
+
+msgctxt "Label for the delete table row button."
+msgid "Delete row"
+msgstr "Odstrániť riadok"
+
+msgctxt "Label for the table row dropdown button."
+msgid "Row"
+msgstr "Riadok"
+
+msgctxt "Label for the merge table cell up button."
+msgid "Merge cell up"
+msgstr "Zlúčiť bunku hore"
+
+msgctxt "Label for the merge table cell right button."
+msgid "Merge cell right"
+msgstr "Zlúčiť bunku vpravo"
+
+msgctxt "Label for the merge table cell down button."
+msgid "Merge cell down"
+msgstr "Zlúčiť bunku dole"
+
+msgctxt "Label for the merge table cell left button."
+msgid "Merge cell left"
+msgstr "Zlúčiť bunku vľavo"
+
+msgctxt "Label for the split table cell vertically button."
+msgid "Split cell vertically"
+msgstr "Rozdeliť bunku zvislo"
+
+msgctxt "Label for the split table cell horizontally button."
+msgid "Split cell horizontally"
+msgstr "Rozdeliť bunku vodorovne"
+
+msgctxt "Label for the merge table cells button."
+msgid "Merge cells"
+msgstr "Zlúčiť bunky"

+ 78 - 0
packages/ckeditor5-table/lang/translations/sq.po

@@ -0,0 +1,78 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language-Team: Albanian (https://www.transifex.com/ckeditor/teams/11143/sq/)\n"
+"Language: sq\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgctxt "Label for the insert table toolbar button."
+msgid "Insert table"
+msgstr "Shto tabelë"
+
+msgctxt "Label for the set/unset table header column button."
+msgid "Header column"
+msgstr "Kolona e kokës"
+
+msgctxt "Label for the insert table column before the current one button."
+msgid "Insert column before"
+msgstr "Shto kolonë para"
+
+msgctxt "Label for the insert table column after the current one button."
+msgid "Insert column after"
+msgstr "Shto kolonë pas"
+
+msgctxt "Label for the delete table column button."
+msgid "Delete column"
+msgstr "Gris kolonën"
+
+msgctxt "Label for the table column dropdown button."
+msgid "Column"
+msgstr "Kolona"
+
+msgctxt "Label for the set/unset table header row button."
+msgid "Header row"
+msgstr "Rreshti i kokës"
+
+msgctxt "Label for the insert row below button."
+msgid "Insert row below"
+msgstr "Shto rresht poshtë"
+
+msgctxt "Label for the insert row above button."
+msgid "Insert row above"
+msgstr "Shto rresht sipër"
+
+msgctxt "Label for the delete table row button."
+msgid "Delete row"
+msgstr "Grish rreshtin"
+
+msgctxt "Label for the table row dropdown button."
+msgid "Row"
+msgstr "Rreshti"
+
+msgctxt "Label for the merge table cell up button."
+msgid "Merge cell up"
+msgstr "Bashko kutizat sipër"
+
+msgctxt "Label for the merge table cell right button."
+msgid "Merge cell right"
+msgstr "Bashko kutizat djathtas"
+
+msgctxt "Label for the merge table cell down button."
+msgid "Merge cell down"
+msgstr "Bashko kutizat poshtë"
+
+msgctxt "Label for the merge table cell left button."
+msgid "Merge cell left"
+msgstr "Bashko kutizat majtas"
+
+msgctxt "Label for the split table cell vertically button."
+msgid "Split cell vertically"
+msgstr "Ndajë kutizat vertikalisht"
+
+msgctxt "Label for the split table cell horizontally button."
+msgid "Split cell horizontally"
+msgstr "Ndaj kutizat horizontalisht"
+
+msgctxt "Label for the merge table cells button."
+msgid "Merge cells"
+msgstr "Bashko kutizat"

+ 16 - 16
packages/ckeditor5-table/package.json

@@ -1,6 +1,6 @@
 {
 {
   "name": "@ckeditor/ckeditor5-table",
   "name": "@ckeditor/ckeditor5-table",
-  "version": "10.1.0",
+  "version": "11.0.0",
   "description": "Table feature for CKEditor 5.",
   "description": "Table feature for CKEditor 5.",
   "keywords": [
   "keywords": [
     "ckeditor",
     "ckeditor",
@@ -10,23 +10,23 @@
     "ckeditor5-plugin"
     "ckeditor5-plugin"
   ],
   ],
   "dependencies": {
   "dependencies": {
-    "@ckeditor/ckeditor5-core": "^11.0.0",
-    "@ckeditor/ckeditor5-engine": "^10.2.0",
-    "@ckeditor/ckeditor5-ui": "^11.0.0",
-    "@ckeditor/ckeditor5-widget": "^10.2.0"
+    "@ckeditor/ckeditor5-core": "^11.0.1",
+    "@ckeditor/ckeditor5-engine": "^11.0.0",
+    "@ckeditor/ckeditor5-ui": "^11.1.0",
+    "@ckeditor/ckeditor5-widget": "^10.3.0"
   },
   },
   "devDependencies": {
   "devDependencies": {
-    "@ckeditor/ckeditor5-alignment": "^10.0.2",
-    "@ckeditor/ckeditor5-block-quote": "^10.0.2",
-    "@ckeditor/ckeditor5-clipboard": "^10.0.2",
-    "@ckeditor/ckeditor5-editor-classic": "^11.0.0",
-    "@ckeditor/ckeditor5-image": "^10.2.0",
-    "@ckeditor/ckeditor5-list": "^11.0.1",
-    "@ckeditor/ckeditor5-media-embed": "^0.0.1",
-    "@ckeditor/ckeditor5-paragraph": "^10.0.2",
-    "@ckeditor/ckeditor5-typing": "^11.0.0",
-    "@ckeditor/ckeditor5-undo": "^10.0.2",
-    "@ckeditor/ckeditor5-utils": "^10.2.0",
+    "@ckeditor/ckeditor5-alignment": "^10.0.3",
+    "@ckeditor/ckeditor5-block-quote": "^10.1.0",
+    "@ckeditor/ckeditor5-clipboard": "^10.0.3",
+    "@ckeditor/ckeditor5-editor-classic": "^11.0.1",
+    "@ckeditor/ckeditor5-image": "^11.0.0",
+    "@ckeditor/ckeditor5-list": "^11.0.2",
+    "@ckeditor/ckeditor5-media-embed": "^10.0.0",
+    "@ckeditor/ckeditor5-paragraph": "^10.0.3",
+    "@ckeditor/ckeditor5-typing": "^11.0.1",
+    "@ckeditor/ckeditor5-undo": "^10.0.3",
+    "@ckeditor/ckeditor5-utils": "^11.0.0",
     "eslint": "^5.5.0",
     "eslint": "^5.5.0",
     "eslint-config-ckeditor5": "^1.0.7",
     "eslint-config-ckeditor5": "^1.0.7",
     "husky": "^0.14.3",
     "husky": "^0.14.3",

+ 112 - 0
packages/ckeditor5-table/src/converters/table-cell-content-post-fixer.js

@@ -0,0 +1,112 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @module table/converters/table-cell-content-post-fixer
+ */
+
+/**
+ * Injects a table cell post-fixer into the model.
+ *
+ * The role of the table post-fixer is to ensure that the table cells have the correct content
+ * after a {@link module:engine/model/model~Model#change `change()`} block was executed.
+ *
+ * A table cells must contains at least one block as a child. The empty table cell will have empty `<paragraph>` as a child.
+ *
+ *        <table>
+ *            <tableRow>
+ *                <tableCell></tableCell>
+ *            </tableRow>
+ *        </table>
+ *
+ * Will be fixed to:
+ *
+ *        <table>
+ *            <tableRow>
+ *                <tableCell><paragraph></paragraph></tableCell>
+ *            </tableRow>
+ *        </table>
+ *
+ * @param {module:engine/model/model~Model} model
+ */
+export default function injectTableCellContentPostFixer( model ) {
+	model.document.registerPostFixer( writer => tableCellContentsPostFixer( writer, model ) );
+}
+
+// The table cell contents post-fixer.
+//
+// @param {module:engine/model/writer~Writer} writer
+// @param {module:engine/model/model~Model} model
+function tableCellContentsPostFixer( writer, model ) {
+	const changes = model.document.differ.getChanges();
+
+	let wasFixed = false;
+
+	for ( const entry of changes ) {
+		// Enforce paragraph in tableCell even after other feature remove its contents.
+		if ( entry.type == 'remove' && entry.position.parent.is( 'tableCell' ) ) {
+			wasFixed = fixTableCellContent( entry.position.parent, writer ) || wasFixed;
+		}
+
+		// Analyze table cells on insertion.
+		if ( entry.type == 'insert' ) {
+			if ( entry.name == 'table' ) {
+				wasFixed = fixTable( entry.position.nodeAfter, writer ) || wasFixed;
+			}
+
+			if ( entry.name == 'tableRow' ) {
+				wasFixed = fixTableRow( entry.position.nodeAfter, writer ) || wasFixed;
+			}
+
+			if ( entry.name == 'tableCell' ) {
+				wasFixed = fixTableCellContent( entry.position.nodeAfter, writer ) || wasFixed;
+			}
+		}
+	}
+
+	return wasFixed;
+}
+
+// Fixes all table cells in a table.
+//
+// @param {module:engine/model/element~Element} table
+// @param {module:engine/model/writer~Writer} writer
+function fixTable( table, writer ) {
+	let wasFixed = false;
+
+	for ( const row of table.getChildren() ) {
+		wasFixed = fixTableRow( row, writer ) || wasFixed;
+	}
+
+	return wasFixed;
+}
+
+// Fixes all table cells in a table row.
+//
+// @param {module:engine/model/element~Element} tableRow
+// @param {module:engine/model/writer~Writer} writer
+function fixTableRow( tableRow, writer ) {
+	let wasFixed = false;
+
+	for ( const tableCell of tableRow.getChildren() ) {
+		wasFixed = fixTableCellContent( tableCell, writer ) || wasFixed;
+	}
+
+	return wasFixed;
+}
+
+// Fixes all table cell content by adding paragraph to a table cell without any child.
+//
+// @param {module:engine/model/element~Element} table
+// @param {module:engine/model/writer~Writer} writer
+function fixTableCellContent( tableCell, writer ) {
+	if ( tableCell.childCount == 0 ) {
+		writer.insertElement( 'paragraph', tableCell );
+
+		return true;
+	}
+
+	return false;
+}

+ 27 - 28
packages/ckeditor5-table/src/converters/table-post-fixer.js → packages/ckeditor5-table/src/converters/table-layout-post-fixer.js

@@ -4,7 +4,7 @@
  */
  */
 
 
 /**
 /**
- * @module table/converters/table-post-fixer
+ * @module table/converters/table-layout-post-fixer
  */
  */
 
 
 import Position from '@ckeditor/ckeditor5-engine/src/model/position';
 import Position from '@ckeditor/ckeditor5-engine/src/model/position';
@@ -12,15 +12,16 @@ import { createEmptyTableCell, findAncestor, updateNumericAttribute } from './..
 import TableWalker from './../tablewalker';
 import TableWalker from './../tablewalker';
 
 
 /**
 /**
- * Injects a table post-fixer into the model.
+ * Injects a table layout post-fixer into the model.
  *
  *
- * The role of the table post-fixer is to ensure that the table rows have the correct structure
+ * The role of the table layout post-fixer is to ensure that the table rows have the correct structure
  * after a {@link module:engine/model/model~Model#change `change()`} block was executed.
  * after a {@link module:engine/model/model~Model#change `change()`} block was executed.
  *
  *
  * The correct structure means that:
  * The correct structure means that:
  *
  *
  * * All table rows have the same size.
  * * All table rows have the same size.
  * * None of a table cells that extend vertically beyond their section (either header or body).
  * * None of a table cells that extend vertically beyond their section (either header or body).
+ * * A table cell has always at least one element as child.
  *
  *
  * If the table structure is not correct, the post-fixer will automatically correct it in two steps:
  * If the table structure is not correct, the post-fixer will automatically correct it in two steps:
  *
  *
@@ -35,12 +36,12 @@ import TableWalker from './../tablewalker';
  *
  *
  *		<table headingRows="1">
  *		<table headingRows="1">
  *			<tableRow>
  *			<tableRow>
- *				<tableCell rowspan="2">FOO</tableCell>
- *				<tableCell colspan="2">BAR</tableCell>
+ *				<tableCell rowspan="2"><paragraph>FOO</paragraph></tableCell>
+ *				<tableCell colspan="2"><paragraph>BAR</paragraph></tableCell>
  *			</tableRow>
  *			</tableRow>
  *			<tableRow>
  *			<tableRow>
- *				<tableCell>BAZ</tableCell>
- *				<tableCell>XYZ</tableCell>
+ *				<tableCell><paragraph>BAZ</paragraph></tableCell>
+ *				<tableCell><paragraph>XYZ</paragraph></tableCell>
  *			</tableRow>
  *			</tableRow>
  *		</table>
  *		</table>
  *
  *
@@ -55,8 +56,8 @@ import TableWalker from './../tablewalker';
  *			</thead>
  *			</thead>
  *			<tbody>
  *			<tbody>
  *				<tr>
  *				<tr>
- *					<td>BAZ<td>
- *					<td>XYZ<td>
+ *					<td>BAZ</td>
+ *					<td>XYZ</td>
  *				</tr>
  *				</tr>
  *			</tbody>
  *			</tbody>
  *		</table>
  *		</table>
@@ -90,8 +91,8 @@ import TableWalker from './../tablewalker';
  *			</thead>
  *			</thead>
  *			<tbody>
  *			<tbody>
  *				<tr>
  *				<tr>
- *					<td>BAZ<td>
- *					<td>XYZ<td>
+ *					<td>BAZ</td>
+ *					<td>XYZ</td>
  *				</tr>
  *				</tr>
  *			</tbody>
  *			</tbody>
  *		</table>
  *		</table>
@@ -113,8 +114,8 @@ import TableWalker from './../tablewalker';
  *					<td>12</td>
  *					<td>12</td>
  *				</tr>
  *				</tr>
  *				<tr>
  *				<tr>
- *					<td>21<td>
- *					<td>22<td>
+ *					<td>21</td>
+ *					<td>22</td>
  *				</tr>
  *				</tr>
  *			</tbody>
  *			</tbody>
  *		</table>
  *		</table>
@@ -156,8 +157,8 @@ import TableWalker from './../tablewalker';
  *					<td>(empty, inserted by A)</td>
  *					<td>(empty, inserted by A)</td>
  *				</tr>
  *				</tr>
  *				<tr>
  *				<tr>
- *					<td>21<td>
- *					<td>22<td>
+ *					<td>21</td>
+ *					<td>22</td>
  *					<td>(empty, inserted by A)</td>
  *					<td>(empty, inserted by A)</td>
  *				</tr>
  *				</tr>
  *				<tr>
  *				<tr>
@@ -197,32 +198,31 @@ import TableWalker from './../tablewalker';
  *				<tr>
  *				<tr>
  *					<td>11</td>
  *					<td>11</td>
  *					<td>12</td>
  *					<td>12</td>
- *					<td>(empty, inserted by a post-fixer after undo)<td>
+ *					<td>(empty, inserted by a post-fixer after undo)</td>
  *				</tr>
  *				</tr>
  *				<tr>
  *				<tr>
- *					<td>21<td>
- *					<td>22<td>
- *					<td>(empty, inserted by a post-fixer after undo)<td>
+ *					<td>21</td>
+ *					<td>22</td>
+ *					<td>(empty, inserted by a post-fixer after undo)</td>
  *				</tr>
  *				</tr>
  *				<tr>
  *				<tr>
- *					<td>(empty, inserted by B)<td>
- *					<td>(empty, inserted by B)<td>
- *					<td>(empty, inserted by a post-fixer)<td>
+ *					<td>(empty, inserted by B)</td>
+ *					<td>(empty, inserted by B)</td>
+ *					<td>(empty, inserted by a post-fixer)</td>
  *				</tr>
  *				</tr>
  *			</tbody>
  *			</tbody>
  *		</table>
  *		</table>
- *
  * @param {module:engine/model/model~Model} model
  * @param {module:engine/model/model~Model} model
  */
  */
-export default function injectTablePostFixer( model ) {
-	model.document.registerPostFixer( writer => tablePostFixer( writer, model ) );
+export default function injectTableLayoutPostFixer( model ) {
+	model.document.registerPostFixer( writer => tableLayoutPostFixer( writer, model ) );
 }
 }
 
 
-// The table post-fixer.
+// The table layout post-fixer.
 //
 //
 // @param {module:engine/model/writer~Writer} writer
 // @param {module:engine/model/writer~Writer} writer
 // @param {module:engine/model/model~Model} model
 // @param {module:engine/model/model~Model} model
-function tablePostFixer( writer, model ) {
+function tableLayoutPostFixer( writer, model ) {
 	const changes = model.document.differ.getChanges();
 	const changes = model.document.differ.getChanges();
 
 
 	let wasFixed = false;
 	let wasFixed = false;
@@ -233,7 +233,6 @@ function tablePostFixer( writer, model ) {
 	for ( const entry of changes ) {
 	for ( const entry of changes ) {
 		let table;
 		let table;
 
 
-		// Fix table on table insert.
 		if ( entry.name == 'table' && entry.type == 'insert' ) {
 		if ( entry.name == 'table' && entry.type == 'insert' ) {
 			table = entry.position.nodeAfter;
 			table = entry.position.nodeAfter;
 		}
 		}

+ 75 - 68
packages/ckeditor5-table/src/converters/tablecell-post-fixer.js

@@ -71,7 +71,7 @@
  * @param {module:engine/controller/editingcontroller~EditingController} editing
  * @param {module:engine/controller/editingcontroller~EditingController} editing
  */
  */
 export default function injectTableCellPostFixer( model, editing ) {
 export default function injectTableCellPostFixer( model, editing ) {
-	editing.view.document.registerPostFixer( writer => tableCellPostFixer( writer, model, editing.mapper ) );
+	editing.view.document.registerPostFixer( writer => tableCellPostFixer( writer, model, editing.mapper, editing.view ) );
 }
 }
 
 
 // The table cell post-fixer.
 // The table cell post-fixer.
@@ -79,94 +79,101 @@ export default function injectTableCellPostFixer( model, editing ) {
 // @param {module:engine/view/writer~Writer} writer
 // @param {module:engine/view/writer~Writer} writer
 // @param {module:engine/model/model~Model} model
 // @param {module:engine/model/model~Model} model
 // @param {module:engine/conversion/mapper~Mapper} mapper
 // @param {module:engine/conversion/mapper~Mapper} mapper
-function tableCellPostFixer( writer, model, mapper ) {
-	const changes = model.document.differ.getChanges();
+function tableCellPostFixer( writer, model, mapper, view ) {
 	let wasFixed = false;
 	let wasFixed = false;
 
 
-	// While this is view post fixer only nodes that changed are worth investigating.
-	for ( const entry of changes ) {
-		// Attribute change - check if it is single paragraph inside table cell that has attributes changed.
-		if ( entry.type == 'attribute' && entry.range.start.parent.name == 'tableCell' ) {
-			const tableCell = entry.range.start.parent;
-
-			if ( tableCell.childCount === 1 ) {
-				const singleChild = tableCell.getChild( 0 );
-				const renameTo = Array.from( singleChild.getAttributes() ).length ? 'p' : 'span';
-
-				wasFixed = renameParagraphIfDifferent( singleChild, renameTo, writer, model, mapper ) || wasFixed;
-			}
-		} else {
-			// Check all nodes inside table cell on insert/remove operations (also other blocks).
-			const parent = entry.position && entry.position.parent;
-
-			if ( parent && parent.is( 'tableCell' ) ) {
-				const renameTo = parent.childCount > 1 ? 'p' : 'span';
-
-				for ( const child of parent.getChildren() ) {
-					wasFixed = renameParagraphIfDifferent( child, renameTo, writer, model, mapper ) || wasFixed;
-				}
-			}
-		}
+	const elementsToCheck = getElementsToCheck( view );
+
+	for ( const element of elementsToCheck ) {
+		wasFixed = ensureProperElementName( element, mapper, writer ) || wasFixed;
+	}
+
+	// Selection in the view might not be updated to renamed elements. Happens mostly when other feature inserts paragraph to the table cell
+	// (ie. when deleting table cell contents) and sets selection to it while table-post fixer changes view <p> to <span> element.
+	// The view.selection would have outdated nodes.
+	if ( wasFixed ) {
+		updateRangesInViewSelection( model.document.selection, mapper, writer );
 	}
 	}
 
 
 	return wasFixed;
 	return wasFixed;
 }
 }
 
 
-// Renames associated view element to a desired one. It will only rename if:
-// - model element is a paragraph
-// - view element is converted (mapped)
-// - view element has different name then requested.
+// Returns view elements changed in current view.change() block.
 //
 //
-// @param {module:engine/model/element~Element} modelElement
-// @param {String} desiredElementName
-// @param {module:engine/view/writer~Writer} writer
-// @param {module:engine/model/model~Model} model
-// @param {module:engine/conversion/mapper~Mapper} mapper
-function renameParagraphIfDifferent( modelElement, desiredElementName, writer, model, mapper ) {
-	// Only rename paragraph elements.
-	if ( !modelElement.is( 'paragraph' ) ) {
-		return false;
-	}
+// **Note**: Currently it uses private property of the view: _renderer to get changed view elements to check.
+//
+// @param {module:engine/view/view~View} view
+function getElementsToCheck( view ) {
+	const elementsWithChangedAttributes = Array.from( view._renderer.markedAttributes )
+		.filter( el => !!el.parent )
+		.filter( isSpanOrP )
+		.filter( el => isTdOrTh( el.parent ) );
+
+	const changedChildren = Array.from( view._renderer.markedChildren )
+		.filter( el => !!el.parent )
+		.filter( isTdOrTh )
+		.reduce( ( prev, element ) => {
+			const childrenToCheck = Array.from( element.getChildren() ).filter( isSpanOrP );
+
+			return [ ...prev, ...childrenToCheck ];
+		}, [] );
+
+	return [ ...elementsWithChangedAttributes, ...changedChildren ];
+}
 
 
-	const viewElement = mapper.toViewElement( modelElement );
+// This method checks if view element for model's <paragraph> was properly converter.
+// Paragraph should be either
+// - span: for single paragraph with no attributes.
+// - p   : in other cases.
+function ensureProperElementName( currentViewElement, mapper, writer ) {
+	const modelParagraph = mapper.toModelElement( currentViewElement );
+	const expectedViewElementName = getExpectedElementName( modelParagraph.parent, modelParagraph );
 
 
-	// Only rename converted elements which aren't desired ones.
-	if ( !viewElement || viewElement.name === desiredElementName ) {
-		return false;
-	}
+	if ( currentViewElement.name !== expectedViewElementName ) {
+		// Unbind current view element as it should be cleared from mapper.
+		mapper.unbindViewElement( currentViewElement );
 
 
-	// After renaming element in the view by a post-fixer the selection would have references to the previous element.
-	const selection = model.document.selection;
-	const shouldFixSelection = checkSelectionForRenamedElement( selection, modelElement );
+		const renamedViewElement = writer.rename( expectedViewElementName, currentViewElement );
 
 
-	// Unbind current view element as it should be cleared from mapper.
-	mapper.unbindViewElement( viewElement );
-	const renamedViewElement = writer.rename( desiredElementName, viewElement );
-	// Bind paragraph inside table cell to the renamed view element.
-	mapper.bindElements( modelElement, renamedViewElement );
+		// Bind paragraph inside table cell to the renamed view element.
+		mapper.bindElements( modelParagraph, renamedViewElement );
 
 
-	if ( shouldFixSelection ) {
-		// Re-create view selection based on model selection.
-		updateRangesInViewSelection( selection, mapper, writer );
+		return true;
 	}
 	}
 
 
-	return true;
+	return false;
 }
 }
 
 
-// Checks if model selection contains renamed element.
+// Expected view element name depends on model elements:
+// - <paragraph> with any attribute set should be rendered as <p>
+// - all <paragraphs> in <tableCell> that has more then one children should be rendered as <p>
+// - an only <paragraph> child with no attributes should be rendered as <span>
 //
 //
-// @param {module:engine/model/selection~Selection} selection
-// @param {module:engine/model/element~Element} modelElement
-// @returns {boolean}
-function checkSelectionForRenamedElement( selection, modelElement ) {
-	return !![ ...selection.getSelectedBlocks() ].find( block => block === modelElement );
+// @param {module:engine/model/element~Element} tableCell
+// @param {module:engine/model/element~Element} paragraph
+// @returns {String}
+function getExpectedElementName( tableCell, paragraph ) {
+	const isOnlyChild = tableCell.childCount > 1;
+	const hasAttributes = !![ ...paragraph.getAttributes() ].length;
+
+	return ( isOnlyChild || hasAttributes ) ? 'p' : 'span';
 }
 }
 
 
-// Re-create view selection from model selection.
+// Method to filter out <span> and <p> elements.
 //
 //
-// @param {module:engine/model/selection~Selection} selection
-// @param {module:engine/view/writer~Writer} writer
-// @param {module:engine/conversion/mapper~Mapper} mapper
+// @param {module:engine/view/element~Element} element
+function isSpanOrP( element ) {
+	return element.is( 'p' ) || element.is( 'span' );
+}
+
+// Method to filter out <td> and <th> elements.
+//
+// @param {module:engine/view/element~Element} element
+function isTdOrTh( element ) {
+	return element.is( 'td' ) || element.is( 'th' );
+}
+
+// Resets view selections based on model selection.
 function updateRangesInViewSelection( selection, mapper, writer ) {
 function updateRangesInViewSelection( selection, mapper, writer ) {
 	const fixedRanges = Array.from( selection.getRanges() )
 	const fixedRanges = Array.from( selection.getRanges() )
 		.map( range => mapper.toViewRange( range ) );
 		.map( range => mapper.toViewRange( range ) );

+ 4 - 2
packages/ckeditor5-table/src/tableediting.js

@@ -33,7 +33,8 @@ import SetHeaderColumnCommand from './commands/setheadercolumncommand';
 import { findAncestor } from './commands/utils';
 import { findAncestor } from './commands/utils';
 import TableUtils from '../src/tableutils';
 import TableUtils from '../src/tableutils';
 
 
-import injectTablePostFixer from './converters/table-post-fixer';
+import injectTableLayoutPostFixer from './converters/table-layout-post-fixer';
+import injectTableCellContentsPostFixer from './converters/table-cell-content-post-fixer';
 import injectTableCellPostFixer from './converters/tablecell-post-fixer';
 import injectTableCellPostFixer from './converters/tablecell-post-fixer';
 
 
 import '../theme/tableediting.css';
 import '../theme/tableediting.css';
@@ -145,7 +146,8 @@ export default class TableEditing extends Plugin {
 		editor.commands.add( 'setTableColumnHeader', new SetHeaderColumnCommand( editor ) );
 		editor.commands.add( 'setTableColumnHeader', new SetHeaderColumnCommand( editor ) );
 		editor.commands.add( 'setTableRowHeader', new SetHeaderRowCommand( editor ) );
 		editor.commands.add( 'setTableRowHeader', new SetHeaderRowCommand( editor ) );
 
 
-		injectTablePostFixer( model );
+		injectTableLayoutPostFixer( model );
+		injectTableCellContentsPostFixer( model );
 
 
 		// Handle tab key navigation.
 		// Handle tab key navigation.
 		this.editor.keystrokes.set( 'Tab', ( ...args ) => this._handleTabOnSelectedTable( ...args ), { priority: 'low' } );
 		this.editor.keystrokes.set( 'Tab', ( ...args ) => this._handleTabOnSelectedTable( ...args ), { priority: 'low' } );

+ 1 - 1
packages/ckeditor5-table/src/tabletoolbar.js

@@ -79,7 +79,7 @@ export default class TableToolbar extends Plugin {
 /**
 /**
  * Items to be placed in the table content toolbar.
  * Items to be placed in the table content toolbar.
  *
  *
- * **Note:** This is a deprecated configuration option! Use {@link module:table/table~TableConfig#contentToolbar} instead.
+ * **Note:** This configuration option is deprecated! Use {@link module:table/table~TableConfig#contentToolbar} instead.
  *
  *
  * Read more about configuring toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.
  * Read more about configuring toolbar in {@link module:core/editor/editorconfig~EditorConfig#toolbar}.
  *
  *

+ 3 - 1
packages/ckeditor5-table/tests/_utils/utils.js

@@ -15,6 +15,8 @@ import {
 } from '../../src/converters/downcast';
 } from '../../src/converters/downcast';
 import upcastTable, { upcastTableCell } from '../../src/converters/upcasttable';
 import upcastTable, { upcastTableCell } from '../../src/converters/upcasttable';
 
 
+const WIDGET_TABLE_CELL_CLASS = 'ck-editor__editable ck-editor__nested-editable';
+
 /**
 /**
  * Returns a model representation of a table shorthand notation:
  * Returns a model representation of a table shorthand notation:
  *
  *
@@ -264,7 +266,7 @@ function makeRows( tableData, options ) {
 				const attributes = isObject ? tableCellData : {};
 				const attributes = isObject ? tableCellData : {};
 
 
 				if ( asWidget ) {
 				if ( asWidget ) {
-					attributes.class = 'ck-editor__editable ck-editor__nested-editable';
+					attributes.class = WIDGET_TABLE_CELL_CLASS + ( attributes.class ? ` ${ attributes.class }` : '' );
 					attributes.contenteditable = 'true';
 					attributes.contenteditable = 'true';
 				}
 				}
 
 

+ 126 - 0
packages/ckeditor5-table/tests/converters/table-cell-content-post-fixer.js

@@ -0,0 +1,126 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+import Range from '@ckeditor/ckeditor5-engine/src/model/range';
+import Position from '@ckeditor/ckeditor5-engine/src/model/position';
+import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
+import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
+import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
+
+import TableEditing from '../../src/tableediting';
+import { formatTable } from './../_utils/utils';
+import UndoEditing from '@ckeditor/ckeditor5-undo/src/undoediting';
+
+describe( 'Table cell content post-fixer', () => {
+	let editor, model, root;
+
+	beforeEach( () => {
+		return VirtualTestEditor
+			.create( {
+				plugins: [ TableEditing, Paragraph, UndoEditing ]
+			} )
+			.then( newEditor => {
+				editor = newEditor;
+				model = editor.model;
+				root = model.document.getRoot();
+			} );
+	} );
+
+	afterEach( () => {
+		editor.destroy();
+	} );
+
+	it( 'should add a paragraph to an empty table cell (on table insert)', () => {
+		setModelData( model,
+			'<table>' +
+				'<tableRow>' +
+					'<tableCell></tableCell>' +
+				'</tableRow>' +
+			'</table>'
+		);
+
+		expect( formatTable( getModelData( model, { withoutSelection: true } ) ) ).to.equal( formatTable(
+			'<table>' +
+				'<tableRow>' +
+					'<tableCell><paragraph></paragraph></tableCell>' +
+				'</tableRow>' +
+			'</table>'
+		) );
+	} );
+
+	it( 'should add a paragraph to an empty table cell (on row insert)', () => {
+		setModelData( model,
+			'<table>' +
+				'<tableRow>' +
+					'<tableCell><paragraph></paragraph></tableCell>' +
+				'</tableRow>' +
+			'</table>'
+		);
+
+		// Insert table row with one table cell
+		model.change( writer => {
+			writer.insertElement( 'tableRow', Position.createAfter( root.getNodeByPath( [ 0, 0 ] ) ) );
+			writer.insertElement( 'tableCell', Position.createAt( root.getNodeByPath( [ 0, 1 ] ) ) );
+		} );
+
+		expect( formatTable( getModelData( model, { withoutSelection: true } ) ) ).to.equal( formatTable(
+			'<table>' +
+				'<tableRow>' +
+					'<tableCell><paragraph></paragraph></tableCell>' +
+				'</tableRow>' +
+				'<tableRow>' +
+					'<tableCell><paragraph></paragraph></tableCell>' +
+				'</tableRow>' +
+			'</table>'
+		) );
+	} );
+
+	it( 'should add a paragraph to an empty table cell (on table cell insert)', () => {
+		setModelData( model,
+			'<table>' +
+				'<tableRow>' +
+					'<tableCell><paragraph></paragraph></tableCell>' +
+				'</tableRow>' +
+			'</table>'
+		);
+
+		// Insert table row with one table cell
+		model.change( writer => {
+			writer.insertElement( 'tableCell', Position.createAt( root.getNodeByPath( [ 0, 0 ], 'end' ) ) );
+		} );
+
+		expect( formatTable( getModelData( model, { withoutSelection: true } ) ) ).to.equal( formatTable(
+			'<table>' +
+				'<tableRow>' +
+					'<tableCell><paragraph></paragraph></tableCell>' +
+					'<tableCell><paragraph></paragraph></tableCell>' +
+				'</tableRow>' +
+			'</table>'
+		) );
+	} );
+
+	it( 'should add a paragraph to an empty table cell (after remove)', () => {
+		setModelData( model,
+			'<table>' +
+				'<tableRow>' +
+					'<tableCell><paragraph>foo</paragraph></tableCell>' +
+				'</tableRow>' +
+			'</table>'
+		);
+
+		// Remove paragraph from table cell.
+		model.change( writer => {
+			writer.remove( Range.createIn( root.getNodeByPath( [ 0, 0, 0 ] ) ) );
+		} );
+
+		expect( formatTable( getModelData( model, { withoutSelection: true } ) ) ).to.equal( formatTable(
+			'<table>' +
+				'<tableRow>' +
+					'<tableCell><paragraph></paragraph></tableCell>' +
+				'</tableRow>' +
+			'</table>'
+		) );
+	} );
+} );

+ 1 - 1
packages/ckeditor5-table/tests/converters/table-post-fixer.js → packages/ckeditor5-table/tests/converters/table-layout-post-fixer.js

@@ -12,7 +12,7 @@ import TableEditing from '../../src/tableediting';
 import { formatTable, formattedModelTable, modelTable } from './../_utils/utils';
 import { formatTable, formattedModelTable, modelTable } from './../_utils/utils';
 import UndoEditing from '@ckeditor/ckeditor5-undo/src/undoediting';
 import UndoEditing from '@ckeditor/ckeditor5-undo/src/undoediting';
 
 
-describe( 'Table post-fixer', () => {
+describe( 'Table layout post-fixer', () => {
 	let editor, model, root;
 	let editor, model, root;
 
 
 	beforeEach( () => {
 	beforeEach( () => {

+ 97 - 27
packages/ckeditor5-table/tests/converters/tablecell-post-fixer.js

@@ -3,32 +3,38 @@
  * For licensing, see LICENSE.md.
  * For licensing, see LICENSE.md.
  */
  */
 
 
-import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor';
+/* globals document */
+
 import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
 import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
-import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 
 
-import { defaultConversion, defaultSchema, formatTable, formattedViewTable, modelTable } from '../_utils/utils';
+import { defaultConversion, defaultSchema, formatTable, formattedViewTable, viewTable } from '../_utils/utils';
 import injectTableCellPostFixer from '../../src/converters/tablecell-post-fixer';
 import injectTableCellPostFixer from '../../src/converters/tablecell-post-fixer';
+import Range from '@ckeditor/ckeditor5-engine/src/model/range';
 
 
 import env from '@ckeditor/ckeditor5-utils/src/env';
 import env from '@ckeditor/ckeditor5-utils/src/env';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
 import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils';
+import Position from '@ckeditor/ckeditor5-engine/src/model/position';
+import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor';
 
 
 describe( 'TableCell post-fixer', () => {
 describe( 'TableCell post-fixer', () => {
-	let editor, model, doc, root, viewDocument;
+	let editor, model, doc, root, view;
 
 
 	testUtils.createSinonSandbox();
 	testUtils.createSinonSandbox();
 
 
 	beforeEach( () => {
 	beforeEach( () => {
+		const element = document.createElement( 'div' );
+		document.body.appendChild( element );
+
 		// Most tests assume non-edge environment but we do not set `contenteditable=false` on Edge so stub `env.isEdge`.
 		// Most tests assume non-edge environment but we do not set `contenteditable=false` on Edge so stub `env.isEdge`.
 		testUtils.sinon.stub( env, 'isEdge' ).get( () => false );
 		testUtils.sinon.stub( env, 'isEdge' ).get( () => false );
 
 
-		return VirtualTestEditor.create()
+		return ClassicTestEditor.create( element )
 			.then( newEditor => {
 			.then( newEditor => {
 				editor = newEditor;
 				editor = newEditor;
 				model = editor.model;
 				model = editor.model;
 				doc = model.document;
 				doc = model.document;
 				root = doc.getRoot( 'main' );
 				root = doc.getRoot( 'main' );
-				viewDocument = editor.editing.view;
+				view = editor.editing.view;
 
 
 				defaultSchema( model.schema );
 				defaultSchema( model.schema );
 				defaultConversion( editor.conversion, true );
 				defaultConversion( editor.conversion, true );
@@ -46,7 +52,7 @@ describe( 'TableCell post-fixer', () => {
 	} );
 	} );
 
 
 	it( 'should rename <span> to <p> when adding more <paragraph> elements to the same table cell', () => {
 	it( 'should rename <span> to <p> when adding more <paragraph> elements to the same table cell', () => {
-		setModelData( model, modelTable( [ [ '00[]' ] ] ) );
+		editor.setData( viewTable( [ [ '<p>00</p>' ] ] ) );
 
 
 		const table = root.getChild( 0 );
 		const table = root.getChild( 0 );
 
 
@@ -60,13 +66,13 @@ describe( 'TableCell post-fixer', () => {
 			writer.setSelection( nodeByPath.nextSibling, 0 );
 			writer.setSelection( nodeByPath.nextSibling, 0 );
 		} );
 		} );
 
 
-		expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+		expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 			[ '<p>00</p><p></p>' ]
 			[ '<p>00</p><p></p>' ]
 		], { asWidget: true } ) );
 		], { asWidget: true } ) );
 	} );
 	} );
 
 
 	it( 'should rename <span> to <p> on adding other block element to the same table cell', () => {
 	it( 'should rename <span> to <p> on adding other block element to the same table cell', () => {
-		setModelData( model, modelTable( [ [ '00[]' ] ] ) );
+		editor.setData( viewTable( [ [ '<p>00</p>' ] ] ) );
 
 
 		const table = root.getChild( 0 );
 		const table = root.getChild( 0 );
 
 
@@ -80,13 +86,13 @@ describe( 'TableCell post-fixer', () => {
 			writer.setSelection( nodeByPath.nextSibling, 0 );
 			writer.setSelection( nodeByPath.nextSibling, 0 );
 		} );
 		} );
 
 
-		expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+		expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 			[ '<p>00</p><div></div>' ]
 			[ '<p>00</p><div></div>' ]
 		], { asWidget: true } ) );
 		], { asWidget: true } ) );
 	} );
 	} );
 
 
 	it( 'should properly rename the same element on consecutive changes', () => {
 	it( 'should properly rename the same element on consecutive changes', () => {
-		setModelData( model, modelTable( [ [ '00[]' ] ] ) );
+		editor.setData( viewTable( [ [ '<p>00</p>' ] ] ) );
 
 
 		const table = root.getChild( 0 );
 		const table = root.getChild( 0 );
 
 
@@ -98,7 +104,7 @@ describe( 'TableCell post-fixer', () => {
 			writer.setSelection( nodeByPath.nextSibling, 0 );
 			writer.setSelection( nodeByPath.nextSibling, 0 );
 		} );
 		} );
 
 
-		expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+		expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 			[ '<p>00</p><p></p>' ]
 			[ '<p>00</p><p></p>' ]
 		], { asWidget: true } ) );
 		], { asWidget: true } ) );
 
 
@@ -106,13 +112,13 @@ describe( 'TableCell post-fixer', () => {
 			writer.remove( table.getNodeByPath( [ 0, 0, 1 ] ) );
 			writer.remove( table.getNodeByPath( [ 0, 0, 1 ] ) );
 		} );
 		} );
 
 
-		expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+		expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 			[ '00' ]
 			[ '00' ]
 		], { asWidget: true } ) );
 		], { asWidget: true } ) );
 	} );
 	} );
 
 
 	it( 'should rename <span> to <p> when setting attribute on <paragraph>', () => {
 	it( 'should rename <span> to <p> when setting attribute on <paragraph>', () => {
-		setModelData( model, modelTable( [ [ '<paragraph>00[]</paragraph>' ] ] ) );
+		editor.setData( '<table><tr><td><p>00</p></td></tr></table>' );
 
 
 		const table = root.getChild( 0 );
 		const table = root.getChild( 0 );
 
 
@@ -120,13 +126,13 @@ describe( 'TableCell post-fixer', () => {
 			writer.setAttribute( 'foo', 'bar', table.getNodeByPath( [ 0, 0, 0 ] ) );
 			writer.setAttribute( 'foo', 'bar', table.getNodeByPath( [ 0, 0, 0 ] ) );
 		} );
 		} );
 
 
-		expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+		expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 			[ '<p foo="bar">00</p>' ]
 			[ '<p foo="bar">00</p>' ]
 		], { asWidget: true } ) );
 		], { asWidget: true } ) );
 	} );
 	} );
 
 
 	it( 'should rename <p> to <span> when removing all but one paragraph inside table cell', () => {
 	it( 'should rename <p> to <span> when removing all but one paragraph inside table cell', () => {
-		setModelData( model, modelTable( [ [ '<paragraph>00[]</paragraph><paragraph>foo</paragraph>' ] ] ) );
+		editor.setData( viewTable( [ [ '<p>00</p><p>foo</p>' ] ] ) );
 
 
 		const table = root.getChild( 0 );
 		const table = root.getChild( 0 );
 
 
@@ -134,13 +140,13 @@ describe( 'TableCell post-fixer', () => {
 			writer.remove( table.getNodeByPath( [ 0, 0, 1 ] ) );
 			writer.remove( table.getNodeByPath( [ 0, 0, 1 ] ) );
 		} );
 		} );
 
 
-		expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+		expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 			[ '00' ]
 			[ '00' ]
 		], { asWidget: true } ) );
 		], { asWidget: true } ) );
 	} );
 	} );
 
 
 	it( 'should rename <p> to <span> when removing attribute from <paragraph>', () => {
 	it( 'should rename <p> to <span> when removing attribute from <paragraph>', () => {
-		setModelData( model, modelTable( [ [ '<paragraph foo="bar">00[]</paragraph>' ] ] ) );
+		editor.setData( '<table><tr><td><p foo="bar">00</p></td></tr></table>' );
 
 
 		const table = root.getChild( 0 );
 		const table = root.getChild( 0 );
 
 
@@ -148,13 +154,13 @@ describe( 'TableCell post-fixer', () => {
 			writer.removeAttribute( 'foo', table.getNodeByPath( [ 0, 0, 0 ] ) );
 			writer.removeAttribute( 'foo', table.getNodeByPath( [ 0, 0, 0 ] ) );
 		} );
 		} );
 
 
-		expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+		expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 			[ '<span>00</span>' ]
 			[ '<span>00</span>' ]
 		], { asWidget: true } ) );
 		], { asWidget: true } ) );
 	} );
 	} );
 
 
 	it( 'should keep <p> in the view when <paragraph> attribute value is changed', () => {
 	it( 'should keep <p> in the view when <paragraph> attribute value is changed', () => {
-		setModelData( model, modelTable( [ [ '<paragraph foo="bar">00[]</paragraph>' ] ] ) );
+		editor.setData( viewTable( [ [ '<p foo="bar">00</p>' ] ] ) );
 
 
 		const table = root.getChild( 0 );
 		const table = root.getChild( 0 );
 
 
@@ -162,13 +168,13 @@ describe( 'TableCell post-fixer', () => {
 			writer.setAttribute( 'foo', 'baz', table.getNodeByPath( [ 0, 0, 0 ] ) );
 			writer.setAttribute( 'foo', 'baz', table.getNodeByPath( [ 0, 0, 0 ] ) );
 		} );
 		} );
 
 
-		expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+		expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 			[ '<p foo="baz">00</p>' ]
 			[ '<p foo="baz">00</p>' ]
 		], { asWidget: true } ) );
 		], { asWidget: true } ) );
 	} );
 	} );
 
 
 	it( 'should keep <p> in the view when <paragraph> attribute value is changed (table cell with multiple blocks)', () => {
 	it( 'should keep <p> in the view when <paragraph> attribute value is changed (table cell with multiple blocks)', () => {
-		setModelData( model, modelTable( [ [ '<paragraph foo="bar">00[]</paragraph><paragraph>00</paragraph>' ] ] ) );
+		editor.setData( viewTable( [ [ '<p foo="bar">00</p><p>00</p>' ] ] ) );
 
 
 		const table = root.getChild( 0 );
 		const table = root.getChild( 0 );
 
 
@@ -176,13 +182,13 @@ describe( 'TableCell post-fixer', () => {
 			writer.setAttribute( 'foo', 'baz', table.getNodeByPath( [ 0, 0, 0 ] ) );
 			writer.setAttribute( 'foo', 'baz', table.getNodeByPath( [ 0, 0, 0 ] ) );
 		} );
 		} );
 
 
-		expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+		expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 			[ '<p foo="baz">00</p><p>00</p>' ]
 			[ '<p foo="baz">00</p><p>00</p>' ]
 		], { asWidget: true } ) );
 		], { asWidget: true } ) );
 	} );
 	} );
 
 
 	it( 'should do nothing on rename <paragraph> to other block', () => {
 	it( 'should do nothing on rename <paragraph> to other block', () => {
-		setModelData( model, modelTable( [ [ '00' ] ] ) );
+		editor.setData( viewTable( [ [ '<p>00</p>' ] ] ) );
 
 
 		const table = root.getChild( 0 );
 		const table = root.getChild( 0 );
 
 
@@ -190,13 +196,13 @@ describe( 'TableCell post-fixer', () => {
 			writer.rename( table.getNodeByPath( [ 0, 0, 0 ] ), 'block' );
 			writer.rename( table.getNodeByPath( [ 0, 0, 0 ] ), 'block' );
 		} );
 		} );
 
 
-		expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+		expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 			[ '<div>00</div>' ]
 			[ '<div>00</div>' ]
 		], { asWidget: true } ) );
 		], { asWidget: true } ) );
 	} );
 	} );
 
 
 	it( 'should do nothing when setting attribute on block item other then <paragraph>', () => {
 	it( 'should do nothing when setting attribute on block item other then <paragraph>', () => {
-		setModelData( model, modelTable( [ [ '<block>foo</block>' ] ] ) );
+		editor.setData( viewTable( [ [ '<div>foo</div>' ] ] ) );
 
 
 		const table = root.getChild( 0 );
 		const table = root.getChild( 0 );
 
 
@@ -204,8 +210,72 @@ describe( 'TableCell post-fixer', () => {
 			writer.setAttribute( 'foo', 'bar', table.getNodeByPath( [ 0, 0, 0 ] ) );
 			writer.setAttribute( 'foo', 'bar', table.getNodeByPath( [ 0, 0, 0 ] ) );
 		} );
 		} );
 
 
-		expect( formatTable( getViewData( viewDocument, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+		expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
 			[ '<div foo="bar">foo</div>' ]
 			[ '<div foo="bar">foo</div>' ]
 		], { asWidget: true } ) );
 		], { asWidget: true } ) );
 	} );
 	} );
+
+	it( 'should not crash when view.change() block was called in model.change()', () => {
+		editor.setData( viewTable( [ [ '<p>foobar</p>' ] ] ) );
+
+		const table = root.getChild( 0 );
+
+		expect( formatTable( getViewData( view, { withoutSelection: true } ) ) )
+			.to.equal( formattedViewTable( [ [ 'foobar' ] ], { asWidget: true } ) );
+
+		expect( () => {
+			model.change( writer => {
+				const tableCell = table.getNodeByPath( [ 0, 0 ] );
+
+				writer.insertElement( 'paragraph', null, Position.createAt( tableCell, 'end' ) );
+				writer.setSelection( Range.createIn( tableCell ) );
+
+				// Do some change in the view while inside model change.
+				editor.editing.view.change( writer => {
+					writer.addClass( 'foo', editor.editing.mapper.toViewElement( tableCell ) );
+				} );
+			} );
+		} ).to.not.throw();
+
+		expect( formatTable( getViewData( view ) ) ).to.equal( formattedViewTable( [
+			[ { class: 'foo', contents: '<p>{foobar</p><p>]</p>' } ]
+		], { asWidget: true } ) );
+	} );
+
+	it( 'should keep <p> in the view when <paragraph> attribute value is changed (table cell with multiple blocks)', () => {
+		editor.setData( viewTable( [ [ '<p>00</p><p>00</p>' ] ] ) );
+
+		const table = root.getChild( 0 );
+
+		model.change( writer => {
+			writer.remove( Range.createOn( table.getNodeByPath( [ 0, 0, 1 ] ) ) );
+		} );
+
+		expect( formatTable( getViewData( view, { withoutSelection: true } ) ) ).to.equal( formattedViewTable( [
+			[ '<span>00</span>' ]
+		], { asWidget: true } ) );
+	} );
+
+	it( 'should update view selection after deleting content', () => {
+		editor.setData( viewTable( [ [ '<p>foo</p><p>bar</p>' ] ] ) );
+
+		const tableCell = root.getNodeByPath( [ 0, 0, 0 ] );
+
+		// Replace table cell contents with paragraph - as model.deleteContent() does.
+		model.change( writer => {
+			writer.remove( Range.createIn( tableCell ) );
+
+			const paragraph = writer.createElement( 'paragraph' );
+
+			writer.insert( paragraph, Position.createAt( tableCell ) );
+
+			// Set selection to newly created paragraph.
+			writer.setSelection( paragraph, 0 );
+		} );
+
+		const viewRange = view.document.selection.getFirstRange();
+
+		// Trying to map view selection to DOM range shouldn't throw after post-fixer will fix inserted <p> to <span>.
+		expect( () => view.domConverter.viewRangeToDom( viewRange ) ).to.not.throw();
+	} );
 } );
 } );