Browse Source

Merge branch 'master' into i/7799

Kamil Piechaczek 5 years ago
parent
commit
0c1f0871f6
100 changed files with 755 additions and 813 deletions
  1. 33 0
      .github/workflows/ckeditor5-integrations.yml
  2. 21 21
      CHANGELOG.md
  3. 13 1
      docs/builds/guides/migrate.md
  4. 1 1
      package.json
  5. 2 2
      packages/ckeditor-cloud-services-core/src/token/token.js
  6. 5 5
      packages/ckeditor-cloud-services-core/src/uploadgateway/fileuploader.js
  7. 2 2
      packages/ckeditor-cloud-services-core/src/uploadgateway/uploadgateway.js
  8. 2 2
      packages/ckeditor5-autoformat/tests/autoformat.js
  9. 6 1
      packages/ckeditor5-ckfinder/src/ckfindercommand.js
  10. 1 1
      packages/ckeditor5-ckfinder/tests/ckfindercommand.js
  11. 5 3
      packages/ckeditor5-clipboard/src/utils/plaintexttohtml.js
  12. 3 0
      packages/ckeditor5-clipboard/src/utils/viewtoplaintext.js
  13. 1 1
      packages/ckeditor5-clipboard/tests/clipboard.js
  14. 13 5
      packages/ckeditor5-clipboard/tests/utils/plaintexttohtml.js
  15. 16 0
      packages/ckeditor5-clipboard/tests/utils/viewtoplaintext.js
  16. 3 3
      packages/ckeditor5-code-block/src/codeblockediting.js
  17. 1 1
      packages/ckeditor5-core/src/commandcollection.js
  18. 4 6
      packages/ckeditor5-core/src/context.js
  19. 1 1
      packages/ckeditor5-core/src/editor/utils/attachtoform.js
  20. 1 1
      packages/ckeditor5-core/src/editor/utils/elementapimixin.js
  21. 1 2
      packages/ckeditor5-core/src/editor/utils/securesourceelement.js
  22. 1 1
      packages/ckeditor5-core/src/pendingactions.js
  23. 3 4
      packages/ckeditor5-core/src/plugincollection.js
  24. 1 1
      packages/ckeditor5-core/tests/_utils-tests/classictesteditor.js
  25. 2 5
      packages/ckeditor5-core/tests/_utils/classictesteditor.js
  26. 3 3
      packages/ckeditor5-core/tests/commandcollection.js
  27. 3 3
      packages/ckeditor5-core/tests/context.js
  28. 3 2
      packages/ckeditor5-core/tests/editor/editor.js
  29. 9 9
      packages/ckeditor5-core/tests/plugincollection.js
  30. 4 9
      packages/ckeditor5-editor-balloon/src/ballooneditor.js
  31. 3 12
      packages/ckeditor5-editor-balloon/tests/ballooneditor.js
  32. 2 5
      packages/ckeditor5-editor-classic/src/classiceditor.js
  33. 4 7
      packages/ckeditor5-editor-decoupled/src/decouplededitor.js
  34. 3 10
      packages/ckeditor5-editor-decoupled/tests/decouplededitor.js
  35. 4 7
      packages/ckeditor5-editor-inline/src/inlineeditor.js
  36. 3 12
      packages/ckeditor5-editor-inline/tests/inlineeditor.js
  37. 22 13
      packages/ckeditor5-engine/docs/_snippets/framework/extending-content-custom-element-converter.js
  38. 3 1
      packages/ckeditor5-engine/docs/framework/guides/deep-dive/conversion-extending-output.md
  39. 1 0
      packages/ckeditor5-engine/docs/framework/guides/deep-dive/conversion-introduction.md
  40. 2 0
      packages/ckeditor5-engine/docs/framework/guides/deep-dive/conversion-preserving-custom-content.md
  41. 49 44
      packages/ckeditor5-engine/docs/framework/guides/deep-dive/custom-element-conversion.md
  42. 8 8
      packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md
  43. 5 5
      packages/ckeditor5-engine/src/controller/datacontroller.js
  44. 3 4
      packages/ckeditor5-engine/src/conversion/conversion.js
  45. 6 0
      packages/ckeditor5-engine/src/conversion/downcastdispatcher.js
  46. 4 2
      packages/ckeditor5-engine/src/conversion/downcasthelpers.js
  47. 112 109
      packages/ckeditor5-engine/src/conversion/upcastdispatcher.js
  48. 1 1
      packages/ckeditor5-engine/src/conversion/viewconsumable.js
  49. 5 13
      packages/ckeditor5-engine/src/model/document.js
  50. 2 2
      packages/ckeditor5-engine/src/model/documentselection.js
  51. 2 5
      packages/ckeditor5-engine/src/model/liveposition.js
  52. 12 7
      packages/ckeditor5-engine/src/model/markercollection.js
  53. 8 2
      packages/ckeditor5-engine/src/model/node.js
  54. 5 8
      packages/ckeditor5-engine/src/model/nodelist.js
  55. 3 4
      packages/ckeditor5-engine/src/model/operation/attributeoperation.js
  56. 1 1
      packages/ckeditor5-engine/src/model/operation/detachoperation.js
  57. 1 1
      packages/ckeditor5-engine/src/model/operation/insertoperation.js
  58. 3 3
      packages/ckeditor5-engine/src/model/operation/mergeoperation.js
  59. 3 3
      packages/ckeditor5-engine/src/model/operation/moveoperation.js
  60. 2 2
      packages/ckeditor5-engine/src/model/operation/renameoperation.js
  61. 5 10
      packages/ckeditor5-engine/src/model/operation/rootattributeoperation.js
  62. 4 4
      packages/ckeditor5-engine/src/model/operation/splitoperation.js
  63. 2 4
      packages/ckeditor5-engine/src/model/operation/utils.js
  64. 25 29
      packages/ckeditor5-engine/src/model/position.js
  65. 1 1
      packages/ckeditor5-engine/src/model/range.js
  66. 5 5
      packages/ckeditor5-engine/src/model/schema.js
  67. 8 19
      packages/ckeditor5-engine/src/model/selection.js
  68. 2 2
      packages/ckeditor5-engine/src/model/textproxy.js
  69. 7 6
      packages/ckeditor5-engine/src/model/treewalker.js
  70. 5 7
      packages/ckeditor5-engine/src/model/utils/insertcontent.js
  71. 31 37
      packages/ckeditor5-engine/src/model/writer.js
  72. 1 2
      packages/ckeditor5-engine/src/view/attributeelement.js
  73. 38 47
      packages/ckeditor5-engine/src/view/downcastwriter.js
  74. 1 1
      packages/ckeditor5-engine/src/view/emptyelement.js
  75. 1 1
      packages/ckeditor5-engine/src/view/node.js
  76. 4 8
      packages/ckeditor5-engine/src/view/position.js
  77. 1 1
      packages/ckeditor5-engine/src/view/rawelement.js
  78. 3 3
      packages/ckeditor5-engine/src/view/renderer.js
  79. 8 16
      packages/ckeditor5-engine/src/view/selection.js
  80. 2 2
      packages/ckeditor5-engine/src/view/textproxy.js
  81. 7 6
      packages/ckeditor5-engine/src/view/treewalker.js
  82. 1 1
      packages/ckeditor5-engine/src/view/uielement.js
  83. 1 3
      packages/ckeditor5-engine/src/view/view.js
  84. 6 6
      packages/ckeditor5-engine/tests/controller/datacontroller.js
  85. 1 1
      packages/ckeditor5-engine/tests/dev-utils/operationreplayer.js
  86. 2 2
      packages/ckeditor5-engine/tests/model/document.js
  87. 2 2
      packages/ckeditor5-engine/tests/model/markercollection.js
  88. 2 0
      packages/ckeditor5-engine/tests/model/model.js
  89. 1 1
      packages/ckeditor5-engine/tests/model/nodelist.js
  90. 1 1
      packages/ckeditor5-engine/tests/model/operation/operation.js
  91. 0 39
      packages/ckeditor5-engine/tests/model/operation/transform.js
  92. 12 12
      packages/ckeditor5-engine/tests/model/position.js
  93. 32 34
      packages/ckeditor5-engine/tests/model/schema.js
  94. 10 20
      packages/ckeditor5-engine/tests/model/selection.js
  95. 8 8
      packages/ckeditor5-engine/tests/model/writer.js
  96. 2 2
      packages/ckeditor5-engine/tests/tickets/ckeditor5-692.js
  97. 5 21
      packages/ckeditor5-engine/tests/view/documentselection.js
  98. 58 58
      packages/ckeditor5-engine/tests/view/domconverter/dom-to-view.js
  99. 3 3
      packages/ckeditor5-engine/tests/view/emptyelement.js
  100. 1 1
      packages/ckeditor5-engine/tests/view/node.js

+ 33 - 0
.github/workflows/ckeditor5-integrations.yml

@@ -0,0 +1,33 @@
+# This script triggers Travis that verifies whether projects that depend on CKEditor 5 build correctly.
+#
+# In order to integrate the action in a new repository, you need add a few secrets in the new repository.
+#   - INTEGRATION_CI_ORGANIZATION - a name of the organization that keeps the repository where the build should be triggered
+#   - INTEGRATION_CI_REPOSITORY - a name of the repository where the build should be triggered
+#   - INTEGRATION_CI_TRAVIS_TOKEN - an authorization token generated by Travis CLI: `travis --pro token`
+name: CKEditor 5 Integrations
+
+on:
+  push:
+    branches: [ master ]
+
+jobs:
+  build:
+    runs-on: ubuntu-latest
+    steps:
+      - name: Trigger CI
+        env:
+          WORKFLOW_TRIGGER_REPOSITORY: ${{ github.repository }}
+          WORKFLOW_TRIGGER_COMMIT: ${{ github.sha }}
+          WORKFLOW_ORGANIZATION: ${{ secrets.INTEGRATION_CI_ORGANIZATION }}
+          WORKFLOW_REPOSITORY: ${{ secrets.INTEGRATION_CI_REPOSITORY }}
+          WORKFLOW_TRAVIS_TOKEN: ${{ secrets.INTEGRATION_CI_TRAVIS_TOKEN }}
+        run: |
+          export BUILD_MESSAGE="Repository: $WORKFLOW_TRIGGER_REPOSITORY\n\nCommit: https://github.com/$WORKFLOW_TRIGGER_REPOSITORY/commit/$WORKFLOW_TRIGGER_COMMIT."
+          export REQUEST_BODY="{\"request\": { \"branch\": \"master\", \"message\": \"$BUILD_MESSAGE\" } }"
+          curl -s -X POST \
+            -H "Content-Type: application/json" \
+            -H "Accept: application/json" \
+            -H "Travis-API-Version: 3" \
+            -H "Authorization: token $WORKFLOW_TRAVIS_TOKEN" \
+            -d "$REQUEST_BODY" \
+            "https://api.travis-ci.com/repo/$WORKFLOW_ORGANIZATION%2F$WORKFLOW_REPOSITORY/requests"

+ 21 - 21
CHANGELOG.md

@@ -9,24 +9,24 @@ We are happy to announce the release of CKEditor 5 v22.0.0.
 
 This release brings a few new features:
 
-* [List styles plugin](https://github.com/ckeditor/ckeditor5/issues/7801).
-* [Makrdown plugin](https://github.com/ckeditor/ckeditor5/issues/6007).
+* The [list style plugin](https://github.com/ckeditor/ckeditor5/issues/7801).
+* The [Markdown plugin](https://github.com/ckeditor/ckeditor5/issues/6007).
 * [Inserting image with URL](https://github.com/ckeditor/ckeditor5/issues/7794).
-* [New event-based conversion api](https://github.com/ckeditor/ckeditor5/issues/7336).
+* [A new event-based conversion API](https://github.com/ckeditor/ckeditor5/issues/7336).
 
 Please note that there are some **major breaking changes**. Be sure to review them before upgrading.
 
-<!-- TODO: Add a link to the blog post. -->
+Read more in the blog post: https://ckeditor.com/blog/ckeditor-5-v22.0.0-with-inserting-images-via-url-list-styles-and-markdown-plugin/
 
 ### Collaboration features
 
-The CKEditor 5 Collaboration features changelog can be found here: https://ckeditor.com/collaboration/changelog.
+The CKEditor 5 Collaboration Features changelog can be found here: https://ckeditor.com/collaboration/changelog.
 
 ### MAJOR BREAKING CHANGES [ℹ️](https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/versioning-policy.html#major-and-minor-breaking-changes)
 
-* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: The `config.view` callback of `DowncastHelpers` takes a `DowncastConversionApi` instance instead of a `DowncastWriter`. An example migration snippet can be found in a [GitHub comment](https://github.com/ckeditor/ckeditor5/issues/7334#issuecomment-670450941). See [#7334](https://github.com/ckeditor/ckeditor5/issues/7334).
-* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: The `config.model` callback of `UpcastHelpers` takes a `UpcastConversionApi` instance instead of a `ModelWriter`. An example migration snippet can be found in a [GitHub comment](https://github.com/ckeditor/ckeditor5/issues/7334#issuecomment-670450941). See [#7334](https://github.com/ckeditor/ckeditor5/issues/7334).
-* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: The `config.view` parameter for upcast element-to-element conversion helpers configurations is now mandatory. You can retain previous "catch-all" behavior for upcast converter using `config.view = /[\s\S]+/` value.
+* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: The `view` and `model` callbacks of all one-way converter helpers (such as `editor.conversion.for( 'upcast' ).elementToElement()`, `editor.conversion.for( 'downcast' ).attributeToElement()`) now take the `conversionApi` as their second parameter. Previously, the second parameter was the downcast or upcast writer instance. Now, the writer needs to be retrieved from `conversionApi.writer`.<br><br>
+An example migration snippet can be found in a [GitHub comment](https://github.com/ckeditor/ckeditor5/issues/7334#issuecomment-670450941).
+* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: The `config.view` parameter for upcast element-to-element conversion helper configurations is now mandatory. You can retain the previous "catch-all" behavior for the upcast converter using the `config.view = /[\s\S]+/` value.
 
 ### MINOR BREAKING CHANGES [ℹ️](https://ckeditor.com/docs/ckeditor5/latest/framework/guides/support/versioning-policy.html#major-and-minor-breaking-changes)
 
@@ -36,35 +36,35 @@ The CKEditor 5 Collaboration features changelog can be found here: https://ckedi
 ### Features
 
 * **[clipboard](https://www.npmjs.com/package/@ckeditor/ckeditor5-clipboard)**: Pasting a plain text will inherit selection attributes. Closes [#1006](https://github.com/ckeditor/ckeditor5/issues/1006). ([commit](https://github.com/ckeditor/ckeditor5/commit/2a163e389a6b22b1e5590fe6a2ed8204387d4350))
-* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: Options passed to `Editor#getData()` and `DataController#get()` are now available in downcast conversion under `conversionApi.options` object. Closes [#7628](https://github.com/ckeditor/ckeditor5/issues/7628). ([commit](https://github.com/ckeditor/ckeditor5/commit/0a5d07e3c9a5cef51ebfb4a5819b5118ad9ae115))
-* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: Added conversion API to upcast and downcast helpers. Closes [#7334](https://github.com/ckeditor/ckeditor5/issues/7334). ([commit](https://github.com/ckeditor/ckeditor5/commit/16c971198971b770d4e7aff4ea8eec7a88a6fcdb))
-* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: Introduced `SchemaItemDefinition#isSelectable` and `SchemaItemDefinition#isContent` properties. Closes [#6432](https://github.com/ckeditor/ckeditor5/issues/6432). ([commit](https://github.com/ckeditor/ckeditor5/commit/579c1c851ca33c78de60c98777684f8ee5ceb26e))
-* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: Introduced new upcast `ConversionApi` helper methods - `conversionApi.safeInsert()` and `conversionApi.updateConversionResult()`. New methods are intended to simplify writing event based element-to-element converters. Closes [#7336](https://github.com/ckeditor/ckeditor5/issues/7336). ([commit](https://github.com/ckeditor/ckeditor5/commit/8d84af1610089ea7916401ecf6f636c9d330b459))
+* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: Options passed to `Editor#getData()` and `DataController#get()` are now available in downcast conversion under the `conversionApi.options` object. Closes [#7628](https://github.com/ckeditor/ckeditor5/issues/7628). ([commit](https://github.com/ckeditor/ckeditor5/commit/0a5d07e3c9a5cef51ebfb4a5819b5118ad9ae115))
+* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: Added the conversion API to upcast and downcast helpers. Closes [#7334](https://github.com/ckeditor/ckeditor5/issues/7334). ([commit](https://github.com/ckeditor/ckeditor5/commit/16c971198971b770d4e7aff4ea8eec7a88a6fcdb))
+* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: Introduced the `SchemaItemDefinition#isSelectable` and `SchemaItemDefinition#isContent` properties. Closes [#6432](https://github.com/ckeditor/ckeditor5/issues/6432). ([commit](https://github.com/ckeditor/ckeditor5/commit/579c1c851ca33c78de60c98777684f8ee5ceb26e))
+* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: Introduced new upcast `ConversionApi` helper methods: `conversionApi.safeInsert()` and `conversionApi.updateConversionResult()`. The new methods are intended to simplify writing event-based element-to-element converters. Closes [#7336](https://github.com/ckeditor/ckeditor5/issues/7336). ([commit](https://github.com/ckeditor/ckeditor5/commit/8d84af1610089ea7916401ecf6f636c9d330b459))
 * **[image](https://www.npmjs.com/package/@ckeditor/ckeditor5-image)**: Introduced the insert image via URL feature. Closes [#7794](https://github.com/ckeditor/ckeditor5/issues/7794). ([commit](https://github.com/ckeditor/ckeditor5/commit/bb00c23f6234751666e859e6e5d7e909f194e375))
 * **[indent](https://www.npmjs.com/package/@ckeditor/ckeditor5-indent)**: Block indentation is now recognized as a formatting attribute. Closes [#2358](https://github.com/ckeditor/ckeditor5/issues/2358). ([commit](https://github.com/ckeditor/ckeditor5/commit/6b2cc25dd717eb22caf7189d8cf33511397179c0))
-* **[list](https://www.npmjs.com/package/@ckeditor/ckeditor5-list)**: Introduced the list styles feature that allows customizing the list marker. Closes [#7801](https://github.com/ckeditor/ckeditor5/issues/7801). ([commit](https://github.com/ckeditor/ckeditor5/commit/137dd2856aecaa8f9c023e6ca9d01592707137a0))
+* **[list](https://www.npmjs.com/package/@ckeditor/ckeditor5-list)**: Introduced the list style feature that allows customizing the list marker. Closes [#7801](https://github.com/ckeditor/ckeditor5/issues/7801). ([commit](https://github.com/ckeditor/ckeditor5/commit/137dd2856aecaa8f9c023e6ca9d01592707137a0))
 * **[markdown-gfm](https://www.npmjs.com/package/@ckeditor/ckeditor5-markdown-gfm)**: Introduced the `Markdown` plugin. Closes [#6007](https://github.com/ckeditor/ckeditor5/issues/6007). ([commit](https://github.com/ckeditor/ckeditor5/commit/7cd5fc198e1977ecefbf0e455f4b514b467e7775))
-* **[markdown-gfm](https://www.npmjs.com/package/@ckeditor/ckeditor5-markdown-gfm)**: The markdown data processor has been revamped and got the dependencies updated. Closes [#5988](https://github.com/ckeditor/ckeditor5/issues/5988). ([commit](https://github.com/ckeditor/ckeditor5/commit/3881349eae0c9a862e76487f8eb117d6ca3e38b0))
-* **[utils](https://www.npmjs.com/package/@ckeditor/ckeditor5-utils)**: Introduced the `Rect#getBoundingRect()` method that returns a `Rect` instance containing all the rectangles passed as argument. Closes [#7858](https://github.com/ckeditor/ckeditor5/issues/7858). ([commit](https://github.com/ckeditor/ckeditor5/commit/ccfaf5e54854cc8a62ebbc005e35676f77be37c4))
+* **[markdown-gfm](https://www.npmjs.com/package/@ckeditor/ckeditor5-markdown-gfm)**: The Markdown data processor was revamped and got the dependencies updated. Closes [#5988](https://github.com/ckeditor/ckeditor5/issues/5988). ([commit](https://github.com/ckeditor/ckeditor5/commit/3881349eae0c9a862e76487f8eb117d6ca3e38b0))
+* **[utils](https://www.npmjs.com/package/@ckeditor/ckeditor5-utils)**: Introduced the `Rect#getBoundingRect()` method that returns a `Rect` instance containing all the rectangles passed as an argument. Closes [#7858](https://github.com/ckeditor/ckeditor5/issues/7858). ([commit](https://github.com/ckeditor/ckeditor5/commit/ccfaf5e54854cc8a62ebbc005e35676f77be37c4))
 * **[utils](https://www.npmjs.com/package/@ckeditor/ckeditor5-utils)**: Introduced the `passive` option support in the `DomEmitterMixin#listenTo()` method. Closes [#7828](https://github.com/ckeditor/ckeditor5/issues/7828). ([commit](https://github.com/ckeditor/ckeditor5/commit/a7ef65c8246b9591a9a2081cfb19266de0c6194b))
-* **[widget](https://www.npmjs.com/package/@ckeditor/ckeditor5-widget)**: Keyboard vertical navigation in the text lines next to objects should move the caret to the position closest to the object. Closes [#7630](https://github.com/ckeditor/ckeditor5/issues/7630). ([commit](https://github.com/ckeditor/ckeditor5/commit/7984a14a411416634d64d405da2d6d18a314e947))
+* **[widget](https://www.npmjs.com/package/@ckeditor/ckeditor5-widget)**: Keyboard vertical navigation in text lines next to objects should move the caret to the position closest to the object. Closes [#7630](https://github.com/ckeditor/ckeditor5/issues/7630). ([commit](https://github.com/ckeditor/ckeditor5/commit/7984a14a411416634d64d405da2d6d18a314e947))
 
 ### Bug fixes
 
-* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: Upcast conversion will now try to wrap text or inline elements in a paragraph in a place where is not allowed but a paragraph is allowed. Closes [#7753](https://github.com/ckeditor/ckeditor5/issues/7753), [#6698](https://github.com/ckeditor/ckeditor5/issues/6698). ([commit](https://github.com/ckeditor/ckeditor5/commit/5e857fd0ec6f4dc9e86dec0bf9c5b87289eedf8b))
+* **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: Upcast conversion will now try to wrap text or inline elements in a paragraph in a place where they are not allowed but a paragraph is allowed. Closes [#7753](https://github.com/ckeditor/ckeditor5/issues/7753), [#6698](https://github.com/ckeditor/ckeditor5/issues/6698). ([commit](https://github.com/ckeditor/ckeditor5/commit/5e857fd0ec6f4dc9e86dec0bf9c5b87289eedf8b))
 * **[engine](https://www.npmjs.com/package/@ckeditor/ckeditor5-engine)**: The selection will no longer inherit attributes from an empty inline element. Closes [#7459](https://github.com/ckeditor/ckeditor5/issues/7459). ([commit](https://github.com/ckeditor/ckeditor5/commit/1ddb955cc667ad16b41521762f77b95382f467da))
-* **[link](https://www.npmjs.com/package/@ckeditor/ckeditor5-link)**: Fixed a case where the link balloon would point invalid place after browser scroll or resize. Closes [#7705](https://github.com/ckeditor/ckeditor5/issues/7705). ([commit](https://github.com/ckeditor/ckeditor5/commit/5158209e2a39884a3015e317f17f33a340e2502d))
+* **[link](https://www.npmjs.com/package/@ckeditor/ckeditor5-link)**: Fixed a case where the link balloon would point to an invalid place after the browser scroll or resize. Closes [#7705](https://github.com/ckeditor/ckeditor5/issues/7705). ([commit](https://github.com/ckeditor/ckeditor5/commit/5158209e2a39884a3015e317f17f33a340e2502d))
 * **[ui](https://www.npmjs.com/package/@ckeditor/ckeditor5-ui)**: Dropdown panels from the editor's main toolbar should always float above the contextual balloons from the editor's content. Closes [#7874](https://github.com/ckeditor/ckeditor5/issues/7874). ([commit](https://github.com/ckeditor/ckeditor5/commit/57d3f02958ad32b8c774dbdc38e1a1210e75af1f))
 * **[ui](https://www.npmjs.com/package/@ckeditor/ckeditor5-ui)**: Balloon toolbar should reposition and ungroup items correctly when the window resizes. Closes [#6444](https://github.com/ckeditor/ckeditor5/issues/6444). ([commit](https://github.com/ckeditor/ckeditor5/commit/32523780fa27146d4f74b538af4831d8b9683bd9))
-* **[utils](https://www.npmjs.com/package/@ckeditor/ckeditor5-utils)**: `Rect` utility returns wrong sizes in case of a sequenced range. Closes [#7838](https://github.com/ckeditor/ckeditor5/issues/7838). ([commit](https://github.com/ckeditor/ckeditor5/commit/ccfaf5e54854cc8a62ebbc005e35676f77be37c4))
+* **[utils](https://www.npmjs.com/package/@ckeditor/ckeditor5-utils)**: The `Rect` utility returns wrong sizes in case of a sequenced range. Closes [#7838](https://github.com/ckeditor/ckeditor5/issues/7838). ([commit](https://github.com/ckeditor/ckeditor5/commit/ccfaf5e54854cc8a62ebbc005e35676f77be37c4))
 
 ### Other changes
 
 * **[markdown-gfm](https://www.npmjs.com/package/@ckeditor/ckeditor5-markdown-gfm)**: Upgraded to Marked v1.1.1. Closes [#7850](https://github.com/ckeditor/ckeditor5/issues/7850). ([commit](https://github.com/ckeditor/ckeditor5/commit/d6c8731a33f3402b8bd71b987b762116efd3898a))
-* **[mention](https://www.npmjs.com/package/@ckeditor/ckeditor5-mention)**: The <kbd>space</kbd> key will not confirm a mention selection from the list. Closes [#6394](https://github.com/ckeditor/ckeditor5/issues/6394). ([commit](https://github.com/ckeditor/ckeditor5/commit/a8d41ecbbeb5d36694ba74d0391805cfaa5214e7))
+* **[mention](https://www.npmjs.com/package/@ckeditor/ckeditor5-mention)**: The <kbd>Space</kbd> key will not confirm a mention selection from the list. Closes [#6394](https://github.com/ckeditor/ckeditor5/issues/6394). ([commit](https://github.com/ckeditor/ckeditor5/commit/a8d41ecbbeb5d36694ba74d0391805cfaa5214e7))
 * **[remove-format](https://www.npmjs.com/package/@ckeditor/ckeditor5-remove-format)**: Block formatting should be removed if the selection is inside that block. ([commit](https://github.com/ckeditor/ckeditor5/commit/6b2cc25dd717eb22caf7189d8cf33511397179c0))
 * **[table](https://www.npmjs.com/package/@ckeditor/ckeditor5-table)**: The `tableCell` model element brought by the `TableEditing` plugin is no longer an object (`SchemaItemDefinition#isObject`) in the `Schema` but a selectable (`SchemaItemDefinition#isSelectable`) (see [#6432](https://github.com/ckeditor/ckeditor5/issues/6432)). ([commit](https://github.com/ckeditor/ckeditor5/commit/579c1c851ca33c78de60c98777684f8ee5ceb26e))
-* **[table](https://www.npmjs.com/package/@ckeditor/ckeditor5-table)**: Pressing <kbd>Shift</kbd>+<kbd>Tab</kbd> in the first table cell now selects entire table. Closes [#7535](https://github.com/ckeditor/ckeditor5/issues/7535). ([commit](https://github.com/ckeditor/ckeditor5/commit/3064c64733145b40290480f3299e168b74380d04))
+* **[table](https://www.npmjs.com/package/@ckeditor/ckeditor5-table)**: Pressing <kbd>Shift</kbd>+<kbd>Tab</kbd> in the first table cell now selects the entire table. Closes [#7535](https://github.com/ckeditor/ckeditor5/issues/7535). ([commit](https://github.com/ckeditor/ckeditor5/commit/3064c64733145b40290480f3299e168b74380d04))
 * **[ui](https://www.npmjs.com/package/@ckeditor/ckeditor5-ui)**: The `clickOutsideHandler()` function will take into consideration that the editor can be placed in a shadow root while detecting a click. Closes [#7743](https://github.com/ckeditor/ckeditor5/issues/7743). ([commit](https://github.com/ckeditor/ckeditor5/commit/2dc026409051828618c274ae62ce331fe05681fe))
 
   Thanks to [@ywsang](https://github.com/ywsang).

File diff suppressed because it is too large
+ 13 - 1
docs/builds/guides/migrate.md


+ 1 - 1
package.json

@@ -79,7 +79,7 @@
     "@ckeditor/ckeditor5-comments": "^22.0.0",
     "@ckeditor/ckeditor5-dev-docs": "^23.2.0",
     "@ckeditor/ckeditor5-dev-env": "^23.2.0",
-    "@ckeditor/ckeditor5-dev-tests": "^23.2.0",
+    "@ckeditor/ckeditor5-dev-tests": "^23.3.0",
     "@ckeditor/ckeditor5-dev-utils": "^23.2.0",
     "@ckeditor/ckeditor5-dev-webpack-plugin": "^23.2.0",
     "@ckeditor/ckeditor5-export-pdf": "^1.0.0",

+ 2 - 2
packages/ckeditor-cloud-services-core/src/token/token.js

@@ -41,7 +41,7 @@ class Token {
 			 * @error token-missing-token-url
 			 */
 			throw new CKEditorError(
-				'token-missing-token-url: A `tokenUrl` must be provided as the first constructor argument.',
+				'token-missing-token-url',
 				this
 			);
 		}
@@ -185,7 +185,7 @@ function defaultRefreshToken( tokenUrl ) {
 				 * @error token-cannot-download-new-token
 				 */
 				return reject(
-					new CKEditorError( 'token-cannot-download-new-token: Cannot download new token from the provided url.', null )
+					new CKEditorError( 'token-cannot-download-new-token', null )
 				);
 			}
 

+ 5 - 5
packages/ckeditor-cloud-services-core/src/uploadgateway/fileuploader.js

@@ -33,7 +33,7 @@ export default class FileUploader {
 			 *
 			 * @error fileuploader-missing-file
 			 */
-			throw new CKEditorError( 'fileuploader-missing-file: File must be provided as the first argument', null );
+			throw new CKEditorError( 'fileuploader-missing-file', null );
 		}
 
 		if ( !token ) {
@@ -42,7 +42,7 @@ export default class FileUploader {
 			 *
 			 * @error fileuploader-missing-token
 			 */
-			throw new CKEditorError( 'fileuploader-missing-token: Token must be provided as the second argument.', null );
+			throw new CKEditorError( 'fileuploader-missing-token', null );
 		}
 
 		if ( !apiAddress ) {
@@ -51,7 +51,7 @@ export default class FileUploader {
 			 *
 			 * @error fileuploader-missing-api-address
 			 */
-			throw new CKEditorError( 'fileuploader-missing-api-address: Api address must be provided as the third argument.', null );
+			throw new CKEditorError( 'fileuploader-missing-api-address', null );
 		}
 
 		/**
@@ -201,7 +201,7 @@ export default class FileUploader {
 						 * @error fileuploader-uploading-data-failed
 						 */
 						return reject( new CKEditorError(
-							'fileuploader-uploading-data-failed: Uploading file failed.',
+							'fileuploader-uploading-data-failed',
 							this,
 							{ message: xhrResponse.message }
 						) );
@@ -270,7 +270,7 @@ function _base64ToBlob( base64, sliceSize = 512 ) {
 		 *
 		 * @error fileuploader-decoding-image-data-error
 		 */
-		throw new CKEditorError( 'fileuploader-decoding-image-data-error: Problem with decoding Base64 image data.', null );
+		throw new CKEditorError( 'fileuploader-decoding-image-data-error', null );
 	}
 }
 

+ 2 - 2
packages/ckeditor-cloud-services-core/src/uploadgateway/uploadgateway.js

@@ -27,7 +27,7 @@ export default class UploadGateway {
 			 *
 			 * @error uploadgateway-missing-token
 			 */
-			throw new CKEditorError( 'uploadgateway-missing-token: Token must be provided.', null );
+			throw new CKEditorError( 'uploadgateway-missing-token', null );
 		}
 
 		if ( !apiAddress ) {
@@ -36,7 +36,7 @@ export default class UploadGateway {
 			 *
 			 * @error uploadgateway-missing-api-address
 			 */
-			throw new CKEditorError( 'uploadgateway-missing-api-address: Api address must be provided.', null );
+			throw new CKEditorError( 'uploadgateway-missing-api-address', null );
 		}
 
 		/**

+ 2 - 2
packages/ckeditor5-autoformat/tests/autoformat.js

@@ -486,7 +486,7 @@ describe( 'Autoformat', () => {
 		} );
 
 		describe( 'with code element', () => {
-			describe( 'should not format', () => {
+			describe( 'should not format (inside)', () => {
 				it( '* inside', () => {
 					setData( model, '<paragraph><$text code="true">fo*obar[]</$text></paragraph>' );
 
@@ -532,7 +532,7 @@ describe( 'Autoformat', () => {
 				} );
 			} );
 
-			describe( 'should not format', () => {
+			describe( 'should not format (across)', () => {
 				it( '* across', () => {
 					setData( model, '<paragraph><$text code="true">fo*o</$text>bar[]</paragraph>' );
 

+ 6 - 1
packages/ckeditor5-ckfinder/src/ckfindercommand.js

@@ -60,7 +60,12 @@ export default class CKFinderCommand extends Command {
 		const openerMethod = this.editor.config.get( 'ckfinder.openerMethod' ) || 'modal';
 
 		if ( openerMethod != 'popup' && openerMethod != 'modal' ) {
-			throw new CKEditorError( 'ckfinder-unknown-openerMethod: The openerMethod config option must by "popup" or "modal".', editor );
+			/**
+			 * The `ckfinder.openerMethod` must be one of: "popup" or "modal".
+			 *
+			 * @error ckfinder-unknown-openermethod
+			 */
+			throw new CKEditorError( 'ckfinder-unknown-openermethod', editor );
 		}
 
 		const options = this.editor.config.get( 'ckfinder.options' ) || {};

+ 1 - 1
packages/ckeditor5-ckfinder/tests/ckfindercommand.js

@@ -178,7 +178,7 @@ describe( 'CKFinderCommand', () => {
 
 			expectToThrowCKEditorError( () => {
 				command.execute();
-			}, /ckfinder-unknown-openerMethod/, editor );
+			}, 'ckfinder-unknown-openermethod', editor );
 		} );
 
 		it( 'should insert single chosen image', () => {

+ 5 - 3
packages/ckeditor5-clipboard/src/utils/plaintexttohtml.js

@@ -18,15 +18,17 @@ export default function plainTextToHtml( text ) {
 		// Encode <>.
 		.replace( /</g, '&lt;' )
 		.replace( />/g, '&gt;' )
-		// Creates paragraphs for every line breaks.
-		.replace( /\n/g, '</p><p>' )
+		// Creates a paragraph for each double line break.
+		.replace( /\r?\n\r?\n/g, '</p><p>' )
+		// Creates a line break for each single line break.
+		.replace( /\r?\n/g, '<br>' )
 		// Preserve trailing spaces (only the first and last one – the rest is handled below).
 		.replace( /^\s/, '&nbsp;' )
 		.replace( /\s$/, '&nbsp;' )
 		// Preserve other subsequent spaces now.
 		.replace( /\s\s/g, ' &nbsp;' );
 
-	if ( text.indexOf( '</p><p>' ) > -1 ) {
+	if ( text.includes( '</p><p>' ) || text.includes( '<br>' ) ) {
 		// If we created paragraphs above, add the trailing ones.
 		text = `<p>${ text }</p>`;
 	}

+ 3 - 0
packages/ckeditor5-clipboard/src/utils/viewtoplaintext.js

@@ -27,6 +27,9 @@ export default function viewToPlainText( viewItem ) {
 	} else if ( viewItem.is( 'element', 'img' ) && viewItem.hasAttribute( 'alt' ) ) {
 		// Special case for images - use alt attribute if it is provided.
 		text = viewItem.getAttribute( 'alt' );
+	} else if ( viewItem.is( 'element', 'br' ) ) {
+		// A soft break should be converted into a single line break (#8045).
+		text = '\n';
 	} else {
 		// Other elements are document fragments, attribute elements or container elements.
 		// They don't have their own text value, so convert their children.

+ 1 - 1
packages/ckeditor5-clipboard/tests/clipboard.js

@@ -112,7 +112,7 @@ describe( 'Clipboard feature', () => {
 				clipboardPlugin.on( 'inputTransformation', ( evt, data ) => {
 					expect( data.content ).is.instanceOf( ViewDocumentFragment );
 					expect( data.dataTransfer ).to.equal( dataTransferMock );
-					expect( stringifyView( data.content ) ).to.equal( '<p>x</p><p></p><p>y  z</p>' );
+					expect( stringifyView( data.content ) ).to.equal( '<p>x</p><p>y  z</p>' );
 
 					done();
 				} );

+ 13 - 5
packages/ckeditor5-clipboard/tests/utils/plaintexttohtml.js

@@ -10,16 +10,24 @@ describe( 'plainTextToHtml()', () => {
 		expect( plainTextToHtml( 'x y <z>' ) ).to.equal( 'x y &lt;z&gt;' );
 	} );
 
-	it( 'turns a single line break into paragraphs', () => {
-		expect( plainTextToHtml( 'x\ny\nz' ) ).to.equal( '<p>x</p><p>y</p><p>z</p>' );
+	it( 'turns double line breaks into paragraphs (Linux/Mac EOL style)', () => {
+		expect( plainTextToHtml( 'x\n\ny\n\nz' ) ).to.equal( '<p>x</p><p>y</p><p>z</p>' );
 	} );
 
-	it( 'turns double line breaks into paragraphs', () => {
-		expect( plainTextToHtml( 'x\n\ny\n\nz' ) ).to.equal( '<p>x</p><p></p><p>y</p><p></p><p>z</p>' );
+	it( 'turns double line breaks into paragraphs (Windows EOL style)', () => {
+		expect( plainTextToHtml( 'x\r\n\r\ny\r\n\r\nz' ) ).to.equal( '<p>x</p><p>y</p><p>z</p>' );
+	} );
+
+	it( 'turns single line breaks into soft breaks (Linux/Mac EOL style)', () => {
+		expect( plainTextToHtml( 'x\ny\nz' ) ).to.equal( '<p>x<br>y<br>z</p>' );
+	} );
+
+	it( 'turns single line breaks into soft breaks (Windows EOL style)', () => {
+		expect( plainTextToHtml( 'x\r\ny\r\nz' ) ).to.equal( '<p>x<br>y<br>z</p>' );
 	} );
 
 	it( 'turns combination of different amount of line breaks to paragraphs', () => {
-		expect( plainTextToHtml( 'a\nb\n\nc\n\n\nd' ) ).to.equal( '<p>a</p><p>b</p><p></p><p>c</p><p></p><p></p><p>d</p>' );
+		expect( plainTextToHtml( 'a\n\nb\nc\n\n\n\nd\ne' ) ).to.equal( '<p>a</p><p>b<br>c</p><p></p><p>d<br>e</p>' );
 	} );
 
 	it( 'preserves trailing spaces', () => {

+ 16 - 0
packages/ckeditor5-clipboard/tests/utils/viewtoplaintext.js

@@ -34,6 +34,22 @@ describe( 'viewToPlainText()', () => {
 		);
 	} );
 
+	it( 'should turn a soft break into a single empty line', () => {
+		testViewToPlainText(
+			'<container:p>Foo<empty:br />Bar</container:p>',
+
+			'Foo\nBar'
+		);
+	} );
+
+	it( 'should turn multiple soft breaks into empty lines', () => {
+		testViewToPlainText(
+			'<container:p>Foo<empty:br /><empty:br />Bar</container:p>',
+
+			'Foo\n\nBar'
+		);
+	} );
+
 	it( 'should output alt attribute of image elements', () => {
 		testViewToPlainText(
 			'<container:p>Foo</container:p>' +

+ 3 - 3
packages/ckeditor5-code-block/src/codeblockediting.js

@@ -214,9 +214,9 @@ export default class CodeBlockEditing extends Plugin {
 				return;
 			}
 
-			leaveBlockStartOnEnter( editor, data.isSoft ) ||
-			leaveBlockEndOnEnter( editor, data.isSoft ) ||
-			breakLineOnEnter( editor );
+			if ( !leaveBlockStartOnEnter( editor, data.isSoft ) && !leaveBlockEndOnEnter( editor, data.isSoft ) ) {
+				breakLineOnEnter( editor );
+			}
 
 			data.preventDefault();
 			evt.stop();

+ 1 - 1
packages/ckeditor5-core/src/commandcollection.js

@@ -63,7 +63,7 @@ export default class CommandCollection {
 			 * @error commandcollection-command-not-found
 			 * @param {String} commandName Name of the command.
 			 */
-			throw new CKEditorError( 'commandcollection-command-not-found: Command does not exist.', this, { commandName } );
+			throw new CKEditorError( 'commandcollection-command-not-found', this, { commandName } );
 		}
 
 		return command.execute( ...args );

+ 4 - 6
packages/ckeditor5-core/src/context.js

@@ -125,7 +125,7 @@ export default class Context {
 				 * @error context-initplugins-constructor-only
 				 */
 				throw new CKEditorError(
-					'context-initplugins-constructor-only: Only a constructor function is allowed as a context plugin.',
+					'context-initplugins-constructor-only',
 					null,
 					{ Plugin }
 				);
@@ -139,7 +139,7 @@ export default class Context {
 				 * @error context-initplugins-invalid-plugin
 				 */
 				throw new CKEditorError(
-					'context-initplugins-invalid-plugin: Only a plugin marked as a context plugin is allowed to be used with a context.',
+					'context-initplugins-invalid-plugin',
 					null,
 					{ Plugin }
 				);
@@ -177,11 +177,9 @@ export default class Context {
 			/**
 			 * Cannot add multiple editors to the context which is created by the editor.
 			 *
-			 * @error context-addEditor-private-context
+			 * @error context-addeditor-private-context
 			 */
-			throw new CKEditorError(
-				'context-addEditor-private-context: Cannot add multiple editors to the context which is created by the editor.'
-			);
+			throw new CKEditorError( 'context-addeditor-private-context' );
 		}
 
 		this.editors.add( editor );

+ 1 - 1
packages/ckeditor5-core/src/editor/utils/attachtoform.js

@@ -27,7 +27,7 @@ export default function attachToForm( editor ) {
 		 * @error attachtoform-missing-elementapi-interface
 		 */
 		throw new CKEditorError(
-			'attachtoform-missing-elementapi-interface: Editor passed to attachToForm() must implement ElementApi.',
+			'attachtoform-missing-elementapi-interface',
 			editor
 		);
 	}

+ 1 - 1
packages/ckeditor5-core/src/editor/utils/elementapimixin.js

@@ -31,7 +31,7 @@ const ElementApiMixin = {
 			 * @error editor-missing-sourceelement
 			 */
 			throw new CKEditorError(
-				'editor-missing-sourceelement: Cannot update the source element of a detached editor.',
+				'editor-missing-sourceelement',
 				this
 			);
 		}

+ 1 - 2
packages/ckeditor5-core/src/editor/utils/securesourceelement.js

@@ -36,8 +36,7 @@ export default function secureSourceElement( editor ) {
 		 * @param {HTMLElement} element DOM element that caused the collision.
 		 */
 		throw new CKEditorError(
-			'editor-source-element-already-used: ' +
-			'The DOM element cannot be used to create multiple editor instances.',
+			'editor-source-element-already-used',
 			editor
 		);
 	}

+ 1 - 1
packages/ckeditor5-core/src/pendingactions.js

@@ -99,7 +99,7 @@ export default class PendingActions extends ContextPlugin {
 			 *
 			 * @error pendingactions-add-invalid-message
 			 */
-			throw new CKEditorError( 'pendingactions-add-invalid-message: The message must be a string.', this );
+			throw new CKEditorError( 'pendingactions-add-invalid-message', this );
 		}
 
 		const action = Object.create( ObservableMixin );

+ 3 - 4
packages/ckeditor5-core/src/plugincollection.js

@@ -295,7 +295,7 @@ export default class PluginCollection {
 							 * @param {String} requiredBy The name of the parent plugin.
 							 */
 							throw new CKEditorError(
-								'plugincollection-context-required: Context plugin can not require plugin which is not a context plugin',
+								'plugincollection-context-required',
 								null,
 								{ plugin: RequiredPluginConstructor.name, requiredBy: PluginConstructor.name }
 							);
@@ -310,8 +310,7 @@ export default class PluginCollection {
 							 * @param {String} requiredBy The name of the parent plugin.
 							 */
 							throw new CKEditorError(
-								'plugincollection-required: Cannot load a plugin because one of its dependencies is listed in' +
-								'the `removePlugins` option.',
+								'plugincollection-required',
 								context,
 								{ plugin: RequiredPluginConstructor.name, requiredBy: PluginConstructor.name }
 							);
@@ -421,7 +420,7 @@ export default class PluginCollection {
 			 * @param {Function} plugin2 The second plugin constructor.
 			 */
 			throw new CKEditorError(
-				'plugincollection-plugin-name-conflict: Two plugins with the same name were loaded.',
+				'plugincollection-plugin-name-conflict',
 				null,
 				{ pluginName, plugin1: this._plugins.get( pluginName ).constructor, plugin2: PluginConstructor }
 			);

+ 1 - 1
packages/ckeditor5-core/tests/_utils-tests/classictesteditor.js

@@ -232,7 +232,7 @@ describe( 'ClassicTestEditor', () => {
 				.then( () => {
 					throw new Error( 'It should throw an error' );
 				}, err => {
-					assertCKEditorError( err, /^editor-create-initial-data:/, null );
+					assertCKEditorError( err, 'editor-create-initial-data', null );
 					removeEditorBodyOrphans();
 				} );
 		} );

+ 2 - 5
packages/ckeditor5-core/tests/_utils/classictesteditor.js

@@ -77,11 +77,8 @@ export default class ClassicTestEditor extends Editor {
 					.then( () => {
 						if ( !isElement( sourceElementOrData ) && config.initialData ) {
 							// Documented in core/editor/editorconfig.jsdoc.
-							throw new CKEditorError(
-								'editor-create-initial-data: ' +
-								'The config.initialData option cannot be used together with initial data passed in Editor.create().',
-								null
-							);
+							// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
+							throw new CKEditorError( 'editor-create-initial-data', null );
 						}
 
 						editor.data.init( config.initialData || getInitialData( sourceElementOrData ) );

+ 3 - 3
packages/ckeditor5-core/tests/commandcollection.js

@@ -75,7 +75,7 @@ describe( 'CommandCollection', () => {
 
 			expectToThrowCKEditorError( () => {
 				collection.execute( 'foo' );
-			}, /^commandcollection-command-not-found:/, editor );
+			}, 'commandcollection-command-not-found', editor );
 		} );
 	} );
 
@@ -135,8 +135,8 @@ describe( 'CommandCollection', () => {
 		} );
 	} );
 
-	describe( 'commands()', () => {
-		it( 'returns iterator of commands', () => {
+	describe( 'destroy()', () => {
+		it( 'should destroy commands', () => {
 			const c1 = new SomeCommand( editor );
 			const c2 = new SomeCommand( editor );
 

+ 3 - 3
packages/ckeditor5-core/tests/context.js

@@ -113,7 +113,7 @@ describe( 'Context', () => {
 
 			expect( caughtError ).to.instanceof( CKEditorError );
 			expect( caughtError.message )
-				.match( /^context-initplugins-invalid-plugin:/ );
+				.match( /^context-initplugins-invalid-plugin/ );
 		} );
 
 		it( 'should throw when plugin added to the context is not marked as a ContextPlugin (Function)', async () => {
@@ -129,7 +129,7 @@ describe( 'Context', () => {
 
 			expect( caughtError ).to.instanceof( CKEditorError );
 			expect( caughtError.message )
-				.match( /^context-initplugins-invalid-plugin:/ );
+				.match( /^context-initplugins-invalid-plugin/ );
 		} );
 
 		it( 'should throw when plugin is added to the context by name', async () => {
@@ -143,7 +143,7 @@ describe( 'Context', () => {
 
 			expect( caughtError ).to.instanceof( CKEditorError );
 			expect( caughtError.message )
-				.match( /^context-initplugins-constructor-only:/ );
+				.match( /^context-initplugins-constructor-only/ );
 		} );
 
 		it( 'should not throw when plugin as a function, marked as a ContextPlugin is added to the context', async () => {

+ 3 - 2
packages/ckeditor5-core/tests/editor/editor.js

@@ -201,7 +201,7 @@ describe( 'Editor', () => {
 			expectToThrowCKEditorError( () => {
 				// eslint-disable-next-line no-new
 				new TestEditor( { context: editor._context } );
-			}, /^context-addEditor-private-context/ );
+			}, 'context-addeditor-private-context' );
 		} );
 
 		it( 'should destroy context created by the editor at the end of the editor destroy chain', async () => {
@@ -510,7 +510,7 @@ describe( 'Editor', () => {
 
 			expectToThrowCKEditorError( () => {
 				editor.execute( 'command' );
-			}, /^commandcollection-command-not-found:/, editor );
+			}, /^commandcollection-command-not-found/, editor );
 		} );
 
 		it( 'should rethrow native errors as they are in the debug=true mode', () => {
@@ -543,6 +543,7 @@ describe( 'Editor', () => {
 					this.isEnabled = true;
 				}
 				execute() {
+					// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
 					throw new CKEditorError( 'foo', editor );
 				}
 			}

+ 9 - 9
packages/ckeditor5-core/tests/plugincollection.js

@@ -255,7 +255,7 @@ describe( 'PluginCollection', () => {
 					expect( err ).to.have.property( 'message', 'Some error inside a plugin' );
 
 					sinon.assert.calledOnce( consoleErrorStub );
-					expect( consoleErrorStub.args[ 0 ][ 0 ] ).to.match( /^plugincollection-load:/ );
+					expect( consoleErrorStub.args[ 0 ][ 0 ] ).to.match( /^plugincollection-load/ );
 				} );
 		} );
 
@@ -270,10 +270,10 @@ describe( 'PluginCollection', () => {
 					throw new Error( 'Test error: this promise should not be resolved successfully' );
 				} )
 				.catch( err => {
-					assertCKEditorError( err, /^plugincollection-plugin-not-found/, editor );
+					assertCKEditorError( err, 'plugincollection-plugin-not-found', editor );
 
 					sinon.assert.calledOnce( consoleErrorStub );
-					expect( consoleErrorStub.args[ 0 ][ 0 ] ).to.match( /^plugincollection-plugin-not-found:/ );
+					expect( consoleErrorStub.args[ 0 ][ 0 ] ).to.match( /^plugincollection-plugin-not-found/ );
 				} );
 		} );
 
@@ -409,7 +409,7 @@ describe( 'PluginCollection', () => {
 					throw new Error( 'The `init()` method should fail.' );
 				} )
 				.catch( err => {
-					assertCKEditorError( err, /^plugincollection-plugin-name-conflict:/, null, {
+					assertCKEditorError( err, /^plugincollection-plugin-name-conflict/, null, {
 						pluginName: 'Foo',
 						plugin1: PluginFoo,
 						plugin2: AnotherPluginFoo
@@ -429,7 +429,7 @@ describe( 'PluginCollection', () => {
 					throw new Error( 'The `init()` method should fail.' );
 				} )
 				.catch( err => {
-					assertCKEditorError( err, /^plugincollection-plugin-name-conflict:/, null );
+					assertCKEditorError( err, /^plugincollection-plugin-name-conflict/, null );
 
 					sinon.assert.calledOnce( consoleErrorStub );
 				} );
@@ -447,7 +447,7 @@ describe( 'PluginCollection', () => {
 					throw new Error( 'The `init()` method should fail.' );
 				} )
 				.catch( err => {
-					assertCKEditorError( err, /^plugincollection-plugin-name-conflict:/, null );
+					assertCKEditorError( err, /^plugincollection-plugin-name-conflict/, null );
 					sinon.assert.calledOnce( consoleErrorStub );
 				} );
 		} );
@@ -521,7 +521,7 @@ describe( 'PluginCollection', () => {
 
 			return plugins.init( [] ).then( () => {
 				expectToThrowCKEditorError( () => plugins.get( 'foo' ),
-					/^plugincollection-plugin-not-loaded:/, editor, { plugin: 'foo' }
+					/^plugincollection-plugin-not-loaded/, editor, { plugin: 'foo' }
 				);
 			} );
 		} );
@@ -534,7 +534,7 @@ describe( 'PluginCollection', () => {
 
 			return plugins.init( [] ).then( () => {
 				expectToThrowCKEditorError( () => plugins.get( SomePlugin ),
-					/^plugincollection-plugin-not-loaded:/, editor, { plugin: 'foo' } );
+					/^plugincollection-plugin-not-loaded/, editor, { plugin: 'foo' } );
 			} );
 		} );
 
@@ -545,7 +545,7 @@ describe( 'PluginCollection', () => {
 
 			return plugins.init( [] ).then( () => {
 				expectToThrowCKEditorError( () => plugins.get( SomePlugin ),
-					/^plugincollection-plugin-not-loaded:/,
+					/^plugincollection-plugin-not-loaded/,
 					editor, { plugin: 'SomePlugin' }
 				);
 			} );

+ 4 - 9
packages/ckeditor5-editor-balloon/src/ballooneditor.js

@@ -203,10 +203,8 @@ export default class BalloonEditor extends Editor {
 
 			if ( isHTMLElement && sourceElementOrData.tagName === 'TEXTAREA' ) {
 				// Documented in core/editor/editor.js
-				throw new CKEditorError(
-					'editor-wrong-element: This type of editor cannot be initialized inside <textarea> element.',
-					null
-				);
+				// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
+				throw new CKEditorError( 'editor-wrong-element', null );
 			}
 
 			const editor = new this( sourceElementOrData, config );
@@ -219,11 +217,8 @@ export default class BalloonEditor extends Editor {
 					.then( () => {
 						if ( !isHTMLElement && config.initialData ) {
 							// Documented in core/editor/editorconfig.jdoc.
-							throw new CKEditorError(
-								'editor-create-initial-data: ' +
-								'The config.initialData option cannot be used together with initial data passed in Editor.create().',
-								null
-							);
+							// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
+							throw new CKEditorError( 'editor-create-initial-data', null );
 						}
 
 						const initialData = config.initialData || getInitialData( sourceElementOrData );

+ 3 - 12
packages/ckeditor5-editor-balloon/tests/ballooneditor.js

@@ -96,9 +96,7 @@ describe( 'BalloonEditor', () => {
 						expect.fail( 'Balloon editor should not initialize on an element already used by other instance.' );
 					},
 					err => {
-						assertCKEditorError( err,
-							/^editor-source-element-already-used/
-						);
+						assertCKEditorError( err, 'editor-source-element-already-used' );
 					}
 				)
 				.then( done )
@@ -199,11 +197,7 @@ describe( 'BalloonEditor', () => {
 						expect.fail( 'Balloon editor should throw an error when both initial data are passed' );
 					},
 					err => {
-						assertCKEditorError( err,
-							// eslint-disable-next-line max-len
-							/^editor-create-initial-data: The config\.initialData option cannot be used together with initial data passed in Editor\.create\(\)\./,
-							null
-						);
+						assertCKEditorError( err, 'editor-create-initial-data', null );
 					}
 				)
 				.then( () => {
@@ -247,10 +241,7 @@ describe( 'BalloonEditor', () => {
 						expect.fail( 'Balloon editor should throw an error when is initialized in textarea.' );
 					},
 					err => {
-						assertCKEditorError( err,
-							/^editor-wrong-element: This type of editor cannot be initialized inside <textarea> element\./,
-							null
-						);
+						assertCKEditorError( err, 'editor-wrong-element', null );
 					}
 				)
 				.then( done )

+ 2 - 5
packages/ckeditor5-editor-classic/src/classiceditor.js

@@ -200,11 +200,8 @@ export default class ClassicEditor extends Editor {
 					.then( () => {
 						if ( !isElement( sourceElementOrData ) && config.initialData ) {
 							// Documented in core/editor/editorconfig.jdoc.
-							throw new CKEditorError(
-								'editor-create-initial-data: ' +
-								'The config.initialData option cannot be used together with initial data passed in Editor.create().',
-								null
-							);
+							// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
+							throw new CKEditorError( 'editor-create-initial-data', null );
 						}
 
 						const initialData = config.initialData || getInitialData( sourceElementOrData );

+ 4 - 7
packages/ckeditor5-editor-decoupled/src/decouplededitor.js

@@ -226,8 +226,8 @@ export default class DecoupledEditor extends Editor {
 
 			if ( isHTMLElement && sourceElementOrData.tagName === 'TEXTAREA' ) {
 				// Documented in core/editor/editor.js
-				throw new CKEditorError(
-					'editor-wrong-element: This type of editor cannot be initialized inside <textarea> element.', null );
+				// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
+				throw new CKEditorError( 'editor-wrong-element', null );
 			}
 
 			const editor = new this( sourceElementOrData, config );
@@ -240,11 +240,8 @@ export default class DecoupledEditor extends Editor {
 					.then( () => {
 						if ( !isHTMLElement && config.initialData ) {
 							// Documented in core/editor/editorconfig.jdoc.
-							throw new CKEditorError(
-								'editor-create-initial-data: ' +
-								'The config.initialData option cannot be used together with initial data passed in Editor.create().',
-								null
-							);
+							// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
+							throw new CKEditorError( 'editor-create-initial-data', null );
 						}
 
 						const initialData = config.initialData || getInitialData( sourceElementOrData );

+ 3 - 10
packages/ckeditor5-editor-decoupled/tests/decouplededitor.js

@@ -163,7 +163,7 @@ describe( 'DecoupledEditor', () => {
 						expect.fail( 'Decoupled editor should not initialize on an element already used by other instance.' );
 					},
 					err => {
-						assertCKEditorError( err, /^editor-source-element-already-used/ );
+						assertCKEditorError( err, 'editor-source-element-already-used' );
 					}
 				)
 				.then( done )
@@ -180,11 +180,7 @@ describe( 'DecoupledEditor', () => {
 						expect.fail( 'Decoupled editor should throw an error when both initial data are passed' );
 					},
 					err => {
-						assertCKEditorError( err,
-							// eslint-disable-next-line max-len
-							/^editor-create-initial-data: The config\.initialData option cannot be used together with initial data passed in Editor\.create\(\)\./,
-							null
-						);
+						assertCKEditorError( err, 'editor-create-initial-data' );
 					}
 				)
 				.then( () => {
@@ -201,10 +197,7 @@ describe( 'DecoupledEditor', () => {
 						expect.fail( 'Decoupled editor should throw an error when is initialized in textarea.' );
 					},
 					err => {
-						assertCKEditorError( err,
-							/^editor-wrong-element: This type of editor cannot be initialized inside <textarea> element\./,
-							null
-						);
+						assertCKEditorError( err, 'editor-wrong-element', null );
 					}
 				)
 				.then( done )

+ 4 - 7
packages/ckeditor5-editor-inline/src/inlineeditor.js

@@ -199,8 +199,8 @@ export default class InlineEditor extends Editor {
 
 			if ( isHTMLElement && sourceElementOrData.tagName === 'TEXTAREA' ) {
 				// Documented in core/editor/editor.js
-				throw new CKEditorError(
-					'editor-wrong-element: This type of editor cannot be initialized inside <textarea> element.', null );
+				// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
+				throw new CKEditorError( 'editor-wrong-element', null );
 			}
 
 			const editor = new this( sourceElementOrData, config );
@@ -213,11 +213,8 @@ export default class InlineEditor extends Editor {
 					.then( () => {
 						if ( !isHTMLElement && config.initialData ) {
 							// Documented in core/editor/editorconfig.jdoc.
-							throw new CKEditorError(
-								'editor-create-initial-data: ' +
-								'The config.initialData option cannot be used together with initial data passed in Editor.create().',
-								null
-							);
+							// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
+							throw new CKEditorError( 'editor-create-initial-data', null );
 						}
 
 						const initialData = config.initialData || getInitialData( sourceElementOrData );

+ 3 - 12
packages/ckeditor5-editor-inline/tests/inlineeditor.js

@@ -97,9 +97,7 @@ describe( 'InlineEditor', () => {
 						expect.fail( 'Inline editor should not initialize on an element already used by other instance.' );
 					},
 					err => {
-						assertCKEditorError( err,
-							/^editor-source-element-already-used/
-						);
+						assertCKEditorError( err, 'editor-source-element-already-used' );
 					}
 				)
 				.then( done )
@@ -209,11 +207,7 @@ describe( 'InlineEditor', () => {
 						expect.fail( 'Inline editor should throw an error when both initial data are passed' );
 					},
 					err => {
-						assertCKEditorError( err,
-							/* eslint-disable-next-line max-len */
-							/^editor-create-initial-data: The config\.initialData option cannot be used together with initial data passed in Editor\.create\(\)\./,
-							null
-						);
+						assertCKEditorError( err, 'editor-create-initial-data', null );
 					}
 				)
 				.then( () => {
@@ -257,10 +251,7 @@ describe( 'InlineEditor', () => {
 						expect.fail( 'Inline editor should throw an error when is initialized in textarea.' );
 					},
 					err => {
-						assertCKEditorError( err,
-							/^editor-wrong-element: This type of editor cannot be initialized inside <textarea> element\./,
-							null
-						);
+						assertCKEditorError( err, 'editor-wrong-element', null );
 					}
 				)
 				.then( done )

+ 22 - 13
packages/ckeditor5-engine/docs/_snippets/framework/extending-content-custom-element-converter.js

@@ -9,7 +9,7 @@ import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud
 
 class InfoBox {
 	constructor( editor ) {
-		// Schema definition
+		// Schema definition.
 		editor.model.schema.register( 'infoBox', {
 			allowWhere: '$block',
 			allowContentOf: '$root',
@@ -21,7 +21,7 @@ class InfoBox {
 		editor.conversion.for( 'upcast' )
 			.add( dispatcher => dispatcher.on( 'element:div', upcastConverter ) );
 
-		// The downcast conversion must be split as we need a widget in the editing pipeline.
+		// The downcast conversion must be split as you need a widget in the editing pipeline.
 		editor.conversion.for( 'editingDowncast' )
 			.add( dispatcher => dispatcher.on( 'insert:infoBox', editingDowncastConverter ) );
 		editor.conversion.for( 'dataDowncast' )
@@ -32,46 +32,51 @@ class InfoBox {
 function upcastConverter( event, data, conversionApi ) {
 	const viewInfoBox = data.viewItem;
 
-	// Detect that view element is an info-box div.
+	// Detect that a view element is an info box <div>.
 	// Otherwise, it should be handled by another converter.
 	if ( !viewInfoBox.hasClass( 'info-box' ) ) {
 		return;
 	}
 
-	// Create a model structure.
+	// Create the model structure.
 	const modelElement = conversionApi.writer.createElement( 'infoBox', {
 		infoBoxType: getTypeFromViewElement( viewInfoBox )
 	} );
 
-	// Try to safely insert element - if it returns false the element can't be safely inserted
-	// into the content, and the conversion process must stop.
+	// Try to safely insert the element into the model structure.
+	// If `safeInsert()` returns `false`, the element cannot be safely inserted
+	// into the content and the conversion process must stop.
+	// This may happen if the data that you are converting has an incorrect structure
+	// (e.g. it was copied from an external website).
 	if ( !conversionApi.safeInsert( modelElement, data.modelCursor ) ) {
 		return;
 	}
 
-	// Mark info-box div as handled by this converter.
+	// Mark the info box <div> as handled by this converter.
 	conversionApi.consumable.consume( viewInfoBox, { name: true } );
 
-	// Let's assume that the HTML structure is always the same.
+	// Let us assume that the HTML structure is always the same.
+	// Note: For full bulletproofing this converter, you should also check
+	// whether these elements are the right ones.
 	const viewInfoBoxTitle = viewInfoBox.getChild( 0 );
 	const viewInfoBoxContent = viewInfoBox.getChild( 1 );
 
-	// Mark info-box inner elements as handled by this converter.
+	// Mark info box inner elements (title and content <div>s) as handled by this converter.
 	conversionApi.consumable.consume( viewInfoBoxTitle, { name: true } );
 	conversionApi.consumable.consume( viewInfoBoxContent, { name: true } );
 
-	// Let the editor handle children of the info-box content conversion.
+	// Let the editor handle the children of <div class="info-box-content">.
 	conversionApi.convertChildren( viewInfoBoxContent, modelElement );
 
-	// Conversion requires updating result data structure properly.
+	// Finally, update the conversion's modelRange and modelCursor.
 	conversionApi.updateConversionResult( modelElement, data );
 }
 
 function editingDowncastConverter( event, data, conversionApi ) {
 	let { infoBox, infoBoxContent, infoBoxTitle } = createViewElements( data, conversionApi );
 
-	// Decorate view items as widgets.
-	infoBox = toWidget( infoBox, conversionApi.writer, { label: 'simple box widget' } );
+	// Decorate view items as a widget and widget editable area.
+	infoBox = toWidget( infoBox, conversionApi.writer, { label: 'info box widget' } );
 	infoBoxContent = toWidgetEditable( infoBoxContent, conversionApi.writer );
 
 	insertViewElements( data, conversionApi, infoBox, infoBoxTitle, infoBoxContent );
@@ -118,7 +123,11 @@ function insertViewElements( data, conversionApi, infoBox, infoBoxTitle, infoBox
 		infoBoxContent
 	);
 
+	// The default mapping between the model <infoBox> and its view representation.
 	conversionApi.mapper.bindElements( data.item, infoBox );
+	// However, since the model <infoBox> content needs to end up in the inner
+	// <div class="info-box-content">, you need to bind one with another overriding
+	// a part of the default binding.
 	conversionApi.mapper.bindElements( data.item, infoBoxContent );
 
 	conversionApi.writer.insert(

+ 3 - 1
packages/ckeditor5-engine/docs/framework/guides/deep-dive/conversion-extending-output.md

@@ -355,4 +355,6 @@ Add some CSS styles for `.my-heading` to see the customization in action:
 
 ## What's next?
 
-If you would like to read more about how to make CKEditor 5 accept more content, refer to the {@link framework/guides/deep-dive/conversion-preserving-custom-content Preserving custom content} guide.
+If you would like to read more about how to make CKEditor 5 accept more content, refer to the {@link framework/guides/deep-dive/conversion-preserving-custom-content Preserving custom content} guide.
+
+If you want to learn how to create complex view structures or how to move from {@link module:engine/conversion/conversion~Conversion two-way} or {@link module:engine/conversion/conversion~Conversion#for one-way} converters to event-based ones, refer to the {@link framework/guides/deep-dive/custom-element-conversion Custom element conversion} guide.

+ 1 - 0
packages/ckeditor5-engine/docs/framework/guides/deep-dive/conversion-introduction.md

@@ -126,3 +126,4 @@ Once you understand more about the conversion of model attributes, you can check
 
 * {@link framework/guides/deep-dive/conversion-extending-output Extending the editor output} &mdash; How to extend the output of existing CKEditor 5 features.
 * {@link framework/guides/deep-dive/conversion-preserving-custom-content Preserving custom content} &mdash; How to make CKEditor 5 accept more content.
+* {@link framework/guides/deep-dive/custom-element-conversion Custom element conversion} &mdash; How to deal with complex view structures during the model-to-view conversion.

+ 2 - 0
packages/ckeditor5-engine/docs/framework/guides/deep-dive/conversion-preserving-custom-content.md

@@ -487,3 +487,5 @@ ClassicEditor
 ## What's next?
 
 If you would like to read more about how to extend the output of existing CKEditor 5 features, refer to the {@link framework/guides/deep-dive/conversion-extending-output Extending the editor output} guide.
+
+If you want to learn how to create complex view structures or how to move from {@link module:engine/conversion/conversion~Conversion two-way} or {@link module:engine/conversion/conversion~Conversion#for one-way} converters to event-based ones, refer to the {@link framework/guides/deep-dive/custom-element-conversion Custom element conversion} guide.

+ 49 - 44
packages/ckeditor5-engine/docs/framework/guides/deep-dive/custom-element-conversion.md

@@ -8,28 +8,31 @@ order: 40
 
 There are three levels on which elements can be converted:
 
-* By using the two-way converter: {@link module:engine/conversion/conversion~Conversion#elementToElement `conversion.elementToElement()`}. It is a fully declarative API. It is the least powerful option but it is the easiest one to use.
-* By using one-way converters: for example {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `conversion.for( 'downcast' ).elementToElement()`} and {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToElement `conversion.for( 'upcast' ).elementToElement()`}. In this case, you need to define at least two converters (for upcast and downcast), but the "how" part becomes a callback, and hence you gain more control over it.
-* Finally, by using event-based converters. In this case, you need to listen to events fired by {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} and {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher}. This method has the full access to every bit of logic that a converter needs to implement and therefore it can be used to write the most complex conversion methods.
+* By using the two-way converter: {@link module:engine/conversion/conversion~Conversion#elementToElement `conversion.elementToElement()`}.
+  This is a fully declarative API. It is the least powerful option but it is the easiest one to use.
+* By using one-way converters: for example {@link module:engine/conversion/downcasthelpers~DowncastHelpers#elementToElement `conversion.for( 'downcast' ).elementToElement()`} and {@link module:engine/conversion/upcasthelpers~UpcastHelpers#elementToElement `conversion.for( 'upcast' ).elementToElement()`}.
+  In this case, you need to define at least two converters (for upcast and downcast), but the "how" part becomes a callback, and hence you gain more control over it.
+* Finally, by using event-based converters.
+  In this case, you need to listen to events fired by {@link module:engine/conversion/downcastdispatcher~DowncastDispatcher} and {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher}. This method has full access to every bit of logic that a converter needs to implement and therefore it can be used to write the most complex conversion methods.
 
-In this guide, we will show you how to migrate from a simple two-way converter to an event-based converters as the requirements regarding the feature get more complex.
+This guide explains how to migrate from a simple two-way converter to an event-based converter as the requirements regarding the feature get more complex.
 
 ## Introduction
 
-Let's assume that content in your application contains "info boxes". As for now, it was only required to wrap part of a content in a `<div>` element that would look in the data and editing views like this:
+Let us assume that the content in your application contains "info boxes". As for now, it was only required to wrap a part of the content in a `<div>` element that would look like this in the data and editing views:
 
 ```html
 <div class="info-box">
-	<!-- any editable content -->
+	<!-- Any editable content. -->
 	<p>This is <strong>important!</strong></p>
 </div>
 ```
 
-This data is represented in the model as the following structure:
+The data is represented in the model as the following structure:
 
 ```html
 <infoBox>
-	<!-- any $block content: -->
+	<!-- Any $block content. -->
 	<paragraph><$text>This is </$text><$text bold="true">important!</$text></paragraph>
 </infoBox>
 ```
@@ -39,14 +42,14 @@ This can be easily done with the below schema and converters in a simple `InfoBo
 ```js
 class InfoBox {
 	constructor( editor ) {
-		// 1. Define infoBox as an object that can be contained any other content.
+		// 1. Define infoBox as an object that can contain any other content.
 		editor.model.schema.register( 'infoBox', {
 			allowWhere: '$block',
 			allowContentOf: '$root',
 			isObject: true
 		} );
 
-		// 2. Conversion is straight forward:
+		// 2. The conversion is straightforward:
 		editor.conversion.elementToElement( {
 			model: 'infoBox',
 			view: {
@@ -60,7 +63,7 @@ class InfoBox {
 
 ## Migrating to an event-based converter
 
-Let's now assume that the requirements have changed and there is a need for adding an additional element in the data and editing views that will display the type of the info box (warning, error, info, etc.).
+Let us now assume that the requirements have changed and there is a need for adding an additional element in the data and editing views that will display the type of the info box (warning, error, info, etc.).
 
 The new info box structure:
 
@@ -68,56 +71,56 @@ The new info box structure:
 <div class="info-box info-box-warning">
 	<div class="info-box-title">Warning</div>
 	<div class="info-box-content">
-		<!-- any editable content -->
+		<!-- Any editable content. -->
 		<p>This is <strong>important!</strong></p>
 	</div>
 </div>
 ```
 
-The "Warning" part should not be editable. It defines a type of the info box so we can store this  bit of information as an attribute of the `<infoBox>` element:
+The "Warning" part should not be editable. It defines the type of the info box so you can store this bit of information as an attribute of the `<infoBox>` element:
 
 ```html
 <infoBox infoBoxType="warning">
-	<!-- any $block content: -->
+	<!-- Any $block content. -->
 	<paragraph><$text>This is </$text><$text bold="true">important!</$text></paragraph>
 </infoBox>
 ```
 
-Let's see how to update our basic implementation to cover these requirements.
+Let us see how to update the basic implementation to cover these requirements.
 
 ### Demo
 
-Below is a demo of the editor with the example info box.
+Below is a demo of the editor with a sample info box.
 
 {@snippet framework/extending-content-custom-element-converter}
 
 ### Schema
 
-The type of the box is defined by the additional class on the main `<div>` but it is also represented as text in `<div class="info-box-title">`. All the info box content must be now placed inside `<div class="info-box-content">` instead of the main wrapper.
+The type of the box is defined by an additional class on the main `<div>` but it is also represented as text in `<div class="info-box-title">`. All the info box content must now be placed inside `<div class="info-box-content">` instead of the main wrapper.
 
-For the above requirements we can see that the model structure of the `infoBox` does not need to change much. We can still use a single element in the model. The only addition to the model is an attribute that will hold information about the info box type:
+For the above requirements you can see that the model structure of the `infoBox` does not need to change much. You can still use a single element in the model. The only addition to the model is an attribute that will store information about the info box type:
 
 ```js
 editor.model.schema.register( 'infoBox', {
 	allowWhere: '$block',
 	allowContentOf: '$root',
 	isObject: true,
-	allowAttributes: [ 'infoBoxType' ] // Added
+	allowAttributes: [ 'infoBoxType' ] // Added.
 } );
 ```
 
 ### Event-based upcast converter
 
-The conversion of the type of the box itself could be achieved by using {@link module:engine/conversion/conversion~Conversion#attributeToAttribute `attributeToAttribute()`} (`info-box-*` CSS classes to the `infoBoxType` model attribute). However, two more changes were made to the data format that we need to handle:
+The conversion of the type of the box itself can be achieved by using {@link module:engine/conversion/conversion~Conversion#attributeToAttribute `attributeToAttribute()`} (`info-box-*` CSS classes to the `infoBoxType` model attribute). However, two more changes were made to the data format that you need to handle:
 
-* There is the new `<div class="info-box-title">` element that should be ignored during upcast conversion as it duplicates the information conveyed by the main element's CSS class.
-* The content of the info box is now located inside another element (previously it was located directly in the main wrapper).
+* There is a new `<div class="info-box-title">` element that should be ignored during the upcast conversion as it duplicates the information conveyed by the main element's CSS class.
+* The content of the info box is now located inside another element. Previously it was located directly in the main wrapper.
 
-Neither two-way nor one-way converters can handle such conversion. Therefore, we need to use an event-based converter with the following behavior:
+Neither two-way nor one-way converters can handle such conversion. Therefore, you need to use an event-based converter with the following behavior:
 
-1. Create model `<infoBox>` element with `infoBoxType` attribute.
-1. Skip conversion of `<div class="info-box-title">` as the information about type can be obtained from the wrapper's CSS classes.
-1. Convert children of `<div class="info-box-content">` and insert them directly into `<infoBox>`.
+1. Create a model `<infoBox>` element with the `infoBoxType` attribute.
+1. Skip the conversion of `<div class="info-box-title">` as the information about type can be obtained from the wrapper's CSS classes.
+1. Convert the children of `<div class="info-box-content">` and insert them directly into `<infoBox>`.
 
 ```js
 function upcastConverter( event, data, conversionApi ) {
@@ -129,16 +132,16 @@ function upcastConverter( event, data, conversionApi ) {
 		return;
 	}
 
-	// Create a model structure.
+	// Create the model structure.
 	const modelElement = conversionApi.writer.createElement( 'infoBox', {
 		infoBoxType: getTypeFromViewElement( viewInfoBox )
 	} );
 
 	// Try to safely insert the element into the model structure.
-	// If `safeInsert()` returns `false` the element cannot be safely inserted
-	// into the content, and the conversion process must stop.
-	// This may happen if the data that we are converting has incorrect structure
-	// (e.g. was copied from an external website).
+	// If `safeInsert()` returns `false`, the element cannot be safely inserted
+	// into the content and the conversion process must stop.
+	// This may happen if the data that you are converting has an incorrect structure
+	// (e.g. it was copied from an external website).
 	if ( !conversionApi.safeInsert( modelElement, data.modelCursor ) ) {
 		return;
 	}
@@ -146,8 +149,8 @@ function upcastConverter( event, data, conversionApi ) {
 	// Mark the info box <div> as handled by this converter.
 	conversionApi.consumable.consume( viewInfoBox, { name: true } );
 
-	// Let's assume that the HTML structure is always the same.
-	// Note: for full bulletproofing this converter we should also check
+	// Let us assume that the HTML structure is always the same.
+	// Note: For full bulletproofing this converter, you should also check
 	// whether these elements are the right ones.
 	const viewInfoBoxTitle = viewInfoBox.getChild( 0 );
 	const viewInfoBoxContent = viewInfoBox.getChild( 1 );
@@ -156,14 +159,14 @@ function upcastConverter( event, data, conversionApi ) {
 	conversionApi.consumable.consume( viewInfoBoxTitle, { name: true } );
 	conversionApi.consumable.consume( viewInfoBoxContent, { name: true } );
 
-	// Let the editor handle children of <div class="info-box-content">.
+	// Let the editor handle the children of <div class="info-box-content">.
 	conversionApi.convertChildren( viewInfoBoxContent, modelElement );
 
 	// Finally, update the conversion's modelRange and modelCursor.
 	conversionApi.updateConversionResult( modelElement, data );
 }
 
-// Helper function to read the type from the view classes.
+// A helper function to read the type from the view classes.
 function getTypeFromViewElement( viewElement ) {
 	if ( viewElement.hasClass( 'info-box-info' ) ) {
 		return 'Info';
@@ -177,7 +180,7 @@ function getTypeFromViewElement( viewElement ) {
 }
 ```
 
-This upcast converter callback can now be plugged by adding a listener to the {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#element `UpcastDispatcher#element` event}. We will listen to `element:div` to ensure that the callback is called only for `<div>` elements.
+This upcast converter callback can now be plugged by adding a listener to the {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#element `UpcastDispatcher#element` event}. You will listen to `element:div` to ensure that the callback is called only for `<div>` elements.
 
 ```js
 editor.conversion.for( 'upcast' )
@@ -186,10 +189,12 @@ editor.conversion.for( 'upcast' )
 
 ### Event-based downcast converter
 
-The missing bit are the downcast converters for the editing and data pipelines. We want to use the widget system to make the info box behave like an "object". The other aspect that we need to take care of is the fact that the view structure has more elements than the model structure. In this case, we could actually use one-way converters. However, we will showcase how an event-based converter would look.
+The missing bits are the downcast converters for the editing and data pipelines.
+
+You will want to use the widget system to make the info box behave like an "object". Another aspect that you need to take care of is the fact that the view structure has more elements than the model structure. In this case, you could actually use one-way converters. However, this tutorial will showcase how an event-based converter would look.
 
 <info-box>
-	See the {@link framework/guides/tutorials/implementing-a-block-widget Implementing a block widget} to learn about the widget system.
+	See the {@link framework/guides/tutorials/implementing-a-block-widget Implementing a block widget} guide to learn about the widget system.
 </info-box>
 
 The remaining downcast converters:
@@ -248,9 +253,9 @@ function insertViewElements( data, conversionApi, infoBox, infoBoxTitle, infoBox
 
 	// The default mapping between the model <infoBox> and its view representation.
 	conversionApi.mapper.bindElements( data.item, infoBox );
-	// However, since the model <infoBox> content need to end up in the inner
-	// <div class="info-box-content"> we need to bind one with another overriding
-	// part of the default binding.
+	// However, since the model <infoBox> content needs to end up in the inner
+	// <div class="info-box-content">, you need to bind one with another overriding
+	// a part of the default binding.
 	conversionApi.mapper.bindElements( data.item, infoBoxContent );
 
 	conversionApi.writer.insert(
@@ -271,12 +276,12 @@ editor.conversion.for( 'dataDowncast' )
 
 ### Updated plugin code
 
-The updated `InfoBox` plugin that glues all this together:
+The updated `InfoBox` plugin that glues the event-based converters together:
 
 ```js
 class InfoBox {
 	constructor( editor ) {
-		// Schema definition
+		// Schema definition.
 		editor.model.schema.register( 'infoBox', {
 			allowWhere: '$block',
 			allowContentOf: '$root',
@@ -288,7 +293,7 @@ class InfoBox {
 		editor.conversion.for( 'upcast' )
 			.add( dispatcher => dispatcher.on( 'element:div', upcastConverter ) );
 
-		// The downcast conversion must be split as we need a widget in the editing pipeline.
+		// The downcast conversion must be split as you need a widget in the editing pipeline.
 		editor.conversion.for( 'editingDowncast' )
 			.add( dispatcher => dispatcher.on( 'insert:infoBox', editingDowncastConverter ) );
 		editor.conversion.for( 'dataDowncast' )

+ 8 - 8
packages/ckeditor5-engine/docs/framework/guides/deep-dive/schema.md

@@ -260,8 +260,8 @@ Here is a table listing various model elements and their properties registered i
 </table>
 
 <info-box>
-	* <span id="inherited1">[1]</span> The value of `isLimit` is `true` for this element because all [objects](#object-elements) are automatically [limit elements](#limit-elements),
-	* <span id="inherited2">[2]</span> The value of `isSelectable` is `true` for this element because all [objects](#object-elements) are automatically [selectable elements](#selectable-elements),
+	* <span id="inherited1">[1]</span> The value of `isLimit` is `true` for this element because all [objects](#object-elements) are automatically [limit elements](#limit-elements).
+	* <span id="inherited2">[2]</span> The value of `isSelectable` is `true` for this element because all [objects](#object-elements) are automatically [selectable elements](#selectable-elements).
 	* <span id="inherited3">[3]</span> The value of `isContent` is `true` for this element because all [objects](#object-elements) are automatically [content elements](#content-elements).
 </info-box>
 
@@ -303,11 +303,11 @@ schema.register( 'myImage', {
 The {@link module:engine/model/schema~Schema#isObject `Schema#isObject()`} can later be used to check this property.
 
 <info-box>
-	Every "object" is automatically also:
+	Every object is automatically also:
 
-	* a [limit element](#limit-elements) – for every element with `isObject` set `true`, {@link module:engine/model/schema~Schema#isLimit `Schema#isLimit( element )`} will always return `true`.
-	* a [selectable element](#selectable-elements) – for every element with `isObject` set `true`, {@link module:engine/model/schema~Schema#isSelectable `Schema#isSelectable( element )`} will always return `true`.
-	* a [content element](#content-elements) – for every element with `isObject` set `true`, {@link module:engine/model/schema~Schema#isContent `Schema#isContent( element )`} will always return `true`.
+	* A [limit element](#limit-elements) &ndash; For every element with `isObject` set to `true`, {@link module:engine/model/schema~Schema#isLimit `Schema#isLimit( element )`} will always return `true`.
+	* A [selectable element](#selectable-elements) &ndash; For every element with `isObject` set to `true`, {@link module:engine/model/schema~Schema#isSelectable `Schema#isSelectable( element )`} will always return `true`.
+	* A [content element](#content-elements) &ndash; For every element with `isObject` set to `true`, {@link module:engine/model/schema~Schema#isContent `Schema#isContent( element )`} will always return `true`.
 </info-box>
 
 ### Block elements
@@ -341,14 +341,14 @@ schema.register( 'mySelectable', {
 The {@link module:engine/model/schema~Schema#isSelectable `Schema#isSelectable()`} method can later be used to check this property.
 
 <info-box>
-	All [object elements](#object-elements) are selectable by default. There are other selectable elements registered in the editor, though. For instance, there is also the `tableCell` model element (rendered as a `<td>` in the editing view) that is selectable while **not** registered as an object. The {@link features/table#table-selection table selection} plugin takes advantage of this fact and allows users create rectangular selections made of multiple table cells.
+	All [object elements](#object-elements) are selectable by default. There are other selectable elements registered in the editor, though. For instance, there is also the `tableCell` model element (rendered as a `<td>` in the editing view) that is selectable while **not** registered as an object. The {@link features/table#table-selection table selection} plugin takes advantage of this fact and allows users to create rectangular selections made of multiple table cells.
 </info-box>
 
 ### Content elements
 
 You can tell content model elements from other elements by looking at their representation in the editor data (you can use {@link module:editor-classic/classiceditor~ClassicEditor#getData `editor.getData()`} or {@link module:engine/model/model~Model#hasContent Model#hasContent()} to check this out).
 
-Elements such as images or media will **always** find their way into editor data and this is what makes them content elements. They are marked with the {@link module:engine/model/schema~SchemaItemDefinition#isContent `isContent`} property in the schema:
+Elements such as images or media will **always** find their way into the editor data and this is what makes them content elements. They are marked with the {@link module:engine/model/schema~SchemaItemDefinition#isContent `isContent`} property in the schema:
 
 ```js
 schema.register( 'myImage', {

+ 5 - 5
packages/ckeditor5-engine/src/controller/datacontroller.js

@@ -72,7 +72,7 @@ export default class DataController {
 		 *
 		 * @member {module:engine/dataprocessor/dataprocessor~DataProcessor} #processor
 		 */
-		this.processor;
+		this.processor = undefined;
 
 		/**
 		 * Mapper used for the conversion. It has no permanent bindings, because they are created when getting data and
@@ -176,7 +176,7 @@ export default class DataController {
 			 *
 			 * @error datacontroller-get-non-existent-root
 			 */
-			throw new CKEditorError( 'datacontroller-get-non-existent-root: Attempting to get data from a non-existing root.', this );
+			throw new CKEditorError( 'datacontroller-get-non-existent-root', this );
 		}
 
 		const root = this.model.document.getRoot( rootName );
@@ -283,7 +283,7 @@ export default class DataController {
 			 *
 			 * @error datacontroller-init-document-not-empty
 			 */
-			throw new CKEditorError( 'datacontroller-init-document-not-empty: Trying to set initial data to not empty document.', this );
+			throw new CKEditorError( 'datacontroller-init-document-not-empty', this );
 		}
 
 		let initialData = {};
@@ -305,7 +305,7 @@ export default class DataController {
 			 *
 			 * @error datacontroller-init-non-existent-root
 			 */
-			throw new CKEditorError( 'datacontroller-init-non-existent-root: Attempting to init data on a non-existing root.', this );
+			throw new CKEditorError( 'datacontroller-init-non-existent-root', this );
 		}
 
 		this.model.enqueueChange( 'transparent', writer => {
@@ -360,7 +360,7 @@ export default class DataController {
 			 *
 			 * @error datacontroller-set-non-existent-root
 			 */
-			throw new CKEditorError( 'datacontroller-set-non-existent-root: Attempting to set data on a non-existing root.', this );
+			throw new CKEditorError( 'datacontroller-set-non-existent-root', this );
 		}
 
 		this.model.enqueueChange( 'transparent', writer => {

+ 3 - 4
packages/ckeditor5-engine/src/conversion/conversion.js

@@ -106,8 +106,7 @@ export default class Conversion {
 			 * @error conversion-add-alias-dispatcher-not-registered
 			 */
 			throw new CKEditorError(
-				'conversion-add-alias-dispatcher-not-registered: ' +
-				'Trying to register and alias for a dispatcher that nas not been registered.',
+				'conversion-add-alias-dispatcher-not-registered',
 				this
 			);
 		}
@@ -183,7 +182,7 @@ export default class Conversion {
 			 *
 			 * @error conversion-for-unknown-group
 			 */
-			throw new CKEditorError( 'conversion-for-unknown-group: Trying to add a converter to an unknown dispatchers group.', this );
+			throw new CKEditorError( 'conversion-for-unknown-group', this );
 		}
 
 		return this._helpers.get( groupName );
@@ -588,7 +587,7 @@ export default class Conversion {
 			 *
 			 * @error conversion-group-exists
 			 */
-			throw new CKEditorError( 'conversion-group-exists: Trying to register a group name that has already been registered.', this );
+			throw new CKEditorError( 'conversion-group-exists', this );
 		}
 
 		const helpers = isDowncast ? new DowncastHelpers( dispatchers ) : new UpcastHelpers( dispatchers );

+ 6 - 0
packages/ckeditor5-engine/src/conversion/downcastdispatcher.js

@@ -75,6 +75,12 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
  * When providing custom listeners for downcast dispatcher, remember to use the provided
  * {@link module:engine/view/downcastwriter~DowncastWriter view downcast writer} to apply changes to the view document.
  *
+ * You can read more about conversion in the following guides:
+ *
+ * * {@glink framework/guides/deep-dive/conversion/conversion-introduction Advanced conversion concepts &mdash; attributes}
+ * * {@glink framework/guides/deep-dive/conversion/conversion-extending-output Extending the editor output }
+ * * {@glink framework/guides/deep-dive/conversion/custom-element-conversion Custom element conversion}
+ *
  * An example of a custom converter for the downcast dispatcher:
  *
  *		// You will convert inserting a "paragraph" model element into the model.

+ 4 - 2
packages/ckeditor5-engine/src/conversion/downcasthelpers.js

@@ -62,6 +62,9 @@ export default class DowncastHelpers extends ConversionHelpers {
 	 * See {@link module:engine/conversion/conversion~Conversion#for `conversion.for()`} to learn how to add a converter
 	 * to the conversion process.
 	 *
+	 * You can read more about element-to-element conversion in the
+	 * {@glink framework/guides/deep-dive/conversion/custom-element-conversion Custom element conversion} guide.
+	 *
 	 * @method #elementToElement
 	 * @param {Object} config Conversion configuration.
 	 * @param {String} config.model The name of the model element to convert.
@@ -1107,8 +1110,7 @@ function changeAttribute( attributeCreator ) {
 			 * @error conversion-attribute-to-attribute-on-text
 			 */
 			throw new CKEditorError(
-				'conversion-attribute-to-attribute-on-text: ' +
-				'Trying to convert text node\'s attribute with attribute-to-attribute converter.',
+				'conversion-attribute-to-attribute-on-text',
 				[ data, conversionApi ]
 			);
 		}

+ 112 - 109
packages/ckeditor5-engine/src/conversion/upcastdispatcher.js

@@ -18,24 +18,24 @@ import EmitterMixin from '@ckeditor/ckeditor5-utils/src/emittermixin';
 import mix from '@ckeditor/ckeditor5-utils/src/mix';
 
 /**
- * `UpcastDispatcher` is a central point of the view to model conversion, which is a process of
- * converting given {@link module:engine/view/documentfragment~DocumentFragment view document fragment} or
+ * Upcast dispatcher is a central point of the view-to-model conversion, which is a process of
+ * converting a given {@link module:engine/view/documentfragment~DocumentFragment view document fragment} or
  * {@link module:engine/view/element~Element view element} into a correct model structure.
  *
  * During the conversion process, the dispatcher fires events for all {@link module:engine/view/node~Node view nodes}
  * from the converted view document fragment.
- * Special callbacks called "converters" should listen to these events in order to convert these view nodes.
+ * Special callbacks called "converters" should listen to these events in order to convert the view nodes.
  *
  * The second parameter of the callback is the `data` object with the following properties:
  *
- * * `data.viewItem` contains {@link module:engine/view/node~Node view node} or
+ * * `data.viewItem` contains a {@link module:engine/view/node~Node view node} or a
  * {@link module:engine/view/documentfragment~DocumentFragment view document fragment}
  * that is converted at the moment and might be handled by the callback.
  * * `data.modelRange` is used to point to the result
  * of the current conversion (e.g. the element that is being inserted)
- * and is always a {@link module:engine/model/range~Range} when the succeeds.
+ * and is always a {@link module:engine/model/range~Range} when the conversion succeeds.
  * * `data.modelCursor` is a {@link module:engine/model/position~Position position} on which the converter should insert
- * newly created items.
+ * the newly created items.
  *
  * The third parameter of the callback is an instance of {@link module:engine/conversion/upcastdispatcher~UpcastConversionApi}
  * which provides additional tools for converters.
@@ -47,11 +47,11 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
  *
  * Examples of event-based converters:
  *
- *		// Converter for links (<a>).
+ *		// A converter for links (<a>).
  *		editor.data.upcastDispatcher.on( 'element:a', ( evt, data, conversionApi ) => {
  *			if ( conversionApi.consumable.consume( data.viewItem, { name: true, attributes: [ 'href' ] } ) ) {
- *				// <a> element is inline and is represented by an attribute in the model.
- *				// This is why we need to convert only children.
+ *				// The <a> element is inline and is represented by an attribute in the model.
+ *				// This is why you need to convert only children.
  *				const { modelRange } = conversionApi.convertChildren( data.viewItem, data.modelCursor );
  *
  *				for ( let item of modelRange.getItems() ) {
@@ -62,9 +62,9 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
  *			}
  *		} );
  *
- *		// Convert <p>'s font-size style.
+ *		// Convert <p> element's font-size style.
  *		// Note: You should use a low-priority observer in order to ensure that
- *		// it's executed after the element-to-element converter.
+ *		// it is executed after the element-to-element converter.
  *		editor.data.upcastDispatcher.on( 'element:p', ( evt, data, conversionApi ) => {
  *			const { consumable, schema, writer } = conversionApi;
  *
@@ -74,7 +74,7 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
  *
  *			const fontSize = data.viewItem.getStyle( 'font-size' );
  *
- *			// Don't go for the model element after data.modelCursor because it might happen
+ *			// Do not go for the model element after data.modelCursor because it might happen
  *			// that a single view element was converted to multiple model elements. Get all of them.
  *			for ( const item of data.modelRange.getItems( { shallow: true } ) ) {
  *				if ( schema.checkAttribute( item, 'fontSize' ) ) {
@@ -85,27 +85,27 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
  *
  *		// Convert all elements which have no custom converter into a paragraph (autoparagraphing).
  *		editor.data.upcastDispatcher.on( 'element', ( evt, data, conversionApi ) => {
- *			// Check if element can be converted.
+ *			// Check if an element can be converted.
  *			if ( !conversionApi.consumable.test( data.viewItem, { name: data.viewItem.name } ) ) {
- *				// When element is already consumed by higher priority converters then do nothing.
+ *				// When an element is already consumed by higher priority converters, do nothing.
  *				return;
  *			}
  *
  *			const paragraph = conversionApi.writer.createElement( 'paragraph' );
  *
- *			// Try to safely insert paragraph at model cursor - it will find an allowed parent for a current element.
+ *			// Try to safely insert a paragraph at the model cursor - it will find an allowed parent for the current element.
  *			if ( !conversionApi.safeInsert( paragraph, data.modelCursor ) ) {
- *				// When element was not inserted it means that we can't insert paragraph at this position.
+ *				// When an element was not inserted, it means that you cannot insert a paragraph at this position.
  *				return;
  *			}
  *
  *			// Consume the inserted element.
  *			conversionApi.consumable.consume( data.viewItem, { name: data.viewItem.name } ) );
  *
- *			// Convert children to paragraph.
+ *			// Convert the children to a paragraph.
  *			const { modelRange } = conversionApi.convertChildren( data.viewItem,  paragraph ) );
  *
- *			// Update `modelRange` and `modelCursor` in a `data` as a conversion result.
+ *			// Update `modelRange` and `modelCursor` in the `data` as a conversion result.
  *			conversionApi.updateConversionResult( paragraph, data );
  *		}, { priority: 'low' } );
  *
@@ -117,17 +117,17 @@ import mix from '@ckeditor/ckeditor5-utils/src/mix';
  */
 export default class UpcastDispatcher {
 	/**
-	 * Creates a `UpcastDispatcher` that operates using passed API.
+	 * Creates an upcast dispatcher that operates using the passed API.
 	 *
 	 * @see module:engine/conversion/upcastdispatcher~UpcastConversionApi
-	 * @param {Object} [conversionApi] Additional properties for interface that will be passed to events fired
-	 * by `UpcastDispatcher`.
+	 * @param {Object} [conversionApi] Additional properties for an interface that will be passed to events fired
+	 * by the upcast dispatcher.
 	 */
 	constructor( conversionApi = {} ) {
 		/**
-		 * List of the elements that were created during splitting.
+		 * The list of elements that were created during splitting.
 		 *
-		 * After conversion process the list is cleared.
+		 * After the conversion process the list is cleared.
 		 *
 		 * @private
 		 * @type {Map.<module:engine/model/element~Element,Array.<module:engine/model/element~Element>>}
@@ -135,9 +135,9 @@ export default class UpcastDispatcher {
 		this._splitParts = new Map();
 
 		/**
-		 * List of cursor parent elements that were created during splitting.
+		 * The list of cursor parent elements that were created during splitting.
 		 *
-		 * After conversion process the list is cleared.
+		 * After the conversion process the list is cleared.
 		 *
 		 * @private
 		 * @type {Map.<module:engine/model/element~Element,Array.<module:engine/model/element~Element>>}
@@ -145,8 +145,8 @@ export default class UpcastDispatcher {
 		this._cursorParents = new Map();
 
 		/**
-		 * Position in the temporary structure where the converted content is inserted. The structure reflect the context of
-		 * the target position where the content will be inserted. This property is build based on the context parameter of the
+		 * The position in the temporary structure where the converted content is inserted. The structure reflects the context of
+		 * the target position where the content will be inserted. This property is built based on the context parameter of the
 		 * convert method.
 		 *
 		 * @private
@@ -155,7 +155,7 @@ export default class UpcastDispatcher {
 		this._modelCursor = null;
 
 		/**
-		 * Interface passed by dispatcher to the events callbacks.
+		 * An interface passed by the dispatcher to the event callbacks.
 		 *
 		 * @member {module:engine/conversion/upcastdispatcher~UpcastConversionApi}
 		 */
@@ -179,11 +179,11 @@ export default class UpcastDispatcher {
 	 * @fires text
 	 * @fires documentFragment
 	 * @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/element~Element} viewItem
-	 * Part of the view to be converted.
-	 * @param {module:engine/model/writer~Writer} writer Instance of model writer.
+	 * The part of the view to be converted.
+	 * @param {module:engine/model/writer~Writer} writer An instance of the model writer.
 	 * @param {module:engine/model/schema~SchemaContextDefinition} [context=['$root']] Elements will be converted according to this context.
-	 * @returns {module:engine/model/documentfragment~DocumentFragment} Model data that is a result of the conversion process
-	 * wrapped in `DocumentFragment`. Converted marker elements will be set as that document fragment's
+	 * @returns {module:engine/model/documentfragment~DocumentFragment} Model data that is the result of the conversion process
+	 * wrapped in `DocumentFragment`. Converted marker elements will be set as the document fragment's
 	 * {@link module:engine/model/documentfragment~DocumentFragment#markers static markers map}.
 	 */
 	convert( viewItem, writer, context = [ '$root' ] ) {
@@ -262,7 +262,7 @@ export default class UpcastDispatcher {
 			 *
 			 * @error view-conversion-dispatcher-incorrect-result
 			 */
-			throw new CKEditorError( 'view-conversion-dispatcher-incorrect-result: Incorrect conversion result was dropped.', this );
+			throw new CKEditorError( 'view-conversion-dispatcher-incorrect-result', this );
 		}
 
 		return { modelRange: data.modelRange, modelCursor: data.modelCursor };
@@ -419,9 +419,9 @@ export default class UpcastDispatcher {
 	}
 
 	/**
-	 * Registers that `splitPart` element is a split part of the `originalPart` element.
+	 * Registers that a `splitPart` element is a split part of the `originalPart` element.
 	 *
-	 * Data set by this method is used by {@link #_getSplitParts} and {@link #_removeEmptyElements}.
+	 * The data set by this method is used by {@link #_getSplitParts} and {@link #_removeEmptyElements}.
 	 *
 	 * @private
 	 * @param {module:engine/model/element~Element} originalPart
@@ -480,36 +480,37 @@ export default class UpcastDispatcher {
 	}
 
 	/**
-	 * Fired before the first conversion event, at the beginning of upcast (view to model conversion) process.
+	 * Fired before the first conversion event, at the beginning of the upcast (view-to-model conversion) process.
 	 *
 	 * @event viewCleanup
 	 * @param {module:engine/view/documentfragment~DocumentFragment|module:engine/view/element~Element}
-	 * viewItem Part of the view to be converted.
+	 * viewItem A part of the view to be converted.
 	 */
 
 	/**
-	 * Fired when {@link module:engine/view/element~Element} is converted.
+	 * Fired when an {@link module:engine/view/element~Element} is converted.
 	 *
-	 * `element` is a namespace event for a class of events. Names of actually called events follow this pattern:
-	 * `element:<elementName>` where `elementName` is the name of converted element. This way listeners may listen to
-	 * all elements conversion or to conversion of specific elements.
+	 * `element` is a namespace event for a class of events. Names of actually called events follow the pattern of
+	 * `element:<elementName>` where `elementName` is the name of the converted element. This way listeners may listen to
+	 * a conversion of all or just specific elements.
 	 *
 	 * @event element
-	 * @param {module:engine/conversion/upcastdispatcher~UpcastConversionData} data Conversion data. Keep in mind that this object is shared
-	 * by reference between all callbacks that will be called. This means that callbacks can override values if needed, and those values
-	 * will be available in other callbacks.
-	 * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion utilities to be used by callback.
+	 * @param {module:engine/conversion/upcastdispatcher~UpcastConversionData} data The conversion data. Keep in mind that this object is
+	 * shared by reference between all callbacks that will be called. This means that callbacks can override values if needed, and these
+	 * values will be available in other callbacks.
+	 * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion utilities to be used by the
+	 * callback.
 	 */
 
 	/**
-	 * Fired when {@link module:engine/view/text~Text} is converted.
+	 * Fired when a {@link module:engine/view/text~Text} is converted.
 	 *
 	 * @event text
 	 * @see #event:element
 	 */
 
 	/**
-	 * Fired when {@link module:engine/view/documentfragment~DocumentFragment} is converted.
+	 * Fired when a {@link module:engine/view/documentfragment~DocumentFragment} is converted.
 	 *
 	 * @event documentFragment
 	 * @see #event:element
@@ -582,54 +583,55 @@ function createContextTree( contextDefinition, writer ) {
 }
 
 /**
- * A set of conversion utils available as the third parameter of
+ * A set of conversion utilities available as the third parameter of the
  * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher upcast dispatcher}'s events.
  *
  * @interface module:engine/conversion/upcastdispatcher~UpcastConversionApi
  */
 
 /**
- * Starts conversion of given item by firing an appropriate event.
+ * Starts the conversion of a given item by firing an appropriate event.
  *
- * Every fired event is passed (as first parameter) an object with `modelRange` property. Every event may set and/or
- * modify that property. When all callbacks are done, the final value of `modelRange` property is returned by this method.
- * The `modelRange` must be {@link module:engine/model/range~Range model range} or `null` (as set by default).
+ * Every fired event is passed (as the first parameter) an object with the `modelRange` property. Every event may set and/or
+ * modify that property. When all callbacks are done, the final value of the `modelRange` property is returned by this method.
+ * The `modelRange` must be a {@link module:engine/model/range~Range model range} or `null` (as set by default).
  *
  * @method #convertItem
  * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element
  * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:text
  * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:documentFragment
  * @param {module:engine/view/item~Item} viewItem Item to convert.
- * @param {module:engine/model/position~Position} modelCursor Position of conversion.
- * @returns {Object} result Conversion result.
- * @returns {module:engine/model/range~Range|null} result.modelRange Model range containing result of item conversion,
- * created and modified by callbacks attached to fired event, or `null` if the conversion result was incorrect.
- * @returns {module:engine/model/position~Position} result.modelCursor Position where conversion should be continued.
+ * @param {module:engine/model/position~Position} modelCursor The conversion position.
+ * @returns {Object} result The conversion result.
+ * @returns {module:engine/model/range~Range|null} result.modelRange The model range containing the result of the item conversion,
+ * created and modified by callbacks attached to the fired event, or `null` if the conversion result was incorrect.
+ * @returns {module:engine/model/position~Position} result.modelCursor The position where the conversion should be continued.
  */
 
 /**
- * Starts conversion of all children of given item by firing appropriate events for all those children.
+ * Starts the conversion of all children of a given item by firing appropriate events for all the children.
  *
  * @method #convertChildren
  * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element
  * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:text
  * @fires module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:documentFragment
- * @param {module:engine/view/item~Item} viewItem Element which children should be converted.
- * @param {module:engine/model/position~Position|module:engine/model/element~Element} positionOrElement Position or element of conversion.
- * @returns {Object} result Conversion result.
- * @returns {module:engine/model/range~Range} result.modelRange Model range containing results of conversion of all children of given item.
- * When no children was converted then range is collapsed.
- * @returns {module:engine/model/position~Position} result.modelCursor Position where conversion should be continued.
+ * @param {module:engine/view/item~Item} viewItem An element whose children should be converted.
+ * @param {module:engine/model/position~Position|module:engine/model/element~Element} positionOrElement A position or an element of
+ * the conversion.
+ * @returns {Object} result The conversion result.
+ * @returns {module:engine/model/range~Range} result.modelRange The model range containing the results of the conversion of all children
+ * of the given item. When no child was converted, the range is collapsed.
+ * @returns {module:engine/model/position~Position} result.modelCursor The position where the conversion should be continued.
  */
 
 /**
- * Safely inserts an element to the document checking {@link module:engine/model/schema~Schema schema} to find allowed parent for
- * an element that we are going to insert starting from given position. If current parent does not allow to insert element
- * but one of the ancestors does then split nodes to allowed parent.
+ * Safely inserts an element to the document, checking the {@link module:engine/model/schema~Schema schema} to find an allowed parent for
+ * an element that you are going to insert, starting from the given position. If the current parent does not allow to insert the element
+ * but one of the ancestors does, then splits the nodes to allowed parent.
  *
- * If schema allows to insert node in given position, nothing is split.
+ * If the schema allows to insert the node in a given position, nothing is split.
  *
- * If it was not possible to find allowed parent, `false` is returned, nothing is split.
+ * If it was not possible to find an allowed parent, `false` is returned and nothing is split.
  *
  * Otherwise, ancestors are split.
  *
@@ -649,22 +651,22 @@ function createContextTree( contextDefinition, writer ) {
  *			return;
  *		}
  *
- * The split result is saved and {@link #updateConversionResult} should be used to update
+ * The split result is saved and {@link #updateConversionResult} should be used to update the
  * {@link module:engine/conversion/upcastdispatcher~UpcastConversionData conversion data}.
  *
  * @method #safeInsert
- * @param {module:engine/model/node~Node} node Node to insert.
- * @param {module:engine/model/position~Position} position Position on which element is going to be inserted.
- * @returns {Boolean} Split result. If it was not possible to find allowed position `false` is returned.
+ * @param {module:engine/model/node~Node} node The node to insert.
+ * @param {module:engine/model/position~Position} position The position where an element is going to be inserted.
+ * @returns {Boolean} The split result. If it was not possible to find an allowed position, `false` is returned.
  */
 
 /**
- * Updates the conversion result and sets proper {@link module:engine/conversion/upcastdispatcher~UpcastConversionData#modelRange} and
- * next {@link module:engine/conversion/upcastdispatcher~UpcastConversionData#modelCursor} after the conversion.
- * Used together with {@link #safeInsert} enables you to easily convert elements without worrying if the node was split
- * during its children conversion.
+ * Updates the conversion result and sets a proper {@link module:engine/conversion/upcastdispatcher~UpcastConversionData#modelRange} and
+ * the next {@link module:engine/conversion/upcastdispatcher~UpcastConversionData#modelCursor} after the conversion.
+ * Used together with {@link #safeInsert}, it enables you to easily convert elements without worrying if the node was split
+ * during the conversion of its children.
  *
- * Example of a usage in a converter code:
+ * A usage example in converter code:
  *
  *		const myElement = conversionApi.writer.createElement( 'myElement' );
  *
@@ -680,19 +682,19 @@ function createContextTree( contextDefinition, writer ) {
  * @method #updateConversionResult
  * @param {module:engine/model/element~Element} element
  * @param {module:engine/conversion/upcastdispatcher~UpcastConversionData} data Conversion data.
- * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion utilities to be used by callback.
+ * @param {module:engine/conversion/upcastdispatcher~UpcastConversionApi} conversionApi Conversion utilities to be used by the callback.
  */
 
 /**
- * Checks {@link module:engine/model/schema~Schema schema} to find allowed parent for element that we are going to insert
- * starting from given position. If current parent does not allow to insert element but one of the ancestors does then
- * split nodes to allowed parent.
+ * Checks the {@link module:engine/model/schema~Schema schema} to find an allowed parent for an element that is going to be inserted
+ * starting from the given position. If the current parent does not allow inserting an element but one of the ancestors does, the method
+ * splits nodes to allowed parent.
  *
- * If schema allows to insert node in given position, nothing is split and object with that position is returned.
+ * If the schema allows inserting the node in the given position, nothing is split and an object with that position is returned.
  *
- * If it was not possible to find allowed parent, `null` is returned, nothing is split.
+ * If it was not possible to find an allowed parent, `null` is returned and nothing is split.
  *
- * Otherwise, ancestors are split and object with position and the copy of the split element is returned.
+ * Otherwise, ancestors are split and an object with a position and the copy of the split element is returned.
  *
  * For instance, if `<image>` is not allowed in `<paragraph>` but is allowed in `$root`:
  *
@@ -702,23 +704,23 @@ function createContextTree( contextDefinition, writer ) {
  *
  *		<paragraph>foo</paragraph>[]<paragraph>bar</paragraph>
  *
- * In the sample above position between `<paragraph>` elements will be returned as `position` and the second `paragraph`
+ * In the example above, the position between `<paragraph>` elements will be returned as `position` and the second `paragraph`
  * as `cursorParent`.
  *
  * **Note:** This is an advanced method. For most cases {@link #safeInsert} and {@link #updateConversionResult} should be used.
  *
  * @method #splitToAllowedParent
- * @param {module:engine/model/position~Position} position Position on which element is going to be inserted.
- * @param {module:engine/model/node~Node} node Node to insert.
- * @returns {Object|null} Split result. If it was not possible to find allowed position `null` is returned.
- * @returns {module:engine/model/position~Position} position between split elements.
- * @returns {module:engine/model/element~Element} [cursorParent] Element inside which cursor should be placed to
- * continue conversion. When element is not defined it means that there was no split.
+ * @param {module:engine/model/position~Position} position The position where the element is going to be inserted.
+ * @param {module:engine/model/node~Node} node The node to insert.
+ * @returns {Object|null} The split result. If it was not possible to find an allowed position, `null` is returned.
+ * @returns {module:engine/model/position~Position} The position between split elements.
+ * @returns {module:engine/model/element~Element} [cursorParent] The element inside which the cursor should be placed to
+ * continue the conversion. When the element is not defined it means that there was no split.
  */
 
 /**
- * Returns all the split parts of given `element` that were created during upcasting through using {@link #splitToAllowedParent}.
- * It enables you to easily track those elements and continue processing them after they are split during their children conversion.
+ * Returns all the split parts of the given `element` that were created during upcasting through using {@link #splitToAllowedParent}.
+ * It enables you to easily track these elements and continue processing them after they are split during the conversion of their children.
  *
  *		<paragraph>Foo<image />bar<image />baz</paragraph> ->
  *		<paragraph>Foo</paragraph><image /><paragraph>bar</paragraph><image /><paragraph>baz</paragraph>
@@ -726,9 +728,9 @@ function createContextTree( contextDefinition, writer ) {
  * For a reference to any of above paragraphs, the function will return all three paragraphs (the original element included),
  * sorted in the order of their creation (the original element is the first one).
  *
- * If given `element` was not split, an array with single element is returned.
+ * If the given `element` was not split, an array with a single element is returned.
  *
- * Example of a usage in a converter code:
+ * A usage example in the converter code:
  *
  *		const myElement = conversionApi.writer.createElement( 'myElement' );
  *
@@ -747,9 +749,9 @@ function createContextTree( contextDefinition, writer ) {
  *		// Setting `data.modelCursor` to continue after the last split element:
  *		data.modelCursor = conversionApi.writer.createPositionAfter( lastSplitPart );
  *
- * **Tip:** if you are unable to get a reference to the original element (for example because the code is split into multiple converters
- * or even classes) but it was already converted, you might want to check first element in `data.modelRange`. This is a common situation
- * if an attribute converter is separated from an element converter.
+ * **Tip:** If you are unable to get a reference to the original element (for example because the code is split into multiple converters
+ * or even classes) but it has already been converted, you may want to check the first element in `data.modelRange`. This is a common
+ * situation if an attribute converter is separated from an element converter.
  *
  * **Note:** This is an advanced method. For most cases {@link #safeInsert} and {@link #updateConversionResult} should be used.
  *
@@ -759,18 +761,19 @@ function createContextTree( contextDefinition, writer ) {
  */
 
 /**
- * Stores information about what parts of processed view item are still waiting to be handled. After a piece of view item
- * was converted, appropriate consumable value should be {@link module:engine/conversion/viewconsumable~ViewConsumable#consume consumed}.
+ * Stores information about what parts of the processed view item are still waiting to be handled. After a piece of view item
+ * was converted, an appropriate consumable value should be
+ * {@link module:engine/conversion/viewconsumable~ViewConsumable#consume consumed}.
  *
  * @member {module:engine/conversion/viewconsumable~ViewConsumable} #consumable
  */
 
 /**
- * Custom data stored by converters for conversion process. Custom properties of this object can be defined and use to
+ * Custom data stored by converters for the conversion process. Custom properties of this object can be defined and use to
  * pass parameters between converters.
  *
- * The difference between this property and `data` parameter of
- * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element} is that `data` parameters allows you
+ * The difference between this property and the `data` parameter of
+ * {@link module:engine/conversion/upcastdispatcher~UpcastDispatcher#event:element} is that the `data` parameters allow you
  * to pass parameters within a single event and `store` within the whole conversion.
  *
  * @member {Object} #store
@@ -783,7 +786,7 @@ function createContextTree( contextDefinition, writer ) {
  */
 
 /**
- * The {@link module:engine/model/writer~Writer} instance used to manipulate data during conversion.
+ * The {@link module:engine/model/writer~Writer} instance used to manipulate the data during conversion.
  *
  * @member {module:engine/model/writer~Writer} #writer
  */
@@ -792,13 +795,13 @@ function createContextTree( contextDefinition, writer ) {
  * Conversion data.
  *
  * **Note:** Keep in mind that this object is shared by reference between all conversion callbacks that will be called.
- * This means that callbacks can override values if needed, and those values will be available in other callbacks.
+ * This means that callbacks can override values if needed, and these values will be available in other callbacks.
  *
  * @typedef {Object} module:engine/conversion/upcastdispatcher~UpcastConversionData
  *
- * @property {module:engine/view/item~Item} viewItem Converted item.
- * @property {module:engine/model/position~Position} modelCursor Position where a converter should start changes.
+ * @property {module:engine/view/item~Item} viewItem The converted item.
+ * @property {module:engine/model/position~Position} modelCursor The position where the converter should start changes.
  * Change this value for the next converter to tell where the conversion should continue.
  * @property {module:engine/model/range~Range} [modelRange] The current state of conversion result. Every change to
- * converted element should be reflected by setting or modifying this property.
+ * the converted element should be reflected by setting or modifying this property.
  */

+ 1 - 1
packages/ckeditor5-engine/src/conversion/viewconsumable.js

@@ -513,7 +513,7 @@ class ViewElementConsumables {
 				 *
 				 * @error viewconsumable-invalid-attribute
 				 */
-				throw new CKEditorError( 'viewconsumable-invalid-attribute: Classes and styles should be handled separately.', this );
+				throw new CKEditorError( 'viewconsumable-invalid-attribute', this );
 			}
 
 			consumables.set( name, true );

+ 5 - 13
packages/ckeditor5-engine/src/model/document.js

@@ -57,7 +57,7 @@ export default class Document {
 		 * operations are applied on a proper document version.
 		 *
 		 * If the {@link module:engine/model/operation/operation~Operation#baseVersion base version} does not match the document version,
-		 * a {@link module:utils/ckeditorerror~CKEditorError model-document-applyOperation-wrong-version} error is thrown.
+		 * a {@link module:utils/ckeditorerror~CKEditorError model-document-applyoperation-wrong-version} error is thrown.
 		 *
 		 * @type {Number}
 		 */
@@ -123,14 +123,10 @@ export default class Document {
 				/**
 				 * Only operations with matching versions can be applied.
 				 *
-				 * @error document-applyOperation-wrong-version
+				 * @error model-document-applyoperation-wrong-version
 				 * @param {module:engine/model/operation/operation~Operation} operation
 				 */
-				throw new CKEditorError(
-					'model-document-applyOperation-wrong-version: Only operations with matching versions can be applied.',
-					this,
-					{ operation }
-				);
+				throw new CKEditorError( 'model-document-applyoperation-wrong-version', this, { operation } );
 			}
 		}, { priority: 'highest' } );
 
@@ -197,15 +193,11 @@ export default class Document {
 			/**
 			 * A root with the specified name already exists.
 			 *
-			 * @error model-document-createRoot-name-exists
+			 * @error model-document-createroot-name-exists
 			 * @param {module:engine/model/document~Document} doc
 			 * @param {String} name
 			 */
-			throw new CKEditorError(
-				'model-document-createRoot-name-exists: Root with specified name already exists.',
-				this,
-				{ name: rootName }
-			);
+			throw new CKEditorError( 'model-document-createroot-name-exists', this, { name: rootName } );
 		}
 
 		const root = new RootElement( this, elementName, rootName );

+ 2 - 2
packages/ckeditor5-engine/src/model/documentselection.js

@@ -653,7 +653,7 @@ class LiveSelection extends Selection {
 					 * @param {module:engine/model/range~Range} range
 					 */
 					throw new CKEditorError(
-						'document-selection-wrong-position: Range from document selection starts or ends at incorrect position.',
+						'document-selection-wrong-position',
 						this,
 						{ range }
 					);
@@ -784,7 +784,7 @@ class LiveSelection extends Selection {
 			 * {@link module:engine/model/documentselection~DocumentSelection#_overrideGravity}.
 			 */
 			throw new CKEditorError(
-				'document-selection-gravity-wrong-restore: Attempting to restore the selection gravity for an unknown UID.',
+				'document-selection-gravity-wrong-restore',
 				this,
 				{ uid }
 			);

+ 2 - 5
packages/ckeditor5-engine/src/model/liveposition.js

@@ -43,12 +43,9 @@ export default class LivePosition extends Position {
 			/**
 			 * LivePosition's root has to be an instance of RootElement.
 			 *
-			 * @error liveposition-root-not-rootelement
+			 * @error model-liveposition-root-not-rootelement
 			 */
-			throw new CKEditorError(
-				'model-liveposition-root-not-rootelement: LivePosition\'s root has to be an instance of RootElement.',
-				root
-			);
+			throw new CKEditorError( 'model-liveposition-root-not-rootelement', root );
 		}
 
 		bindWithDocument.call( this );

+ 12 - 7
packages/ckeditor5-engine/src/model/markercollection.js

@@ -99,7 +99,7 @@ export default class MarkerCollection {
 			 *
 			 * @error markercollection-incorrect-marker-name
 			 */
-			throw new CKEditorError( 'markercollection-incorrect-marker-name: Marker name cannot contain the "," character.', this );
+			throw new CKEditorError( 'markercollection-incorrect-marker-name', this );
 		}
 
 		const oldMarker = this._markers.get( markerName );
@@ -177,7 +177,12 @@ export default class MarkerCollection {
 		const marker = this._markers.get( markerName );
 
 		if ( !marker ) {
-			throw new CKEditorError( 'markercollection-refresh-marker-not-exists: Marker with provided name does not exists.', this );
+			/**
+			 * Marker with provided name does not exists.
+			 *
+			 * @error markercollection-refresh-marker-not-exists
+			 */
+			throw new CKEditorError( 'markercollection-refresh-marker-not-exists', this );
 		}
 
 		const range = marker.getRange();
@@ -393,7 +398,7 @@ class Marker {
 	 */
 	get managedUsingOperations() {
 		if ( !this._liveRange ) {
-			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );
+			throw new CKEditorError( 'marker-destroyed', this );
 		}
 
 		return this._managedUsingOperations;
@@ -406,7 +411,7 @@ class Marker {
 	 */
 	get affectsData() {
 		if ( !this._liveRange ) {
-			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );
+			throw new CKEditorError( 'marker-destroyed', this );
 		}
 
 		return this._affectsData;
@@ -419,7 +424,7 @@ class Marker {
 	 */
 	getStart() {
 		if ( !this._liveRange ) {
-			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );
+			throw new CKEditorError( 'marker-destroyed', this );
 		}
 
 		return this._liveRange.start.clone();
@@ -432,7 +437,7 @@ class Marker {
 	 */
 	getEnd() {
 		if ( !this._liveRange ) {
-			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );
+			throw new CKEditorError( 'marker-destroyed', this );
 		}
 
 		return this._liveRange.end.clone();
@@ -452,7 +457,7 @@ class Marker {
 	 */
 	getRange() {
 		if ( !this._liveRange ) {
-			throw new CKEditorError( 'marker-destroyed: Cannot use a destroyed marker instance.', this );
+			throw new CKEditorError( 'marker-destroyed', this );
 		}
 
 		return this._liveRange.toRange();

+ 8 - 2
packages/ckeditor5-engine/src/model/node.js

@@ -87,7 +87,7 @@ export default class Node {
 		}
 
 		if ( ( pos = this.parent.getChildIndex( this ) ) === null ) {
-			throw new CKEditorError( 'model-node-not-found-in-parent: The node\'s parent does not contain this node.', this );
+			throw new CKEditorError( 'model-node-not-found-in-parent', this );
 		}
 
 		return pos;
@@ -111,7 +111,7 @@ export default class Node {
 		}
 
 		if ( ( pos = this.parent.getChildStartOffset( this ) ) === null ) {
-			throw new CKEditorError( 'model-node-not-found-in-parent: The node\'s parent does not contain this node.', this );
+			throw new CKEditorError( 'model-node-not-found-in-parent', this );
 		}
 
 		return pos;
@@ -499,3 +499,9 @@ export default class Node {
 		this._attrs.clear();
 	}
 }
+
+/**
+ * The node's parent does not contain this node.
+ *
+ * @error model-node-not-found-in-parent
+ */

+ 5 - 8
packages/ckeditor5-engine/src/model/nodelist.js

@@ -122,9 +122,9 @@ export default class NodeList {
 			/**
 			 * Given index cannot be found in the node list.
 			 *
-			 * @error nodelist-index-out-of-bounds
+			 * @error model-nodelist-index-out-of-bounds
 			 */
-			throw new CKEditorError( 'model-nodelist-index-out-of-bounds: Given index cannot be found in the node list.', this );
+			throw new CKEditorError( 'model-nodelist-index-out-of-bounds', this );
 		}
 
 		return this.getNodeStartOffset( node );
@@ -158,7 +158,7 @@ export default class NodeList {
 			 * @param {Number} offset
 			 * @param {module:engine/model/nodelist~NodeList} nodeList Stringified node list.
 			 */
-			throw new CKEditorError( 'model-nodelist-offset-out-of-bounds: Given offset cannot be found in the node list.',
+			throw new CKEditorError( 'model-nodelist-offset-out-of-bounds',
 				this,
 				{
 					offset,
@@ -184,12 +184,9 @@ export default class NodeList {
 				/**
 				 * Trying to insert an object which is not a Node instance.
 				 *
-				 * @error nodelist-insertNodes-not-node
+				 * @error model-nodelist-insertnodes-not-node
 				 */
-				throw new CKEditorError(
-					'model-nodelist-insertNodes-not-node: Trying to insert an object which is not a Node instance.',
-					this
-				);
+				throw new CKEditorError( 'model-nodelist-insertnodes-not-node', this );
 			}
 		}
 

+ 3 - 4
packages/ckeditor5-engine/src/model/operation/attributeoperation.js

@@ -128,7 +128,7 @@ export default class AttributeOperation extends Operation {
 			 *
 			 * @error attribute-operation-range-not-flat
 			 */
-			throw new CKEditorError( 'attribute-operation-range-not-flat: The range to change is not flat.', this );
+			throw new CKEditorError( 'attribute-operation-range-not-flat', this );
 		}
 
 		for ( const item of this.range.getItems( { shallow: true } ) ) {
@@ -142,8 +142,7 @@ export default class AttributeOperation extends Operation {
 				 * @param {*} value
 				 */
 				throw new CKEditorError(
-					'attribute-operation-wrong-old-value: Changed node has different attribute value than operation\'s ' +
-					'old attribute value.',
+					'attribute-operation-wrong-old-value',
 					this,
 					{ item, key: this.key, value: this.oldValue }
 				);
@@ -158,7 +157,7 @@ export default class AttributeOperation extends Operation {
 				 * @param {String} key
 				 */
 				throw new CKEditorError(
-					'attribute-operation-attribute-exists: The attribute with given key already exists.',
+					'attribute-operation-attribute-exists',
 					this,
 					{ node: item, key: this.key }
 				);

+ 1 - 1
packages/ckeditor5-engine/src/model/operation/detachoperation.js

@@ -75,7 +75,7 @@ export default class DetachOperation extends Operation {
 			 *
 			 * @error detach-operation-on-document-node
 			 */
-			throw new CKEditorError( 'detach-operation-on-document-node: Cannot detach document node.', this );
+			throw new CKEditorError( 'detach-operation-on-document-node', this );
 		}
 	}
 

+ 1 - 1
packages/ckeditor5-engine/src/model/operation/insertoperation.js

@@ -115,7 +115,7 @@ export default class InsertOperation extends Operation {
 			 * @error insert-operation-position-invalid
 			 */
 			throw new CKEditorError(
-				'insert-operation-position-invalid: Insertion position is invalid.',
+				'insert-operation-position-invalid',
 				this
 			);
 		}

+ 3 - 3
packages/ckeditor5-engine/src/model/operation/mergeoperation.js

@@ -147,21 +147,21 @@ export default class MergeOperation extends Operation {
 			 *
 			 * @error merge-operation-source-position-invalid
 			 */
-			throw new CKEditorError( 'merge-operation-source-position-invalid: Merge source position is invalid.', this );
+			throw new CKEditorError( 'merge-operation-source-position-invalid', this );
 		} else if ( !targetElement.parent ) {
 			/**
 			 * Merge target position is invalid. The element to be merged must have a parent node.
 			 *
 			 * @error merge-operation-target-position-invalid
 			 */
-			throw new CKEditorError( 'merge-operation-target-position-invalid: Merge target position is invalid.', this );
+			throw new CKEditorError( 'merge-operation-target-position-invalid', this );
 		} else if ( this.howMany != sourceElement.maxOffset ) {
 			/**
 			 * Merge operation specifies wrong number of nodes to move.
 			 *
 			 * @error merge-operation-how-many-invalid
 			 */
-			throw new CKEditorError( 'merge-operation-how-many-invalid: Merge operation specifies wrong number of nodes to move.', this );
+			throw new CKEditorError( 'merge-operation-how-many-invalid', this );
 		}
 	}
 

+ 3 - 3
packages/ckeditor5-engine/src/model/operation/moveoperation.js

@@ -132,7 +132,7 @@ export default class MoveOperation extends Operation {
 			 * @error move-operation-nodes-do-not-exist
 			 */
 			throw new CKEditorError(
-				'move-operation-nodes-do-not-exist: The nodes which should be moved do not exist.', this
+				'move-operation-nodes-do-not-exist', this
 			);
 		} else if ( sourceElement === targetElement && sourceOffset < targetOffset && targetOffset < sourceOffset + this.howMany ) {
 			/**
@@ -141,7 +141,7 @@ export default class MoveOperation extends Operation {
 			 * @error move-operation-range-into-itself
 			 */
 			throw new CKEditorError(
-				'move-operation-range-into-itself: Trying to move a range of nodes to the inside of that range.', this
+				'move-operation-range-into-itself', this
 			);
 		} else if ( this.sourcePosition.root == this.targetPosition.root ) {
 			if ( compareArrays( this.sourcePosition.getParentPath(), this.targetPosition.getParentPath() ) == 'prefix' ) {
@@ -154,7 +154,7 @@ export default class MoveOperation extends Operation {
 					 * @error move-operation-node-into-itself
 					 */
 					throw new CKEditorError(
-						'move-operation-node-into-itself: Trying to move a range of nodes into one of nodes from that range.', this
+						'move-operation-node-into-itself', this
 					);
 				}
 			}

+ 2 - 2
packages/ckeditor5-engine/src/model/operation/renameoperation.js

@@ -94,7 +94,7 @@ export default class RenameOperation extends Operation {
 			 * @error rename-operation-wrong-position
 			 */
 			throw new CKEditorError(
-				'rename-operation-wrong-position: Given position is invalid or node after it is not an instance of Element.',
+				'rename-operation-wrong-position',
 				this
 			);
 		} else if ( element.name !== this.oldName ) {
@@ -104,7 +104,7 @@ export default class RenameOperation extends Operation {
 			 * @error rename-operation-wrong-name
 			 */
 			throw new CKEditorError(
-				'rename-operation-wrong-name: Element to change has different name than operation\'s old name.',
+				'rename-operation-wrong-name',
 				this
 			);
 		}

+ 5 - 10
packages/ckeditor5-engine/src/model/operation/rootattributeoperation.js

@@ -115,7 +115,7 @@ export default class RootAttributeOperation extends Operation {
 			 * @param {*} value
 			 */
 			throw new CKEditorError(
-				'rootattribute-operation-not-a-root: The element to change is not a root element.',
+				'rootattribute-operation-not-a-root',
 				this,
 				{ root: this.root, key: this.key }
 			);
@@ -131,8 +131,7 @@ export default class RootAttributeOperation extends Operation {
 			 * @param {*} value
 			 */
 			throw new CKEditorError(
-				'rootattribute-operation-wrong-old-value: Changed node has different attribute value than operation\'s ' +
-				'old attribute value.',
+				'rootattribute-operation-wrong-old-value',
 				this,
 				{ root: this.root, key: this.key }
 			);
@@ -147,7 +146,7 @@ export default class RootAttributeOperation extends Operation {
 			 * @param {String} key
 			 */
 			throw new CKEditorError(
-				'rootattribute-operation-attribute-exists: The attribute with given key already exists.',
+				'rootattribute-operation-attribute-exists',
 				this,
 				{ root: this.root, key: this.key }
 			);
@@ -195,14 +194,10 @@ export default class RootAttributeOperation extends Operation {
 			/**
 			 * Cannot create RootAttributeOperation for document. Root with specified name does not exist.
 			 *
-			 * @error rootattributeoperation-fromjson-no-root
+			 * @error rootattribute-operation-fromjson-no-root
 			 * @param {String} rootName
 			 */
-			throw new CKEditorError(
-				'rootattribute-operation-fromjson-no-root: Cannot create RootAttributeOperation. Root with specified name does not exist.',
-				this,
-				{ rootName: json.root }
-			);
+			throw new CKEditorError( 'rootattribute-operation-fromjson-no-root', this, { rootName: json.root } );
 		}
 
 		return new RootAttributeOperation( document.getRoot( json.root ), json.key, json.oldValue, json.newValue, json.baseVersion );

+ 4 - 4
packages/ckeditor5-engine/src/model/operation/splitoperation.js

@@ -149,28 +149,28 @@ export default class SplitOperation extends Operation {
 			 *
 			 * @error split-operation-position-invalid
 			 */
-			throw new CKEditorError( 'split-operation-position-invalid: Split position is invalid.', this );
+			throw new CKEditorError( 'split-operation-position-invalid', this );
 		} else if ( !element.parent ) {
 			/**
 			 * Cannot split root element.
 			 *
 			 * @error split-operation-split-in-root
 			 */
-			throw new CKEditorError( 'split-operation-split-in-root: Cannot split root element.', this );
+			throw new CKEditorError( 'split-operation-split-in-root', this );
 		} else if ( this.howMany != element.maxOffset - this.splitPosition.offset ) {
 			/**
 			 * Split operation specifies wrong number of nodes to move.
 			 *
 			 * @error split-operation-how-many-invalid
 			 */
-			throw new CKEditorError( 'split-operation-how-many-invalid: Split operation specifies wrong number of nodes to move.', this );
+			throw new CKEditorError( 'split-operation-how-many-invalid', this );
 		} else if ( this.graveyardPosition && !this.graveyardPosition.nodeAfter ) {
 			/**
 			 * Graveyard position invalid.
 			 *
 			 * @error split-operation-graveyard-position-invalid
 			 */
-			throw new CKEditorError( 'split-operation-graveyard-position-invalid: Graveyard position invalid.', this );
+			throw new CKEditorError( 'split-operation-graveyard-position-invalid', this );
 		}
 	}
 

+ 2 - 4
packages/ckeditor5-engine/src/model/operation/utils.js

@@ -70,8 +70,7 @@ export function _remove( range ) {
 		 * @error operation-utils-remove-range-not-flat
 		 */
 		throw new CKEditorError(
-			'operation-utils-remove-range-not-flat: ' +
-			'Trying to remove a range which starts and ends in different element.',
+			'operation-utils-remove-range-not-flat',
 			this
 		);
 	}
@@ -109,8 +108,7 @@ export function _move( sourceRange, targetPosition ) {
 		 * @error operation-utils-move-range-not-flat
 		 */
 		throw new CKEditorError(
-			'operation-utils-move-range-not-flat: ' +
-			'Trying to move a range which starts and ends in different element.',
+			'operation-utils-move-range-not-flat',
 			this
 		);
 	}

+ 25 - 29
packages/ckeditor5-engine/src/model/position.js

@@ -60,7 +60,7 @@ export default class Position {
 			 * @error model-position-root-invalid
 			 */
 			throw new CKEditorError(
-				'model-position-root-invalid: Position root invalid.',
+				'model-position-root-invalid',
 				root
 			);
 		}
@@ -73,7 +73,7 @@ export default class Position {
 			 * @param path
 			 */
 			throw new CKEditorError(
-				'model-position-path-incorrect-format: Position path must be an array with at least one item.',
+				'model-position-path-incorrect-format',
 				root,
 				{ path }
 			);
@@ -169,27 +169,27 @@ export default class Position {
 			parent = parent.getChild( parent.offsetToIndex( this.path[ i ] ) );
 
 			if ( !parent ) {
-				throw new CKEditorError( 'model-position-path-incorrect: The position\'s path is incorrect.', this, { position: this } );
+				/**
+				 * The position's path is incorrect. This means that a position does not point to
+				 * a correct place in the tree and hence, some of its methods and getters cannot work correctly.
+				 *
+				 * **Note**: Unlike DOM and view positions, in the model, the
+				 * {@link module:engine/model/position~Position#parent position's parent} is always an element or a document fragment.
+				 * The last offset in the {@link module:engine/model/position~Position#path position's path} is the point in this element
+				 * where this position points.
+				 *
+				 * Read more about model positions and offsets in
+				 * the {@glink framework/guides/architecture/editing-engine#indexes-and-offsets Editing engine architecture guide}.
+				 *
+				 * @error model-position-path-incorrect
+				 * @param {module:engine/model/position~Position} position The incorrect position.
+				 */
+				throw new CKEditorError( 'model-position-path-incorrect', this, { position: this } );
 			}
 		}
 
 		if ( parent.is( '$text' ) ) {
-			/**
-			 * The position's path is incorrect. This means that a position does not point to
-			 * a correct place in the tree and hence, some of its methods and getters cannot work correctly.
-			 *
-			 * **Note**: Unlike DOM and view positions, in the model, the
-			 * {@link module:engine/model/position~Position#parent position's parent} is always an element or a document fragment.
-			 * The last offset in the {@link module:engine/model/position~Position#path position's path} is the point in this element where
-			 * this position points.
-			 *
-			 * Read more about model positions and offsets in
-			 * the {@glink framework/guides/architecture/editing-engine#indexes-and-offsets Editing engine architecture guide}.
-			 *
-			 * @error position-incorrect-path
-			 * @param {module:engine/model/position~Position} position The incorrect position.
-			 */
-			throw new CKEditorError( 'model-position-path-incorrect: The position\'s path is incorrect.', this, { position: this } );
+			throw new CKEditorError( 'model-position-path-incorrect', this, { position: this } );
 		}
 
 		return parent;
@@ -923,13 +923,9 @@ export default class Position {
 				 * {@link module:engine/model/model~Model#createPositionAt `Model#createPositionAt()`}
 				 * requires the offset to be specified when the first parameter is a model item.
 				 *
-				 * @error model-createPositionAt-offset-required
+				 * @error model-createpositionat-offset-required
 				 */
-				throw new CKEditorError(
-					'model-createPositionAt-offset-required: ' +
-					'Model#createPositionAt() requires the offset when the first parameter is a model item.',
-					[ this, itemOrPosition ]
-				);
+				throw new CKEditorError( 'model-createpositionat-offset-required', [ this, itemOrPosition ] );
 			}
 
 			if ( !node.is( 'element' ) && !node.is( 'documentFragment' ) ) {
@@ -939,7 +935,7 @@ export default class Position {
 				 * @error model-position-parent-incorrect
 				 */
 				throw new CKEditorError(
-					'model-position-parent-incorrect: Position parent have to be a element or document fragment.',
+					'model-position-parent-incorrect',
 					[ this, itemOrPosition ]
 				);
 			}
@@ -969,7 +965,7 @@ export default class Position {
 			 * @param {module:engine/model/item~Item} root
 			 */
 			throw new CKEditorError(
-				'model-position-after-root: You cannot make a position after root.',
+				'model-position-after-root',
 				[ this, item ],
 				{ root: item }
 			);
@@ -995,7 +991,7 @@ export default class Position {
 			 * @param {module:engine/model/item~Item} root
 			 */
 			throw new CKEditorError(
-				'model-position-before-root: You cannot make a position before root.',
+				'model-position-before-root',
 				item,
 				{ root: item }
 			);
@@ -1027,7 +1023,7 @@ export default class Position {
 			 * @param {String} rootName
 			 */
 			throw new CKEditorError(
-				'model-position-fromjson-no-root: Cannot create position for document. Root with specified name does not exist.',
+				'model-position-fromjson-no-root',
 				doc,
 				{ rootName: json.root }
 			);

+ 1 - 1
packages/ckeditor5-engine/src/model/range.js

@@ -974,7 +974,7 @@ export default class Range {
 			 * @error range-create-from-ranges-empty-array
 			 */
 			throw new CKEditorError(
-				'range-create-from-ranges-empty-array: At least one range has to be passed.',
+				'range-create-from-ranges-empty-array',
 				null
 			);
 		} else if ( ranges.length == 1 ) {

+ 5 - 5
packages/ckeditor5-engine/src/model/schema.js

@@ -92,7 +92,7 @@ export default class Schema {
 			 * @error schema-cannot-register-item-twice
 			 */
 			throw new CKEditorError(
-				'schema-cannot-register-item-twice: A single item cannot be registered twice in the schema.',
+				'schema-cannot-register-item-twice',
 				this,
 				{
 					itemName
@@ -142,7 +142,7 @@ export default class Schema {
 			 * @param itemName The name of the model element which is being extended.
 			 * @error schema-cannot-extend-missing-item
 			 */
-			throw new CKEditorError( 'schema-cannot-extend-missing-item: Cannot extend an item which was not registered yet.', this, {
+			throw new CKEditorError( 'schema-cannot-extend-missing-item', this, {
 				itemName
 			} );
 		}
@@ -447,7 +447,7 @@ export default class Schema {
 				 * @error schema-check-merge-no-element-before
 				 */
 				throw new CKEditorError(
-					'schema-check-merge-no-element-before: The node before the merge position must be an element.',
+					'schema-check-merge-no-element-before',
 					this
 				);
 			}
@@ -459,7 +459,7 @@ export default class Schema {
 				 * @error schema-check-merge-no-element-after
 				 */
 				throw new CKEditorError(
-					'schema-check-merge-no-element-after: The node after the merge position must be an element.',
+					'schema-check-merge-no-element-after',
 					this
 				);
 			}
@@ -1256,7 +1256,7 @@ mix( Schema, ObservableMixin );
  * {@glink framework/guides/deep-dive/schema#selectable-elements Selectable elements} section of the Schema deep dive} guide.
  *
  * @property {Boolean} isContent
- * An item is a content when it always finds its way to editor data output regardless of the number and type of its descendants.
+ * An item is a content when it always finds its way to the editor data output regardless of the number and type of its descendants.
  * Examples of content elements: `$text`, `image`, `table`, etc. (but not `paragraph`, `heading1` or `tableCell`).
  *
  * **Note:** An object is also a content element, so

+ 8 - 19
packages/ckeditor5-engine/src/model/selection.js

@@ -390,13 +390,9 @@ export default class Selection {
 				/**
 				 * selection.setTo requires the second parameter when the first parameter is a node.
 				 *
-				 * @error model-selection-setTo-required-second-parameter
+				 * @error model-selection-setto-required-second-parameter
 				 */
-				throw new CKEditorError(
-					'model-selection-setTo-required-second-parameter: ' +
-					'selection.setTo requires the second parameter when the first parameter is a node.',
-					[ this, selectable ]
-				);
+				throw new CKEditorError( 'model-selection-setto-required-second-parameter', [ this, selectable ] );
 			}
 
 			this._setRanges( [ range ], backward );
@@ -414,12 +410,9 @@ export default class Selection {
 			 * * View nodes were passed instead of model nodes.
 			 * * `null`/`undefined` was passed.
 			 *
-			 * @error model-selection-setTo-not-selectable
+			 * @error model-selection-setto-not-selectable
 			 */
-			throw new CKEditorError(
-				'model-selection-setTo-not-selectable: Cannot set the selection to the given place.',
-				[ this, selectable ]
-			);
+			throw new CKEditorError( 'model-selection-setto-not-selectable', [ this, selectable ] );
 		}
 	}
 
@@ -452,8 +445,7 @@ export default class Selection {
 				 * @error model-selection-set-ranges-not-range
 				 */
 				throw new CKEditorError(
-					'model-selection-set-ranges-not-range: ' +
-					'Selection range set to an object that is not an instance of model.Range.',
+					'model-selection-set-ranges-not-range',
 					[ this, newRanges ]
 				);
 			}
@@ -495,12 +487,9 @@ export default class Selection {
 			/**
 			 * Cannot set selection focus if there are no ranges in selection.
 			 *
-			 * @error model-selection-setFocus-no-ranges
+			 * @error model-selection-setfocus-no-ranges
 			 */
-			throw new CKEditorError(
-				'model-selection-setFocus-no-ranges: Cannot set selection focus if there are no ranges in selection.',
-				[ this, itemOrPosition ]
-			);
+			throw new CKEditorError( 'model-selection-setfocus-no-ranges', [ this, itemOrPosition ] );
 		}
 
 		const newFocus = Position._createAt( itemOrPosition, offset );
@@ -756,7 +745,7 @@ export default class Selection {
 				 * @param {module:engine/model/range~Range} intersectingRange Range in the selection that intersects with `addedRange`.
 				 */
 				throw new CKEditorError(
-					'model-selection-range-intersects: Trying to add a range that intersects with another range in the selection.',
+					'model-selection-range-intersects',
 					[ this, range ],
 					{ addedRange: range, intersectingRange: this._ranges[ i ] }
 				);

+ 2 - 2
packages/ckeditor5-engine/src/model/textproxy.js

@@ -66,7 +66,7 @@ export default class TextProxy {
 			 *
 			 * @error model-textproxy-wrong-offsetintext
 			 */
-			throw new CKEditorError( 'model-textproxy-wrong-offsetintext: Given offsetInText value is incorrect.', this );
+			throw new CKEditorError( 'model-textproxy-wrong-offsetintext', this );
 		}
 
 		if ( length < 0 || offsetInText + length > textNode.offsetSize ) {
@@ -75,7 +75,7 @@ export default class TextProxy {
 			 *
 			 * @error model-textproxy-wrong-length
 			 */
-			throw new CKEditorError( 'model-textproxy-wrong-length: Given length value is incorrect.', this );
+			throw new CKEditorError( 'model-textproxy-wrong-length', this );
 		}
 
 		/**

+ 7 - 6
packages/ckeditor5-engine/src/model/treewalker.js

@@ -48,7 +48,7 @@ export default class TreeWalker {
 			 * @error model-tree-walker-no-start-position
 			 */
 			throw new CKEditorError(
-				'model-tree-walker-no-start-position: Neither boundaries nor starting position have been defined.',
+				'model-tree-walker-no-start-position',
 				null
 			);
 		}
@@ -56,11 +56,12 @@ export default class TreeWalker {
 		const direction = options.direction || 'forward';
 
 		if ( direction != 'forward' && direction != 'backward' ) {
-			throw new CKEditorError(
-				'model-tree-walker-unknown-direction: Only `backward` and `forward` direction allowed.',
-				options,
-				{ direction }
-			);
+			/**
+			 * Only `backward` and `forward` direction allowed.
+			 *
+			 * @error model-tree-walker-unknown-direction
+			 */
+			throw new CKEditorError( 'model-tree-walker-unknown-direction', options, { direction } );
 		}
 
 		/**

+ 5 - 7
packages/ckeditor5-engine/src/model/utils/insertcontent.js

@@ -324,7 +324,7 @@ class Insertion {
 			 * @param {module:engine/model/position~Position} position Position to insert the node at.
 			 */
 			throw new CKEditorError(
-				'insertcontent-wrong-position: Given node cannot be inserted on the given position.',
+				'insertcontent-wrong-position',
 				this,
 				{ node, position: this.position }
 			);
@@ -443,17 +443,15 @@ class Insertion {
 				// At this point the insertion position should be after the node we'll merge. If it isn't,
 				// it should need to be secured as in the left merge case.
 				/**
-				 * An internal error occurred during merging inserted content with its siblings.
-				 * The insertion position should equal to the merge position.
+				 * An internal error occurred when merging inserted content with its siblings.
+				 * The insertion position should equal the merge position.
 				 *
 				 * If you encountered this error, report it back to the CKEditor 5 team
-				 * with as many details regarding the content being inserted and the insertion position
-				 * as possible.
+				 * with as many details as possible regarding the content being inserted and the insertion position.
 				 *
 				 * @error insertcontent-invalid-insertion-position
 				 */
-				throw new CKEditorError( 'insertcontent-invalid-insertion-position: ' +
-					'An internal error occurred during insertContent().', this );
+				throw new CKEditorError( 'insertcontent-invalid-insertion-position', this );
 			}
 
 			// Move the position to the previous node, so it isn't moved to the graveyard on merge.

+ 31 - 37
packages/ckeditor5-engine/src/model/writer.js

@@ -196,9 +196,7 @@ export default class Writer {
 					 * @error model-writer-insert-forbidden-move
 					 */
 					throw new CKEditorError(
-						'model-writer-insert-forbidden-move: ' +
-						'Cannot move a node from a document to a different tree. ' +
-						'It is forbidden to move a node that was already in a document outside of it.',
+						'model-writer-insert-forbidden-move',
 						this
 					);
 				} else {
@@ -484,7 +482,7 @@ export default class Writer {
 			 *
 			 * @error writer-move-invalid-range
 			 */
-			throw new CKEditorError( 'writer-move-invalid-range: Invalid range to move.', this );
+			throw new CKEditorError( 'writer-move-invalid-range', this );
 		}
 
 		if ( !range.isFlat ) {
@@ -493,7 +491,7 @@ export default class Writer {
 			 *
 			 * @error writer-move-range-not-flat
 			 */
-			throw new CKEditorError( 'writer-move-range-not-flat: Range to move is not flat.', this );
+			throw new CKEditorError( 'writer-move-range-not-flat', this );
 		}
 
 		const position = Position._createAt( itemOrPosition, offset );
@@ -513,7 +511,7 @@ export default class Writer {
 			 *
 			 * @error writer-move-different-document
 			 */
-			throw new CKEditorError( 'writer-move-different-document: Range is going to be moved between different documents.', this );
+			throw new CKEditorError( 'writer-move-different-document', this );
 		}
 
 		const version = range.root.document ? range.root.document.version : null;
@@ -565,7 +563,7 @@ export default class Writer {
 			 *
 			 * @error writer-merge-no-element-before
 			 */
-			throw new CKEditorError( 'writer-merge-no-element-before: Node before merge position must be an element.', this );
+			throw new CKEditorError( 'writer-merge-no-element-before', this );
 		}
 
 		if ( !( nodeAfter instanceof Element ) ) {
@@ -574,7 +572,7 @@ export default class Writer {
 			 *
 			 * @error writer-merge-no-element-after
 			 */
-			throw new CKEditorError( 'writer-merge-no-element-after: Node after merge position must be an element.', this );
+			throw new CKEditorError( 'writer-merge-no-element-after', this );
 		}
 
 		if ( !position.root.document ) {
@@ -724,7 +722,7 @@ export default class Writer {
 			 * @error writer-rename-not-element-instance
 			 */
 			throw new CKEditorError(
-				'writer-rename-not-element-instance: Trying to rename an object which is not an instance of Element.',
+				'writer-rename-not-element-instance',
 				this
 			);
 		}
@@ -761,7 +759,7 @@ export default class Writer {
 			 *
 			 * @error writer-split-element-no-parent
 			 */
-			throw new CKEditorError( 'writer-split-element-no-parent: Element with no parent can not be split.', this );
+			throw new CKEditorError( 'writer-split-element-no-parent', this );
 		}
 
 		// When limit element is not defined lets set splitElement parent as limit.
@@ -770,7 +768,12 @@ export default class Writer {
 		}
 
 		if ( !position.parent.getAncestors( { includeSelf: true } ).includes( limitElement ) ) {
-			throw new CKEditorError( 'writer-split-invalid-limit-element: Limit element is not a position ancestor.', this );
+			/**
+			 * Limit element is not a position ancestor.
+			 *
+			 * @error writer-split-invalid-limit-element
+			 */
+			throw new CKEditorError( 'writer-split-invalid-limit-element', this );
 		}
 
 		// We need to cache elements that will be created as a result of the first split because
@@ -820,7 +823,7 @@ export default class Writer {
 			 *
 			 * @error writer-wrap-range-not-flat
 			 */
-			throw new CKEditorError( 'writer-wrap-range-not-flat: Range to wrap is not flat.', this );
+			throw new CKEditorError( 'writer-wrap-range-not-flat', this );
 		}
 
 		const element = elementOrString instanceof Element ? elementOrString : new Element( elementOrString );
@@ -831,7 +834,7 @@ export default class Writer {
 			 *
 			 * @error writer-wrap-element-not-empty
 			 */
-			throw new CKEditorError( 'writer-wrap-element-not-empty: Element to wrap with is not empty.', this );
+			throw new CKEditorError( 'writer-wrap-element-not-empty', this );
 		}
 
 		if ( element.parent !== null ) {
@@ -840,7 +843,7 @@ export default class Writer {
 			 *
 			 * @error writer-wrap-element-attached
 			 */
-			throw new CKEditorError( 'writer-wrap-element-attached: Element to wrap with is already attached to tree model.', this );
+			throw new CKEditorError( 'writer-wrap-element-attached', this );
 		}
 
 		this.insert( element, range.start );
@@ -866,7 +869,7 @@ export default class Writer {
 			 *
 			 * @error writer-unwrap-element-no-parent
 			 */
-			throw new CKEditorError( 'writer-unwrap-element-no-parent: Trying to unwrap an element which has no parent.', this );
+			throw new CKEditorError( 'writer-unwrap-element-no-parent', this );
 		}
 
 		this.move( Range._createIn( element ), this.createPositionAfter( element ) );
@@ -919,12 +922,9 @@ export default class Writer {
 			/**
 			 * The `options.usingOperation` parameter is required when adding a new marker.
 			 *
-			 * @error writer-addMarker-no-usingOperation
+			 * @error writer-addmarker-no-usingoperation
 			 */
-			throw new CKEditorError(
-				'writer-addMarker-no-usingOperation: The options.usingOperation parameter is required when adding a new marker.',
-				this
-			);
+			throw new CKEditorError( 'writer-addmarker-no-usingoperation', this );
 		}
 
 		const usingOperation = options.usingOperation;
@@ -935,21 +935,18 @@ export default class Writer {
 			/**
 			 * Marker with provided name already exists.
 			 *
-			 * @error writer-addMarker-marker-exists
+			 * @error writer-addmarker-marker-exists
 			 */
-			throw new CKEditorError( 'writer-addMarker-marker-exists: Marker with provided name already exists.', this );
+			throw new CKEditorError( 'writer-addmarker-marker-exists', this );
 		}
 
 		if ( !range ) {
 			/**
 			 * Range parameter is required when adding a new marker.
 			 *
-			 * @error writer-addMarker-no-range
+			 * @error writer-addmarker-no-range
 			 */
-			throw new CKEditorError(
-				'writer-addMarker-no-range: Range parameter is required when adding a new marker.',
-				this
-			);
+			throw new CKEditorError( 'writer-addmarker-no-range', this );
 		}
 
 		if ( !usingOperation ) {
@@ -1040,9 +1037,9 @@ export default class Writer {
 			/**
 			 * Marker with provided name does not exists.
 			 *
-			 * @error writer-updateMarker-marker-not-exists
+			 * @error writer-updatemarker-marker-not-exists
 			 */
-			throw new CKEditorError( 'writer-updateMarker-marker-not-exists: Marker with provided name does not exists.', this );
+			throw new CKEditorError( 'writer-updatemarker-marker-not-exists', this );
 		}
 
 		if ( !options ) {
@@ -1061,12 +1058,9 @@ export default class Writer {
 			/**
 			 * One of the options is required - provide range, usingOperations or affectsData.
 			 *
-			 * @error writer-updateMarker-wrong-options
+			 * @error writer-updatemarker-wrong-options
 			 */
-			throw new CKEditorError(
-				'writer-updateMarker-wrong-options: One of the options is required - provide range, usingOperations or affectsData.',
-				this
-			);
+			throw new CKEditorError( 'writer-updatemarker-wrong-options', this );
 		}
 
 		const currentRange = currentMarker.getRange();
@@ -1114,9 +1108,9 @@ export default class Writer {
 			/**
 			 * Trying to remove marker which does not exist.
 			 *
-			 * @error writer-removeMarker-no-marker
+			 * @error writer-removemarker-no-marker
 			 */
-			throw new CKEditorError( 'writer-removeMarker-no-marker: Trying to remove marker which does not exist.', this );
+			throw new CKEditorError( 'writer-removemarker-no-marker', this );
 		}
 
 		const marker = this.model.markers.get( name );
@@ -1349,7 +1343,7 @@ export default class Writer {
 		 * @error writer-incorrect-use
 		 */
 		if ( this.model._currentWriter !== this ) {
-			throw new CKEditorError( 'writer-incorrect-use: Trying to use a writer outside the change() block.', this );
+			throw new CKEditorError( 'writer-incorrect-use', this );
 		}
 	}
 

+ 1 - 2
packages/ckeditor5-engine/src/view/attributeelement.js

@@ -120,8 +120,7 @@ export default class AttributeElement extends Element {
 			 * @error attribute-element-get-elements-with-same-id-no-id
 			 */
 			throw new CKEditorError(
-				'attribute-element-get-elements-with-same-id-no-id: ' +
-				'Cannot get elements with the same id for an attribute element without id.',
+				'attribute-element-get-elements-with-same-id-no-id',
 				this
 			);
 		}

+ 38 - 47
packages/ckeditor5-engine/src/view/downcastwriter.js

@@ -427,7 +427,7 @@ export default class DowncastWriter {
 	}
 
 	/**
-	 * Breaks attribute elements at provided position or at boundaries of a provided range. It breaks attribute elements
+	 * Breaks attribute elements at the provided position or at the boundaries of a provided range. It breaks attribute elements
 	 * up to their first ancestor that is a container element.
 	 *
 	 * In following examples `<p>` is a container, `<b>` and `<u>` are attribute elements:
@@ -439,31 +439,29 @@ export default class DowncastWriter {
 	 *
 	 * **Note:** {@link module:engine/view/documentfragment~DocumentFragment DocumentFragment} is treated like a container.
 	 *
-	 * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes} and
-	 * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer} is that `breakAttributes` breaks all
-	 * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of given `position`,
+	 * **Note:** The difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes()} and
+	 * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer()} is that `breakAttributes()` breaks all
+	 * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of a given `position`,
 	 * up to the first encountered {@link module:engine/view/containerelement~ContainerElement container element}.
-	 * `breakContainer` assumes that given `position` is directly in container element and breaks that container element.
+	 * `breakContainer()` assumes that a given `position` is directly in the container element and breaks that container element.
 	 *
-	 * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-invalid-range-container`
-	 * when {@link module:engine/view/range~Range#start start}
+	 * Throws the `view-writer-invalid-range-container` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}
+	 * when the {@link module:engine/view/range~Range#start start}
 	 * and {@link module:engine/view/range~Range#end end} positions of a passed range are not placed inside same parent container.
 	 *
-	 * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-empty-element`
-	 * when trying to break attributes
-	 * inside {@link module:engine/view/emptyelement~EmptyElement EmptyElement}.
+	 * Throws the `view-writer-cannot-break-empty-element` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}
+	 * when trying to break attributes inside an {@link module:engine/view/emptyelement~EmptyElement EmptyElement}.
 	 *
-	 * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-cannot-break-ui-element`
-	 * when trying to break attributes
-	 * inside {@link module:engine/view/uielement~UIElement UIElement}.
+	 * Throws the `view-writer-cannot-break-ui-element` {@link module:utils/ckeditorerror~CKEditorError CKEditorError}
+	 * when trying to break attributes inside a {@link module:engine/view/uielement~UIElement UIElement}.
 	 *
 	 * @see module:engine/view/attributeelement~AttributeElement
 	 * @see module:engine/view/containerelement~ContainerElement
 	 * @see module:engine/view/downcastwriter~DowncastWriter#breakContainer
-	 * @param {module:engine/view/position~Position|module:engine/view/range~Range} positionOrRange Position where
+	 * @param {module:engine/view/position~Position|module:engine/view/range~Range} positionOrRange The position where
 	 * to break attribute elements.
-	 * @returns {module:engine/view/position~Position|module:engine/view/range~Range} New position or range, after breaking the attribute
-	 * elements.
+	 * @returns {module:engine/view/position~Position|module:engine/view/range~Range} The new position or range, after breaking the
+	 * attribute elements.
 	 */
 	breakAttributes( positionOrRange ) {
 		if ( positionOrRange instanceof Position ) {
@@ -474,27 +472,27 @@ export default class DowncastWriter {
 	}
 
 	/**
-	 * Breaks {@link module:engine/view/containerelement~ContainerElement container view element} into two, at the given position. Position
-	 * has to be directly inside container element and cannot be in root. Does not break if position is at the beginning
-	 * or at the end of it's parent element.
+	 * Breaks a {@link module:engine/view/containerelement~ContainerElement container view element} into two, at the given position.
+	 * The position has to be directly inside the container element and cannot be in the root. It does not break the conrainer view element
+	 * if the position is at the beginning or at the end of its parent element.
 	 *
 	 *		<p>foo^bar</p> -> <p>foo</p><p>bar</p>
 	 *		<div><p>foo</p>^<p>bar</p></div> -> <div><p>foo</p></div><div><p>bar</p></div>
 	 *		<p>^foobar</p> -> ^<p>foobar</p>
 	 *		<p>foobar^</p> -> <p>foobar</p>^
 	 *
-	 * **Note:** Difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes} and
-	 * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer} is that `breakAttributes` breaks all
-	 * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of given `position`,
+	 * **Note:** The difference between {@link module:engine/view/downcastwriter~DowncastWriter#breakAttributes breakAttributes()} and
+	 * {@link module:engine/view/downcastwriter~DowncastWriter#breakContainer breakContainer()} is that `breakAttributes()` breaks all
+	 * {@link module:engine/view/attributeelement~AttributeElement attribute elements} that are ancestors of a given `position`,
 	 * up to the first encountered {@link module:engine/view/containerelement~ContainerElement container element}.
-	 * `breakContainer` assumes that given `position` is directly in container element and breaks that container element.
+	 * `breakContainer()` assumes that the given `position` is directly in the container element and breaks that container element.
 	 *
 	 * @see module:engine/view/attributeelement~AttributeElement
 	 * @see module:engine/view/containerelement~ContainerElement
 	 * @see module:engine/view/downcastwriter~DowncastWriter#breakAttributes
-	 * @param {module:engine/view/position~Position} position Position where to break element.
-	 * @returns {module:engine/view/position~Position} Position between broken elements. If element has not been broken,
-	 * the returned position is placed either before it or after it.
+	 * @param {module:engine/view/position~Position} position The position where to break the element.
+	 * @returns {module:engine/view/position~Position} The position between broken elements. If an element has not been broken,
+	 * the returned position is placed either before or after it.
 	 */
 	breakContainer( position ) {
 		const element = position.parent;
@@ -505,10 +503,7 @@ export default class DowncastWriter {
 			 *
 			 * @error view-writer-break-non-container-element
 			 */
-			throw new CKEditorError(
-				'view-writer-break-non-container-element: Trying to break an element which is not a container element.',
-				this.document
-			);
+			throw new CKEditorError( 'view-writer-break-non-container-element', this.document );
 		}
 
 		if ( !element.parent ) {
@@ -517,7 +512,7 @@ export default class DowncastWriter {
 			 *
 			 * @error view-writer-break-root
 			 */
-			throw new CKEditorError( 'view-writer-break-root: Trying to break root element.', this.document );
+			throw new CKEditorError( 'view-writer-break-root', this.document );
 		}
 
 		if ( position.isAtStart ) {
@@ -639,8 +634,7 @@ export default class DowncastWriter {
 			 *
 			 * @error view-writer-merge-containers-invalid-position
 			 */
-			throw new CKEditorError( 'view-writer-merge-containers-invalid-position: ' +
-				'Element before and after given position cannot be merged.', this.document );
+			throw new CKEditorError( 'view-writer-merge-containers-invalid-position', this.document );
 		}
 
 		const lastChild = prev.getChild( prev.childCount - 1 );
@@ -653,7 +647,7 @@ export default class DowncastWriter {
 	}
 
 	/**
-	 * Insert node or nodes at specified position. Takes care about breaking attributes before insertion
+	 * Inserts a node or nodes at specified position. Takes care about breaking attributes before insertion
 	 * and merging them afterwards.
 	 *
 	 * Throws {@link module:utils/ckeditorerror~CKEditorError CKEditorError} `view-writer-insert-invalid-node` when nodes to insert
@@ -686,7 +680,7 @@ export default class DowncastWriter {
 			 * @error view-writer-invalid-position-container
 			 */
 			throw new CKEditorError(
-				'view-writer-invalid-position-container: Position\'s parent container cannot be found.',
+				'view-writer-invalid-position-container',
 				this.document
 			);
 		}
@@ -876,7 +870,7 @@ export default class DowncastWriter {
 	wrap( range, attribute ) {
 		if ( !( attribute instanceof AttributeElement ) ) {
 			throw new CKEditorError(
-				'view-writer-wrap-invalid-attribute: DowncastWriter#wrap() must be called with an attribute element.',
+				'view-writer-wrap-invalid-attribute',
 				this.document
 			);
 		}
@@ -925,7 +919,7 @@ export default class DowncastWriter {
 			 * @error view-writer-unwrap-invalid-attribute
 			 */
 			throw new CKEditorError(
-				'view-writer-unwrap-invalid-attribute: DowncastWriter#unwrap() must be called with an attribute element.',
+				'view-writer-unwrap-invalid-attribute',
 				this.document
 			);
 		}
@@ -1611,7 +1605,7 @@ export default class DowncastWriter {
 			 *
 			 * @error view-writer-cannot-break-empty-element
 			 */
-			throw new CKEditorError( 'view-writer-cannot-break-empty-element: Cannot break an EmptyElement instance.', this.document );
+			throw new CKEditorError( 'view-writer-cannot-break-empty-element', this.document );
 		}
 
 		// If position is placed inside UIElement - throw an exception as we cannot break inside.
@@ -1625,7 +1619,7 @@ export default class DowncastWriter {
 			 *
 			 * @error view-writer-cannot-break-ui-element
 			 */
-			throw new CKEditorError( 'view-writer-cannot-break-ui-element: Cannot break a UIElement instance.', this.document );
+			throw new CKEditorError( 'view-writer-cannot-break-ui-element', this.document );
 		}
 
 		// If position is placed inside RawElement - throw an exception as we cannot break inside.
@@ -1639,7 +1633,7 @@ export default class DowncastWriter {
 			 *
 			 * @error view-writer-cannot-break-raw-element
 			 */
-			throw new CKEditorError( 'view-writer-cannot-break-raw-element: Cannot break a RawElement instance.', this.document );
+			throw new CKEditorError( 'view-writer-cannot-break-raw-element', this.document );
 		}
 
 		// There are no attributes to break and text nodes breaking is not forced.
@@ -1927,7 +1921,7 @@ function validateNodesToInsert( nodes, errorContext ) {
 	for ( const node of nodes ) {
 		if ( !validNodesToInsert.some( ( validNode => node instanceof validNode ) ) ) { // eslint-disable-line no-use-before-define
 			/**
-			 * One of the nodes to be inserted is of invalid type.
+			 * One of the nodes to be inserted is of an invalid type.
 			 *
 			 * Nodes to be inserted with {@link module:engine/view/downcastwriter~DowncastWriter#insert `DowncastWriter#insert()`} should be
 			 * of the following types:
@@ -1941,10 +1935,7 @@ function validateNodesToInsert( nodes, errorContext ) {
 			 *
 			 * @error view-writer-insert-invalid-node-type
 			 */
-			throw new CKEditorError(
-				'view-writer-insert-invalid-node-type: One of the nodes to be inserted is of invalid type.',
-				errorContext
-			);
+			throw new CKEditorError( 'view-writer-insert-invalid-node-type', errorContext );
 		}
 
 		if ( !node.is( '$text' ) ) {
@@ -1985,12 +1976,12 @@ function validateRangeContainer( range, errorContext ) {
 		 * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#clean()`},
 		 * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#wrap()`},
 		 * {@link module:engine/view/downcastwriter~DowncastWriter#wrap `DowncastWriter#unwrap()`} need to be called
-		 * on a range that have its start and end positions located in the same container element. Both positions can be
+		 * on a range that has its start and end positions located in the same container element. Both positions can be
 		 * nested within other elements (e.g. an attribute element) but the closest container ancestor must be the same.
 		 *
 		 * @error view-writer-invalid-range-container
 		 */
-		throw new CKEditorError( 'view-writer-invalid-range-container: The container of the given range is invalid.', errorContext );
+		throw new CKEditorError( 'view-writer-invalid-range-container', errorContext );
 	}
 }
 

+ 1 - 1
packages/ckeditor5-engine/src/view/emptyelement.js

@@ -101,7 +101,7 @@ export default class EmptyElement extends Element {
 			 * @error view-emptyelement-cannot-add
 			 */
 			throw new CKEditorError(
-				'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.',
+				'view-emptyelement-cannot-add',
 				[ this, nodes ]
 			);
 		}

+ 1 - 1
packages/ckeditor5-engine/src/view/node.js

@@ -73,7 +73,7 @@ export default class Node {
 			 *
 			 * @error view-node-not-found-in-parent
 			 */
-			throw new CKEditorError( 'view-node-not-found-in-parent: The node\'s parent does not contain this node.', this );
+			throw new CKEditorError( 'view-node-not-found-in-parent', this );
 		}
 
 		return pos;

+ 4 - 8
packages/ckeditor5-engine/src/view/position.js

@@ -356,13 +356,9 @@ export default class Position {
 				 * {@link module:engine/view/view~View#createPositionAt `View#createPositionAt()`}
 				 * requires the offset to be specified when the first parameter is a view item.
 				 *
-				 * @error view-createPositionAt-offset-required
+				 * @error view-createpositionat-offset-required
 				 */
-				throw new CKEditorError(
-					'view-createPositionAt-offset-required: ' +
-					'View#createPositionAt() requires the offset when the first parameter is a view item.',
-					node
-				);
+				throw new CKEditorError( 'view-createpositionat-offset-required', node );
 			}
 
 			return new Position( node, offset );
@@ -389,7 +385,7 @@ export default class Position {
 			 * @error view-position-after-root
 			 * @param {module:engine/view/node~Node} root
 			 */
-			throw new CKEditorError( 'view-position-after-root: You can not make position after root.', item, { root: item } );
+			throw new CKEditorError( 'view-position-after-root', item, { root: item } );
 		}
 
 		return new Position( item.parent, item.index + 1 );
@@ -415,7 +411,7 @@ export default class Position {
 			 * @error view-position-before-root
 			 * @param {module:engine/view/node~Node} root
 			 */
-			throw new CKEditorError( 'view-position-before-root: You can not make position before root.', item, { root: item } );
+			throw new CKEditorError( 'view-position-before-root', item, { root: item } );
 		}
 
 		return new Position( item.parent, item.index );

+ 1 - 1
packages/ckeditor5-engine/src/view/rawelement.js

@@ -113,7 +113,7 @@ export default class RawElement extends Element {
 			 * @error view-rawelement-cannot-add
 			 */
 			throw new CKEditorError(
-				'view-rawelement-cannot-add: Cannot add child nodes to a RawElement instance.',
+				'view-rawelement-cannot-add',
 				[ this, nodes ]
 			);
 		}

+ 3 - 3
packages/ckeditor5-engine/src/view/renderer.js

@@ -150,9 +150,9 @@ export default class Renderer {
 				/**
 				 * Unknown type passed to Renderer.markToSync.
 				 *
-				 * @error renderer-unknown-type
+				 * @error view-renderer-unknown-type
 				 */
-				throw new CKEditorError( 'view-renderer-unknown-type: Unknown type passed to Renderer.markToSync.', this );
+				throw new CKEditorError( 'view-renderer-unknown-type', this );
 			}
 		}
 	}
@@ -387,7 +387,7 @@ export default class Renderer {
 			 *
 			 * @error view-renderer-filler-was-lost
 			 */
-			throw new CKEditorError( 'view-renderer-filler-was-lost: The inline filler node was lost.', this );
+			throw new CKEditorError( 'view-renderer-filler-was-lost', this );
 		}
 
 		if ( isInlineFiller( domFillerNode ) ) {

+ 8 - 16
packages/ckeditor5-engine/src/view/selection.js

@@ -497,13 +497,9 @@ export default class Selection {
 				/**
 				 * selection.setTo requires the second parameter when the first parameter is a node.
 				 *
-				 * @error view-selection-setTo-required-second-parameter
+				 * @error view-selection-setto-required-second-parameter
 				 */
-				throw new CKEditorError(
-					'view-selection-setTo-required-second-parameter: ' +
-					'selection.setTo requires the second parameter when the first parameter is a node.',
-					this
-				);
+				throw new CKEditorError( 'view-selection-setto-required-second-parameter', this );
 			} else if ( placeOrOffset == 'in' ) {
 				range = Range._createIn( selectable );
 			} else if ( placeOrOffset == 'on' ) {
@@ -523,9 +519,9 @@ export default class Selection {
 			/**
 			 * Cannot set selection to given place.
 			 *
-			 * @error view-selection-setTo-not-selectable
+			 * @error view-selection-setto-not-selectable
 			 */
-			throw new CKEditorError( 'view-selection-setTo-not-selectable: Cannot set selection to given place.', this );
+			throw new CKEditorError( 'view-selection-setto-not-selectable', this );
 		}
 
 		this.fire( 'change' );
@@ -547,12 +543,9 @@ export default class Selection {
 			/**
 			 * Cannot set selection focus if there are no ranges in selection.
 			 *
-			 * @error view-selection-setFocus-no-ranges
+			 * @error view-selection-setfocus-no-ranges
 			 */
-			throw new CKEditorError(
-				'view-selection-setFocus-no-ranges: Cannot set selection focus if there are no ranges in selection.',
-				this
-			);
+			throw new CKEditorError( 'view-selection-setfocus-no-ranges', this );
 		}
 
 		const newFocus = Position._createAt( itemOrPosition, offset );
@@ -660,8 +653,7 @@ export default class Selection {
 			 * @error view-selection-add-range-not-range
 			 */
 			throw new CKEditorError(
-				'view-selection-add-range-not-range: ' +
-				'Selection range set to an object that is not an instance of view.Range',
+				'view-selection-add-range-not-range',
 				this
 			);
 		}
@@ -690,7 +682,7 @@ export default class Selection {
 				 * @param {module:engine/view/range~Range} intersectingRange Range from selection that intersects with `addedRange`.
 				 */
 				throw new CKEditorError(
-					'view-selection-range-intersects: Trying to add a range that intersects with another range from selection.',
+					'view-selection-range-intersects',
 					this,
 					{ addedRange: range, intersectingRange: storedRange }
 				);

+ 2 - 2
packages/ckeditor5-engine/src/view/textproxy.js

@@ -55,7 +55,7 @@ export default class TextProxy {
 			 *
 			 * @error view-textproxy-wrong-offsetintext
 			 */
-			throw new CKEditorError( 'view-textproxy-wrong-offsetintext: Given offsetInText value is incorrect.', this );
+			throw new CKEditorError( 'view-textproxy-wrong-offsetintext', this );
 		}
 
 		if ( length < 0 || offsetInText + length > textNode.data.length ) {
@@ -64,7 +64,7 @@ export default class TextProxy {
 			 *
 			 * @error view-textproxy-wrong-length
 			 */
-			throw new CKEditorError( 'view-textproxy-wrong-length: Given length value is incorrect.', this );
+			throw new CKEditorError( 'view-textproxy-wrong-length', this );
 		}
 
 		/**

+ 7 - 6
packages/ckeditor5-engine/src/view/treewalker.js

@@ -43,17 +43,18 @@ export default class TreeWalker {
 			 * @error view-tree-walker-no-start-position
 			 */
 			throw new CKEditorError(
-				'view-tree-walker-no-start-position: Neither boundaries nor starting position have been defined.',
+				'view-tree-walker-no-start-position',
 				null
 			);
 		}
 
 		if ( options.direction && options.direction != 'forward' && options.direction != 'backward' ) {
-			throw new CKEditorError(
-				'view-tree-walker-unknown-direction: Only `backward` and `forward` direction allowed.',
-				options.startPosition,
-				{ direction: options.direction }
-			);
+			/**
+			 * Only `backward` and `forward` direction allowed.
+			 *
+			 * @error view-tree-walker-unknown-direction
+			 */
+			throw new CKEditorError( 'view-tree-walker-unknown-direction', options.startPosition, { direction: options.direction } );
 		}
 
 		/**

+ 1 - 1
packages/ckeditor5-engine/src/view/uielement.js

@@ -113,7 +113,7 @@ export default class UIElement extends Element {
 			 *
 			 * @error view-uielement-cannot-add
 			 */
-			throw new CKEditorError( 'view-uielement-cannot-add: Cannot add child nodes to UIElement instance.', this );
+			throw new CKEditorError( 'view-uielement-cannot-add', this );
 		}
 	}
 

+ 1 - 3
packages/ckeditor5-engine/src/view/view.js

@@ -460,9 +460,7 @@ export default class View {
 			 * @error cannot-change-view-tree
 			 */
 			throw new CKEditorError(
-				'cannot-change-view-tree: ' +
-				'Attempting to make changes to the view when it is in an incorrect state: rendering or post-fixers are in progress. ' +
-				'This may cause some unexpected behavior and inconsistency between the DOM and the view.',
+				'cannot-change-view-tree',
 				this
 			);
 		}

+ 6 - 6
packages/ckeditor5-engine/tests/controller/datacontroller.js

@@ -189,7 +189,7 @@ describe( 'DataController', () => {
 
 			expectToThrowCKEditorError( () => {
 				data.init( '<p>Bar</p>' );
-			}, /datacontroller-init-document-not-empty:/, model );
+			}, /datacontroller-init-document-not-empty/, model );
 		} );
 
 		it( 'should set data to default main root', () => {
@@ -243,7 +243,7 @@ describe( 'DataController', () => {
 		it( 'should throw an error when non-existent root is used (single)', () => {
 			expectToThrowCKEditorError( () => {
 				data.init( { nonexistent: '<p>Bar</p>' } );
-			}, /^datacontroller-init-non-existent-root:/ );
+			}, 'datacontroller-init-non-existent-root' );
 		} );
 
 		it( 'should throw an error when non-existent root is used (one of many)', () => {
@@ -251,7 +251,7 @@ describe( 'DataController', () => {
 
 			expectToThrowCKEditorError( () => {
 				data.init( { main: 'bar', nonexistent: '<p>Bar</p>' } );
-			}, /^datacontroller-init-non-existent-root:/, model );
+			}, /^datacontroller-init-non-existent-root/, model );
 
 			expect( getData( model, { withoutSelection: true } ) ).to.equal( '' );
 		} );
@@ -332,7 +332,7 @@ describe( 'DataController', () => {
 		it( 'should throw an error when non-existent root is used (single)', () => {
 			expectToThrowCKEditorError( () => {
 				data.set( { nonexistent: '<p>Bar</p>' } );
-			}, /datacontroller-set-non-existent-root:/, model );
+			}, /datacontroller-set-non-existent-root/, model );
 		} );
 
 		it( 'should throw an error when non-existent root is used (one of many) without touching any roots data', () => {
@@ -341,7 +341,7 @@ describe( 'DataController', () => {
 
 			expectToThrowCKEditorError( () => {
 				data.set( { main: 'bar', nonexistent: '<p>Bar</p>' } );
-			}, /datacontroller-set-non-existent-root:/, model );
+			}, /datacontroller-set-non-existent-root/, model );
 
 			expect( getData( model, { withoutSelection: true } ) ).to.equal( 'foo' );
 		} );
@@ -452,7 +452,7 @@ describe( 'DataController', () => {
 		it( 'should throw an error when non-existent root is used', () => {
 			expectToThrowCKEditorError( () => {
 				data.get( { rootName: 'nonexistent' } );
-			}, /datacontroller-get-non-existent-root:/ );
+			}, 'datacontroller-get-non-existent-root' );
 		} );
 
 		it( 'should allow to provide additional options for retrieving data - insert conversion', () => {

+ 1 - 1
packages/ckeditor5-engine/tests/dev-utils/operationreplayer.js

@@ -148,7 +148,7 @@ describe( 'OperationReplayer', () => {
 				.then( () => {
 					throw new Error( 'It should throw an error' );
 				}, err => {
-					expect( err.message ).to.match( /^model-document-applyOperation-wrong-version/ );
+					expect( err.message ).to.match( /model-document-applyoperation-wrong-version/ );
 				} );
 		} );
 	} );

+ 2 - 2
packages/ckeditor5-engine/tests/model/document.js

@@ -87,7 +87,7 @@ describe( 'Document', () => {
 
 			expectToThrowCKEditorError( () => {
 				model.applyOperation( operation );
-			}, /^model-document-applyOperation-wrong-version/, model );
+			}, 'model-document-applyoperation-wrong-version', model );
 		} );
 	} );
 
@@ -130,7 +130,7 @@ describe( 'Document', () => {
 
 			expectToThrowCKEditorError( () => {
 				doc.createRoot( '$root', 'rootName' );
-			}, /model-document-createRoot-name-exists/, model );
+			}, 'model-document-createroot-name-exists', model );
 		} );
 	} );
 

+ 2 - 2
packages/ckeditor5-engine/tests/model/markercollection.js

@@ -127,7 +127,7 @@ describe( 'MarkerCollection', () => {
 		it( 'should throw if marker name with "," is added', () => {
 			expectToThrowCKEditorError( () => {
 				markers._set( 'foo,bar', range );
-			}, /^markercollection-incorrect-marker-name:/, markers );
+			}, 'markercollection-incorrect-marker-name', markers );
 		} );
 	} );
 
@@ -215,7 +215,7 @@ describe( 'MarkerCollection', () => {
 		it( 'should throw if marker does not exist', () => {
 			expectToThrowCKEditorError( () => {
 				markers._refresh( 'name' );
-			}, /^markercollection-refresh-marker-not-exists:/, markers );
+			}, 'markercollection-refresh-marker-not-exists', markers );
 		} );
 	} );
 

+ 2 - 0
packages/ckeditor5-engine/tests/model/model.js

@@ -339,6 +339,7 @@ describe( 'Model', () => {
 		it( 'should throw the original CKEditorError error if it was thrown inside the `change()` block', () => {
 			expectToThrowCKEditorError( () => {
 				model.change( () => {
+					// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
 					throw new CKEditorError( 'foo', null, { foo: 1 } );
 				} );
 			}, /foo/, null, { foo: 1 } );
@@ -355,6 +356,7 @@ describe( 'Model', () => {
 		} );
 
 		it( 'should throw the original CKEditorError error if it was thrown inside the `enqueueChange()` block', () => {
+			// eslint-disable-next-line ckeditor5-rules/ckeditor-error-message
 			const err = new CKEditorError( 'foo', null, { foo: 1 } );
 
 			expectToThrowCKEditorError( () => {

+ 1 - 1
packages/ckeditor5-engine/tests/model/nodelist.js

@@ -160,7 +160,7 @@ describe( 'NodeList', () => {
 		it( 'should throw if not a Node is inserted', () => {
 			expectToThrowCKEditorError( () => {
 				nodes._insertNodes( 0, [ 'foo' ] );
-			}, /nodelist-insertNodes-not-node/, nodes );
+			}, 'nodelist-insertnodes-not-node', nodes );
 		} );
 	} );
 

+ 1 - 1
packages/ckeditor5-engine/tests/model/operation/operation.js

@@ -39,7 +39,7 @@ describe( 'Operation', () => {
 			} );
 		} );
 
-		it( 'should create proper json object #1', () => {
+		it( 'should create proper json object #2', () => {
 			const op = new Operation( 4 );
 			const batch = new Batch();
 			batch.addOperation( op );

+ 0 - 39
packages/ckeditor5-engine/tests/model/operation/transform.js

@@ -1771,45 +1771,6 @@ describe( 'transform', () => {
 				expectOperation( transOp[ 2 ], expected );
 			} );
 
-			it( 'range intersects on right side of transforming range and is important: shrink range', () => {
-				const transformBy = new MoveOperation(
-					new Position( root, [ 2, 2, 5 ] ),
-					2,
-					new Position( root, [ 4, 1, 0 ] ),
-					0
-				);
-
-				const transOp = transform( op, transformBy );
-
-				expected.howMany = 1;
-
-				expect( transOp.length ).to.equal( 1 );
-				expectOperation( transOp[ 0 ], expected );
-			} );
-
-			it( 'range intersects on right side of transforming range and is less important: split into two operations', () => {
-				const transformBy = new MoveOperation(
-					new Position( root, [ 2, 2, 5 ] ),
-					2,
-					new Position( root, [ 4, 1, 0 ] ),
-					0
-				);
-
-				const transOp = transform( op, transformBy, strongContext );
-
-				expect( transOp.length ).to.equal( 2 );
-
-				expected.sourcePosition = sourcePosition;
-				expected.howMany = 1;
-
-				expectOperation( transOp[ 0 ], expected );
-
-				expected.sourcePosition = new Position( root, [ 4, 1, 0 ] );
-				expected.targetPosition = targetPosition.getShiftedBy( 1 );
-
-				expectOperation( transOp[ 1 ], expected );
-			} );
-
 			it( 'range intersects, target inside transforming range and is important: split into two operations', () => {
 				op.targetPosition.path = [ 2, 2, 7 ];
 

+ 12 - 12
packages/ckeditor5-engine/tests/model/position.js

@@ -158,7 +158,7 @@ describe( 'Position', () => {
 			it( 'should throw if no offset is passed', () => {
 				expectToThrowCKEditorError( () => {
 					Position._createAt( ul );
-				}, /model-createPositionAt-offset-required/, model );
+				}, 'model-createpositionat-offset-required', model );
 			} );
 
 			it( 'should create positions from positions', () => {
@@ -321,7 +321,7 @@ describe( 'Position', () => {
 
 			expectToThrowCKEditorError( () => {
 				position.parent;
-			}, /^model-position-path-incorrect:/, position, { position } );
+			}, 'model-position-path-incorrect', position, { position } );
 		} );
 
 		it( 'should throw when based on a path, the parent would be a text node', () => {
@@ -330,7 +330,7 @@ describe( 'Position', () => {
 
 			expectToThrowCKEditorError( () => {
 				position.parent;
-			}, /^model-position-path-incorrect:/, position, { position } );
+			}, 'model-position-path-incorrect', position, { position } );
 		} );
 	} );
 
@@ -388,7 +388,7 @@ describe( 'Position', () => {
 
 			expectToThrowCKEditorError( () => {
 				position.index;
-			}, /^model-position-path-incorrect:/, position, { position } );
+			}, 'model-position-path-incorrect', position, { position } );
 		} );
 	} );
 
@@ -419,7 +419,7 @@ describe( 'Position', () => {
 
 			expectToThrowCKEditorError( () => {
 				position.nodeBefore;
-			}, /^model-nodelist-offset-out-of-bounds:/, position );
+			}, 'model-nodelist-offset-out-of-bounds', position );
 		} );
 	} );
 
@@ -450,7 +450,7 @@ describe( 'Position', () => {
 
 			expectToThrowCKEditorError( () => {
 				position.nodeAfter;
-			}, /^model-nodelist-offset-out-of-bounds:/, position );
+			}, 'model-nodelist-offset-out-of-bounds', position );
 		} );
 	} );
 
@@ -486,7 +486,7 @@ describe( 'Position', () => {
 
 			expectToThrowCKEditorError( () => {
 				position.textNode;
-			}, /^model-nodelist-offset-out-of-bounds:/, position );
+			}, 'model-nodelist-offset-out-of-bounds', position );
 		} );
 	} );
 
@@ -615,7 +615,7 @@ describe( 'Position', () => {
 			expect( positionB.isTouching( positionA ) ).to.be.false;
 		} );
 
-		it( 'should return false if there are whole nodes between positions', () => {
+		it( 'should return false if there are whole nodes between positions (same depth, but deeper)', () => {
 			const positionA = new Position( root, [ 1, 0, 3 ] );
 			const positionB = new Position( root, [ 1, 1, 1 ] );
 
@@ -1255,9 +1255,9 @@ describe( 'Position', () => {
 
 			root._appendChild( p );
 
-			const postion = new Position( root, [ 0, 3 ] ); // <p>foo^bar</p>
+			const position = new Position( root, [ 0, 3 ] ); // <p>foo^bar</p>
 
-			testAncestor( postion, postion, p );
+			testAncestor( position, position, p );
 		} );
 
 		it( 'for two positions in the same element returns the element', () => {
@@ -1284,9 +1284,9 @@ describe( 'Position', () => {
 
 			root._appendChild( p );
 
-			const postion = new Position( root, [ 0, 0 ] ); // <p>^<a></a></p>
+			const position = new Position( root, [ 0, 0 ] ); // <p>^<a></a></p>
 
-			testAncestor( postion, postion, p );
+			testAncestor( position, position, p );
 		} );
 
 		it( 'works fine with positions located in DocumentFragment', () => {

+ 32 - 34
packages/ckeditor5-engine/tests/model/schema.js

@@ -62,7 +62,7 @@ describe( 'Schema', () => {
 
 			expectToThrowCKEditorError( () => {
 				schema.register( 'foo' );
-			}, /^schema-cannot-register-item-twice:/, schema );
+			}, 'schema-cannot-register-item-twice', schema );
 		} );
 	} );
 
@@ -91,7 +91,7 @@ describe( 'Schema', () => {
 		it( 'throws when trying to extend a not yet registered item', () => {
 			expectToThrowCKEditorError( () => {
 				schema.extend( 'foo' );
-			}, /^schema-cannot-extend-missing-item:/, schema );
+			}, 'schema-cannot-extend-missing-item', schema );
 		} );
 	} );
 
@@ -960,7 +960,7 @@ describe( 'Schema', () => {
 
 			expectToThrowCKEditorError( () => {
 				expect( schema.checkMerge( position ) );
-			}, /^schema-check-merge-no-element-before:/, schema );
+			}, 'schema-check-merge-no-element-before', schema );
 		} );
 
 		it( 'throws an error if the node before the position is not the element', () => {
@@ -978,7 +978,7 @@ describe( 'Schema', () => {
 
 			expectToThrowCKEditorError( () => {
 				expect( schema.checkMerge( position ) );
-			}, /^schema-check-merge-no-element-before:/, schema );
+			}, 'schema-check-merge-no-element-before', schema );
 		} );
 
 		it( 'throws an error if there is no element after the position', () => {
@@ -995,7 +995,7 @@ describe( 'Schema', () => {
 
 			expectToThrowCKEditorError( () => {
 				expect( schema.checkMerge( position ) );
-			}, /^schema-check-merge-no-element-after:/, schema );
+			}, 'schema-check-merge-no-element-after', schema );
 		} );
 
 		it( 'throws an error if the node after the position is not the element', () => {
@@ -1013,7 +1013,7 @@ describe( 'Schema', () => {
 
 			expectToThrowCKEditorError( () => {
 				expect( schema.checkMerge( position ) );
-			}, /^schema-check-merge-no-element-before:/, schema );
+			}, 'schema-check-merge-no-element-before', schema );
 		} );
 
 		// This is an invalid case by definition – the baseElement should not contain disallowed elements
@@ -2509,7 +2509,7 @@ describe( 'Schema', () => {
 				expect( schema.checkChild( root1, r1p1 ) ).to.be.true;
 			} );
 
-			it( 'passes $root>paragraph>$text – paragraph inherits allowIn from $block through $block\'s allowWhere', () => {
+			it( 'passes $root>paragraph>$text – paragraph inherits allowed content from $block through $block\'s allowContentOf', () => {
 				schema.register( '$root' );
 				schema.register( '$blockProto' );
 				schema.register( '$block', {
@@ -2525,6 +2525,31 @@ describe( 'Schema', () => {
 
 				expect( schema.checkChild( r1p1, r1p1.getChild( 0 ) ) ).to.be.true;
 			} );
+
+			it( 'passes paragraph[align] – paragraph inherits attributes of $block', () => {
+				schema.register( '$block', {
+					allowAttributes: 'align'
+				} );
+				schema.register( 'paragraph', {
+					inheritAllFrom: '$block'
+				} );
+
+				expect( schema.checkAttribute( r1p1, 'align' ) ).to.be.true;
+			} );
+
+			it( 'passes paragraph[align] – paragraph inherits attributes of $block through allowAttributesOf', () => {
+				schema.register( '$blockProto', {
+					allowAttributes: 'align'
+				} );
+				schema.register( '$block', {
+					allowAttributesOf: '$blockProto'
+				} );
+				schema.register( 'paragraph', {
+					inheritAllFrom: '$block'
+				} );
+
+				expect( schema.checkAttribute( r1p1, 'align' ) ).to.be.true;
+			} );
 		} );
 
 		// We need to handle cases where some independent features registered definitions which might use
@@ -2669,33 +2694,6 @@ describe( 'Schema', () => {
 			// However, those situations are rather theoretical, so we're not going to waste time on them now.
 		} );
 
-		describe( 'inheritAllFrom', () => {
-			it( 'passes paragraph[align] – paragraph inherits attributes of $block', () => {
-				schema.register( '$block', {
-					allowAttributes: 'align'
-				} );
-				schema.register( 'paragraph', {
-					inheritAllFrom: '$block'
-				} );
-
-				expect( schema.checkAttribute( r1p1, 'align' ) ).to.be.true;
-			} );
-
-			it( 'passes paragraph[align] – paragraph inherits attributes of $block through allowAttributesOf', () => {
-				schema.register( '$blockProto', {
-					allowAttributes: 'align'
-				} );
-				schema.register( '$block', {
-					allowAttributesOf: '$blockProto'
-				} );
-				schema.register( 'paragraph', {
-					inheritAllFrom: '$block'
-				} );
-
-				expect( schema.checkAttribute( r1p1, 'align' ) ).to.be.true;
-			} );
-		} );
-
 		describe( 'missing attribute definitions', () => {
 			it( 'does not crash when checking an attribute of a non-registered element', () => {
 				expect( schema.checkAttribute( r1p1, 'align' ) ).to.be.false;

+ 10 - 20
packages/ckeditor5-engine/tests/model/selection.js

@@ -123,7 +123,7 @@ describe( 'Selection', () => {
 			expectToThrowCKEditorError( () => {
 				// eslint-disable-next-line no-new
 				new Selection( {} );
-			}, /model-selection-setTo-not-selectable/ );
+			}, 'model-selection-setto-not-selectable' );
 		} );
 	} );
 
@@ -143,7 +143,12 @@ describe( 'Selection', () => {
 			expect( selection.is( 'model' ) ).to.be.false;
 			expect( selection.is( 'model:node' ) ).to.be.false;
 			expect( selection.is( '$text' ) ).to.be.false;
+			expect( selection.is( '$textProxy' ) ).to.be.false;
+			expect( selection.is( 'element' ) ).to.be.false;
 			expect( selection.is( 'element', 'paragraph' ) ).to.be.false;
+			expect( selection.is( 'documentSelection' ) ).to.be.false;
+			expect( selection.is( 'node' ) ).to.be.false;
+			expect( selection.is( 'rootElement' ) ).to.be.false;
 		} );
 	} );
 
@@ -302,13 +307,13 @@ describe( 'Selection', () => {
 		it( 'should throw an error when trying to set selection to not selectable', () => {
 			expectToThrowCKEditorError( () => {
 				selection.setTo( {} );
-			}, /model-selection-setTo-not-selectable/ );
+			}, 'model-selection-setto-not-selectable' );
 		} );
 
 		it( 'should throw an error when trying to set selection to not selectable #2', () => {
 			expectToThrowCKEditorError( () => {
 				selection.setTo();
-			}, /model-selection-setTo-not-selectable/ );
+			}, 'model-selection-setto-not-selectable' );
 		} );
 
 		it( 'should allow setting selection inside an element', () => {
@@ -374,7 +379,7 @@ describe( 'Selection', () => {
 			it( 'should throw if second parameter is not passed', () => {
 				expectToThrowCKEditorError( () => {
 					selection.setTo( root );
-				}, /model-selection-setTo-required-second-parameter/, model );
+				}, 'model-selection-setto-required-second-parameter', model );
 			} );
 
 			it( 'should set selection at given offset in given parent', () => {
@@ -460,7 +465,7 @@ describe( 'Selection', () => {
 
 			expectToThrowCKEditorError( () => {
 				selection.setFocus( endPos );
-			}, /model-selection-setFocus-no-ranges/, model );
+			}, 'model-selection-setfocus-no-ranges', model );
 		} );
 
 		it( 'modifies existing collapsed selection', () => {
@@ -826,21 +831,6 @@ describe( 'Selection', () => {
 		} );
 	} );
 
-	describe( 'is()', () => {
-		it( 'should return true for selection', () => {
-			expect( selection.is( 'selection' ) ).to.be.true;
-		} );
-
-		it( 'should return false for other values', () => {
-			expect( selection.is( 'documentSelection' ) ).to.be.false;
-			expect( selection.is( 'node' ) ).to.be.false;
-			expect( selection.is( '$text' ) ).to.be.false;
-			expect( selection.is( '$textProxy' ) ).to.be.false;
-			expect( selection.is( 'element' ) ).to.be.false;
-			expect( selection.is( 'rootElement' ) ).to.be.false;
-		} );
-	} );
-
 	describe( 'setTo - used to collapse at start', () => {
 		it( 'should collapse to start position and fire change event', () => {
 			selection.setTo( [ range2, range1, range3 ] );

+ 8 - 8
packages/ckeditor5-engine/tests/model/writer.js

@@ -2157,13 +2157,13 @@ describe( 'Writer', () => {
 		it( 'should throw if options.usingOperation is not defined', () => {
 			expectToThrowCKEditorError( () => {
 				addMarker( 'name' );
-			}, /^writer-addMarker-no-usingOperation/, model );
+			}, '^writer-addmarker-no-usingoperation', model );
 		} );
 
 		it( 'should throw if name and range is defined but options.usingOperation is not defined', () => {
 			expectToThrowCKEditorError( () => {
 				addMarker( 'name', { range } );
-			}, /^writer-addMarker-no-usingOperation/, model );
+			}, '^writer-addmarker-no-usingoperation', model );
 		} );
 
 		it( 'should add marker to the document marker collection', () => {
@@ -2215,7 +2215,7 @@ describe( 'Writer', () => {
 
 			expectToThrowCKEditorError( () => {
 				addMarker( 'name', { range: range2, usingOperation: false } );
-			}, /^writer-addMarker-marker-exists/, model );
+			}, 'writer-addmarker-marker-exists', model );
 		} );
 
 		it( 'should use operations when having set usingOperation to true', () => {
@@ -2235,13 +2235,13 @@ describe( 'Writer', () => {
 		it( 'should throw if marker with given name does not exist and range is not passed', () => {
 			expectToThrowCKEditorError( () => {
 				addMarker( 'name', { usingOperation: true } );
-			}, /^writer-addMarker-no-range/, model );
+			}, 'writer-addmarker-no-range', model );
 		} );
 
 		it( 'should throw if marker is set directly and range is not passed', () => {
 			expectToThrowCKEditorError( () => {
 				addMarker( 'name', { usingOperation: false } );
-			}, /^writer-addMarker-no-range/, model );
+			}, 'writer-addmarker-no-range', model );
 		} );
 
 		it( 'should throw when trying to use detached writer', () => {
@@ -2487,13 +2487,13 @@ describe( 'Writer', () => {
 			expectToThrowCKEditorError( () => {
 				addMarker( 'name', { range, usingOperation: false } );
 				updateMarker( 'name', {} );
-			}, /^writer-updateMarker-wrong-options/, model );
+			}, 'writer-updatemarker-wrong-options', model );
 		} );
 
 		it( 'should throw when marker provided by name does not exists', () => {
 			expectToThrowCKEditorError( () => {
 				updateMarker( 'name', { usingOperation: false } );
-			}, /^writer-updateMarker-marker-not-exists/, model );
+			}, 'writer-updatemarker-marker-not-exists', model );
 		} );
 
 		it( 'should only refresh the marker when there is no provided options to update', () => {
@@ -2540,7 +2540,7 @@ describe( 'Writer', () => {
 		it( 'should throw when trying to remove non existing marker', () => {
 			expectToThrowCKEditorError( () => {
 				removeMarker( 'name' );
-			}, /^writer-removeMarker-no-marker/, model );
+			}, 'writer-removemarker-no-marker', model );
 		} );
 
 		it( 'should throw when trying to use detached writer', () => {

+ 2 - 2
packages/ckeditor5-engine/tests/tickets/ckeditor5-692.js

@@ -41,7 +41,7 @@ describe( 'Bug ckeditor5#692', () => {
 
 	describe( 'DomConverter', () => {
 		// https://github.com/ckeditor/ckeditor5/issues/692 Scenario 1.
-		it( 'should handle space after inline filler at the end of container', () => {
+		it( 'should handle space after inline filler at the end of container (scenario 1)', () => {
 			setModelData( editor.model, '<paragraph>foo[]</paragraph>' );
 
 			// Create Bold attribute at the end of paragraph.
@@ -63,7 +63,7 @@ describe( 'Bug ckeditor5#692', () => {
 		} );
 
 		// https://github.com/ckeditor/ckeditor5/issues/692 Scenario 2.
-		it( 'should handle space after inline filler at the end of container', () => {
+		it( 'should handle space after inline filler at the end of container (scenario 2)', () => {
 			setModelData( editor.model, '<paragraph>[]foo</paragraph>' );
 
 			// Create Bold attribute at the end of paragraph.

+ 5 - 21
packages/ckeditor5-engine/tests/view/documentselection.js

@@ -80,16 +80,6 @@ describe( 'DocumentSelection', () => {
 			expect( selection.isBackward ).to.be.false;
 		} );
 
-		it( 'should be able to create a collapsed selection at the given position', () => {
-			const position = range1.start;
-			const selection = new DocumentSelection( position );
-
-			expect( Array.from( selection.getRanges() ).length ).to.equal( 1 );
-			expect( selection.getFirstRange().start ).to.deep.equal( position );
-			expect( selection.getFirstRange().end ).to.deep.equal( position );
-			expect( selection.isBackward ).to.be.false;
-		} );
-
 		it( 'should be able to create a selection from the other document selection', () => {
 			const otherSelection = new DocumentSelection( [ range2, range3 ], { backward: true } );
 			const selection = new DocumentSelection( otherSelection );
@@ -135,7 +125,7 @@ describe( 'DocumentSelection', () => {
 			expectToThrowCKEditorError( () => {
 				// eslint-disable-next-line no-new
 				new DocumentSelection( {} );
-			}, /view-selection-setTo-not-selectable/ );
+			}, 'view-selection-setto-not-selectable' );
 		} );
 	} );
 
@@ -207,7 +197,7 @@ describe( 'DocumentSelection', () => {
 
 			expectToThrowCKEditorError( () => {
 				documentSelection._setFocus( endPos );
-			}, /view-selection-setFocus-no-ranges/, documentSelection );
+			}, 'view-selection-setfocus-no-ranges', documentSelection );
 		} );
 
 		it( 'modifies existing collapsed selection', () => {
@@ -553,12 +543,6 @@ describe( 'DocumentSelection', () => {
 			expect( documentSelection.isEqual( otherSelection ) ).to.be.false;
 		} );
 
-		it( 'should return false if one selection is fake', () => {
-			const otherSelection = new DocumentSelection( null, { fake: true } );
-
-			expect( documentSelection.isEqual( otherSelection ) ).to.be.false;
-		} );
-
 		it( 'should return true if both selection are fake - DocumentSelection and Selection', () => {
 			const otherSelection = new Selection( range1, { fake: true } );
 			documentSelection._setTo( range1, { fake: true } );
@@ -818,7 +802,7 @@ describe( 'DocumentSelection', () => {
 
 				expectToThrowCKEditorError( () => {
 					otherSelection._setTo( {} );
-				}, /view-selection-setTo-not-selectable/ );
+				}, 'view-selection-setto-not-selectable' );
 			} );
 
 			it( 'should throw an error when trying to set to not selectable #2', () => {
@@ -826,7 +810,7 @@ describe( 'DocumentSelection', () => {
 
 				expectToThrowCKEditorError( () => {
 					otherSelection._setTo();
-				}, /view-selection-setTo-not-selectable/ );
+				}, 'view-selection-setto-not-selectable' );
 			} );
 		} );
 
@@ -870,7 +854,7 @@ describe( 'DocumentSelection', () => {
 
 				expectToThrowCKEditorError( () => {
 					documentSelection._setTo( foo );
-				}, /view-selection-setTo-required-second-parameter/, documentSelection );
+				}, 'view-selection-setto-required-second-parameter', documentSelection );
 			} );
 
 			it( 'should collapse selection at node and flag', () => {

+ 58 - 58
packages/ckeditor5-engine/tests/view/domconverter/dom-to-view.js

@@ -421,7 +421,7 @@ describe( 'DomConverter', () => {
 				expect( viewDiv.getChild( 0 ).getChild( 0 ).data ).to.equal( 'f o o' );
 			} );
 
-			function test( inputTexts, output ) {
+			function testTexts( inputTexts, output ) {
 				if ( typeof inputTexts == 'string' ) {
 					inputTexts = [ inputTexts ];
 				}
@@ -446,75 +446,75 @@ describe( 'DomConverter', () => {
 			}
 
 			// At the beginning.
-			test( '_x', ' x' );
-			test( '_ x', '  x' );
-			test( '_ _x', '   x' );
-			test( '_ _ x', '    x' );
+			testTexts( '_x', ' x' );
+			testTexts( '_ x', '  x' );
+			testTexts( '_ _x', '   x' );
+			testTexts( '_ _ x', '    x' );
 
 			// At the end.
-			test( 'x_', 'x ' );
-			test( 'x _', 'x  ' );
-			test( 'x __', 'x   ' );
-			test( 'x _ _', 'x    ' );
+			testTexts( 'x_', 'x ' );
+			testTexts( 'x _', 'x  ' );
+			testTexts( 'x __', 'x   ' );
+			testTexts( 'x _ _', 'x    ' );
 
 			// In the middle.
-			test( 'x x', 'x x' );
-			test( 'x _x', 'x  x' );
-			test( 'x _ x', 'x   x' );
-			test( 'x _ _x', 'x    x' );
+			testTexts( 'x x', 'x x' );
+			testTexts( 'x _x', 'x  x' );
+			testTexts( 'x _ x', 'x   x' );
+			testTexts( 'x _ _x', 'x    x' );
 
 			// Complex.
-			test( '_x_', ' x ' );
-			test( '_ x _x _', '  x  x  ' );
-			test( '_ _x x _', '   x x  ' );
-			test( '_ _x x __', '   x x   ' );
-			test( '_ _x _ _x_', '   x    x ' );
-			test( '_', ' ' );
+			testTexts( '_x_', ' x ' );
+			testTexts( '_ x _x _', '  x  x  ' );
+			testTexts( '_ _x x _', '   x x  ' );
+			testTexts( '_ _x x __', '   x x   ' );
+			testTexts( '_ _x _ _x_', '   x    x ' );
+			testTexts( '_', ' ' );
 
 			// With hard &nbsp;
-			test( '_x', ' x' );
-			test( '__x', ' _x' );
-			test( '___x', ' __x' );
-			test( '__ x', ' _ x' );
-
-			test( 'x_', 'x ' );
-			test( 'x__', 'x_ ' );
-			test( 'x___', 'x__ ' );
-
-			test( 'x_x', 'x_x' );
-			test( 'x___x', 'x___x' );
-			test( 'x____x', 'x____x' );
-			test( 'x__ x', 'x__ x' );
-			test( 'x___ x', 'x___ x' );
-			test( 'x_ _x', 'x_  x' );
-			test( 'x __x', 'x  _x' );
-			test( 'x _ x', 'x   x' );
-			test( 'x __ _x', 'x  _  x' );
+			testTexts( '_x', ' x' );
+			testTexts( '__x', ' _x' );
+			testTexts( '___x', ' __x' );
+			testTexts( '__ x', ' _ x' );
+
+			testTexts( 'x_', 'x ' );
+			testTexts( 'x__', 'x_ ' );
+			testTexts( 'x___', 'x__ ' );
+
+			testTexts( 'x_x', 'x_x' );
+			testTexts( 'x___x', 'x___x' );
+			testTexts( 'x____x', 'x____x' );
+			testTexts( 'x__ x', 'x__ x' );
+			testTexts( 'x___ x', 'x___ x' );
+			testTexts( 'x_ _x', 'x_  x' );
+			testTexts( 'x __x', 'x  _x' );
+			testTexts( 'x _ x', 'x   x' );
+			testTexts( 'x __ _x', 'x  _  x' );
 
 			// Two text nodes.
-			test( [ 'x', 'y' ], 'xy' );
-			test( [ 'x ', 'y' ], 'x y' );
-			test( [ 'x _', 'y' ], 'x  y' );
-			test( [ 'x __', 'y' ], 'x   y' );
-			test( [ 'x _  _', 'y' ], 'x    y' );
-
-			test( [ 'x', ' y' ], 'x y' );
-			test( [ 'x_', ' y' ], 'x  y' );
-			test( [ 'x _', ' y' ], 'x   y' );
-			test( [ 'x __', ' y' ], 'x    y' );
-			test( [ 'x _ _', ' y' ], 'x     y' );
-
-			test( [ 'x', ' _y' ], 'x  y' );
-			test( [ 'x_', ' _y' ], 'x   y' );
-			test( [ 'x _', ' _y' ], 'x    y' );
-			test( [ 'x __', ' _y' ], 'x     y' );
-			test( [ 'x _ _', ' _y' ], 'x      y' );
+			testTexts( [ 'x', 'y' ], 'xy' );
+			testTexts( [ 'x ', 'y' ], 'x y' );
+			testTexts( [ 'x _', 'y' ], 'x  y' );
+			testTexts( [ 'x __', 'y' ], 'x   y' );
+			testTexts( [ 'x _  _', 'y' ], 'x    y' );
+
+			testTexts( [ 'x', ' y' ], 'x y' );
+			testTexts( [ 'x_', ' y' ], 'x  y' );
+			testTexts( [ 'x _', ' y' ], 'x   y' );
+			testTexts( [ 'x __', ' y' ], 'x    y' );
+			testTexts( [ 'x _ _', ' y' ], 'x     y' );
+
+			testTexts( [ 'x', ' _y' ], 'x  y' );
+			testTexts( [ 'x_', ' _y' ], 'x   y' );
+			testTexts( [ 'x _', ' _y' ], 'x    y' );
+			testTexts( [ 'x __', ' _y' ], 'x     y' );
+			testTexts( [ 'x _ _', ' _y' ], 'x      y' );
 
 			// Some tests with hard &nbsp;
-			test( [ 'x', '_y' ], 'x_y' );
-			test( [ 'x_', 'y' ], 'x_y' );
-			test( [ 'x__', ' y' ], 'x_  y' );
-			test( [ 'x_ _', ' y' ], 'x_   y' );
+			testTexts( [ 'x', '_y' ], 'x_y' );
+			testTexts( [ 'x_', 'y' ], 'x_y' );
+			testTexts( [ 'x__', ' y' ], 'x_  y' );
+			testTexts( [ 'x_ _', ' y' ], 'x_   y' );
 
 			it( 'not in preformatted blocks', () => {
 				const domDiv = createElement( document, 'div', {}, [

+ 3 - 3
packages/ckeditor5-engine/tests/view/emptyelement.js

@@ -66,14 +66,14 @@ describe( 'EmptyElement', () => {
 
 		expectToThrowCKEditorError( () => {
 			new EmptyElement( document, 'img', null, [ el ] ); // eslint-disable-line no-new
-		}, 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.', el );
+		}, 'view-emptyelement-cannot-add', el );
 	} );
 
 	describe( '_appendChild', () => {
 		it( 'should throw when try to append new child element', () => {
 			expectToThrowCKEditorError( () => {
 				emptyElement._appendChild( element );
-			}, 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.', element );
+			}, 'view-emptyelement-cannot-add', element );
 		} );
 	} );
 
@@ -81,7 +81,7 @@ describe( 'EmptyElement', () => {
 		it( 'should throw when try to insert new child element', () => {
 			expectToThrowCKEditorError( () => {
 				emptyElement._insertChild( 0, element );
-			}, 'view-emptyelement-cannot-add: Cannot add child nodes to EmptyElement instance.', element );
+			}, 'view-emptyelement-cannot-add', element );
 		} );
 	} );
 

+ 1 - 1
packages/ckeditor5-engine/tests/view/node.js

@@ -214,7 +214,7 @@ describe( 'Node', () => {
 		} );
 	} );
 
-	describe( 'getIndex()', () => {
+	describe( '#index getter', () => {
 		it( 'should return null if the parent is null', () => {
 			expect( root.index ).to.be.null;
 		} );

Some files were not shown because too many files changed in this diff