8
0
Просмотр исходного кода

Merge tag 'v1.0.0-beta.1' into stable

Release: v1.0.0-beta.1.
Piotrek Koszuliński 7 лет назад
Родитель
Сommit
69f0d66b3a
100 измененных файлов с 1220 добавлено и 904 удалено
  1. 1 1
      packages/ckeditor5-core/.eslintrc.js
  2. 15 11
      packages/ckeditor5-core/.travis.yml
  3. 15 0
      packages/ckeditor5-core/CHANGELOG.md
  4. 1 1
      packages/ckeditor5-core/LICENSE.md
  5. 3 1
      packages/ckeditor5-core/README.md
  6. 1 1
      packages/ckeditor5-core/docs/api/core.md
  7. 1 1
      packages/ckeditor5-core/lang/translations/ast.po
  8. 1 1
      packages/ckeditor5-core/lang/translations/bg.po
  9. 1 1
      packages/ckeditor5-core/lang/translations/da.po
  10. 1 1
      packages/ckeditor5-core/lang/translations/de.po
  11. 1 1
      packages/ckeditor5-core/lang/translations/el.po
  12. 1 1
      packages/ckeditor5-core/lang/translations/en-au.po
  13. 1 1
      packages/ckeditor5-core/lang/translations/en.po
  14. 1 1
      packages/ckeditor5-core/lang/translations/eo.po
  15. 1 1
      packages/ckeditor5-core/lang/translations/es.po
  16. 14 0
      packages/ckeditor5-core/lang/translations/et.po
  17. 14 0
      packages/ckeditor5-core/lang/translations/eu.po
  18. 1 1
      packages/ckeditor5-core/lang/translations/fi.po
  19. 1 1
      packages/ckeditor5-core/lang/translations/fr.po
  20. 1 1
      packages/ckeditor5-core/lang/translations/gl.po
  21. 1 1
      packages/ckeditor5-core/lang/translations/hr.po
  22. 1 1
      packages/ckeditor5-core/lang/translations/hu.po
  23. 1 1
      packages/ckeditor5-core/lang/translations/it.po
  24. 1 1
      packages/ckeditor5-core/lang/translations/ja.po
  25. 1 1
      packages/ckeditor5-core/lang/translations/km.po
  26. 1 1
      packages/ckeditor5-core/lang/translations/kn.po
  27. 1 1
      packages/ckeditor5-core/lang/translations/ko.po
  28. 1 1
      packages/ckeditor5-core/lang/translations/ku.po
  29. 1 1
      packages/ckeditor5-core/lang/translations/nb.po
  30. 1 1
      packages/ckeditor5-core/lang/translations/ne.po
  31. 1 1
      packages/ckeditor5-core/lang/translations/nl.po
  32. 1 1
      packages/ckeditor5-core/lang/translations/oc.po
  33. 1 1
      packages/ckeditor5-core/lang/translations/pl.po
  34. 1 1
      packages/ckeditor5-core/lang/translations/pt-br.po
  35. 1 1
      packages/ckeditor5-core/lang/translations/pt.po
  36. 1 1
      packages/ckeditor5-core/lang/translations/ro.po
  37. 1 1
      packages/ckeditor5-core/lang/translations/ru.po
  38. 1 1
      packages/ckeditor5-core/lang/translations/sk.po
  39. 14 0
      packages/ckeditor5-core/lang/translations/sq.po
  40. 1 1
      packages/ckeditor5-core/lang/translations/sv.po
  41. 1 1
      packages/ckeditor5-core/lang/translations/tr.po
  42. 14 0
      packages/ckeditor5-core/lang/translations/tt.po
  43. 14 0
      packages/ckeditor5-core/lang/translations/ug.po
  44. 1 1
      packages/ckeditor5-core/lang/translations/uk.po
  45. 1 1
      packages/ckeditor5-core/lang/translations/zh-cn.po
  46. 1 1
      packages/ckeditor5-core/lang/translations/zh.po
  47. 17 17
      packages/ckeditor5-core/package.json
  48. 4 4
      packages/ckeditor5-core/src/command.js
  49. 8 4
      packages/ckeditor5-core/src/commandcollection.js
  50. 2 2
      packages/ckeditor5-core/src/editingkeystrokehandler.js
  51. 63 39
      packages/ckeditor5-core/src/editor/editor.js
  52. 38 1
      packages/ckeditor5-core/src/editor/editorconfig.jsdoc
  53. 1 1
      packages/ckeditor5-core/src/editor/editorui.jsdoc
  54. 31 0
      packages/ckeditor5-core/src/editor/editorwithui.jsdoc
  55. 0 175
      packages/ckeditor5-core/src/editor/standardeditor.js
  56. 63 0
      packages/ckeditor5-core/src/editor/utils/attachtoform.js
  57. 53 0
      packages/ckeditor5-core/src/editor/utils/dataapimixin.js
  58. 49 0
      packages/ckeditor5-core/src/editor/utils/elementapimixin.js
  59. 11 1
      packages/ckeditor5-core/src/plugin.js
  60. 7 3
      packages/ckeditor5-core/src/plugincollection.js
  61. 113 113
      packages/ckeditor5-core/tests/_utils-tests/articlepluginset.js
  62. 25 14
      packages/ckeditor5-core/tests/_utils-tests/classictesteditor.js
  63. 1 1
      packages/ckeditor5-core/tests/_utils-tests/classictesteditorui.js
  64. 1 1
      packages/ckeditor5-core/tests/_utils-tests/createsinonsandbox.js
  65. 26 10
      packages/ckeditor5-core/tests/_utils-tests/modeltesteditor.js
  66. 82 0
      packages/ckeditor5-core/tests/_utils-tests/utils.js
  67. 13 9
      packages/ckeditor5-core/tests/_utils-tests/virtualtesteditor.js
  68. 1 1
      packages/ckeditor5-core/tests/_utils/articlepluginset.js
  69. 21 8
      packages/ckeditor5-core/tests/_utils/classictesteditor.js
  70. 1 1
      packages/ckeditor5-core/tests/_utils/classictesteditorui.js
  71. 11 18
      packages/ckeditor5-core/tests/_utils/modeltesteditor.js
  72. 64 1
      packages/ckeditor5-core/tests/_utils/utils.js
  73. 13 9
      packages/ckeditor5-core/tests/_utils/virtualtesteditor.js
  74. 3 3
      packages/ckeditor5-core/tests/command.js
  75. 1 1
      packages/ckeditor5-core/tests/commandcollection.js
  76. 1 1
      packages/ckeditor5-core/tests/editingkeystrokehandler.js
  77. 57 10
      packages/ckeditor5-core/tests/editor/editor.js
  78. 0 385
      packages/ckeditor5-core/tests/editor/standardeditor.js
  79. 176 0
      packages/ckeditor5-core/tests/editor/utils/attachtoform.js
  80. 53 0
      packages/ckeditor5-core/tests/editor/utils/dataapimixin.js
  81. 47 0
      packages/ckeditor5-core/tests/editor/utils/elementapimixin.js
  82. 1 1
      packages/ckeditor5-core/tests/manual/article.html
  83. 3 3
      packages/ckeditor5-core/tests/manual/article.js
  84. 1 1
      packages/ckeditor5-core/tests/manual/formsubmit.js
  85. 6 6
      packages/ckeditor5-core/tests/manual/readonly.js
  86. 1 1
      packages/ckeditor5-core/tests/plugin.js
  87. 1 1
      packages/ckeditor5-core/tests/plugincollection.js
  88. 1 0
      packages/ckeditor5-core/theme/icons/cancel.svg
  89. 1 0
      packages/ckeditor5-core/theme/icons/check.svg
  90. 1 1
      packages/ckeditor5-core/theme/icons/image.svg
  91. 0 0
      packages/ckeditor5-core/theme/icons/input.svg
  92. 0 0
      packages/ckeditor5-core/theme/icons/low-vision.svg
  93. 1 1
      packages/ckeditor5-core/theme/icons/object-center.svg
  94. 1 1
      packages/ckeditor5-core/theme/icons/object-full-width.svg
  95. 1 1
      packages/ckeditor5-core/theme/icons/object-left.svg
  96. 1 1
      packages/ckeditor5-core/theme/icons/object-right.svg
  97. 1 0
      packages/ckeditor5-core/theme/icons/pencil.svg
  98. 0 1
      packages/ckeditor5-core/theme/icons/picker.svg
  99. 1 1
      packages/ckeditor5-core/theme/icons/quote.svg
  100. 0 1
      packages/ckeditor5-core/theme/icons/source.svg

+ 1 - 1
packages/ckeditor5-core/.eslintrc.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 15 - 11
packages/ckeditor5-core/.travis.yml

@@ -1,24 +1,28 @@
 sudo: required
 dist: trusty
 addons:
+  firefox: "latest"
   apt:
     sources:
-      - google-chrome
+    - google-chrome
     packages:
-      - google-chrome-stable
+    - google-chrome-stable
 language: node_js
 node_js:
-  - "6"
+- '6'
 cache:
-  - node_modules
+- node_modules
 before_install:
-  - export DISPLAY=:99.0
-  - sh -e /etc/init.d/xvfb start
+- export DISPLAY=:99.0
+- sh -e /etc/init.d/xvfb start
 install:
-  - npm install @ckeditor/ckeditor5-dev-tests
-  - ckeditor5-dev-tests-install-dependencies
+- npm install @ckeditor/ckeditor5-dev-tests
+- ckeditor5-dev-tests-install-dependencies
 script:
-  - ckeditor5-dev-tests-travis
+- ckeditor5-dev-tests-travis
 after_success:
-  - codeclimate-test-reporter < coverage/lcov.info
-  - ckeditor5-dev-tests-save-revision
+- ckeditor5-dev-tests-save-revision
+env:
+  global:
+  - secure: uJiLhULzhBDdkuQrYW7k7H4l4HizyfCdnV9ORe2HXyNnWFnFfAhc2vD1FQ5182ldQXtUQMX51gM/YL5r1Sa2IO3EW/j0gyuznqYvM8KX4lU1hXUAap1ZHW7Zb/leVQfU76IH688rkGcpr2SwCG6/LglqunozwhyePuxBzH23whSrf5dGXjswnMUAjouavtm+YybPZY81uj181aFY7nbcWOCUkx7FGaIg5WqG27kkYuUCVDw977hlwSevL6K1AF1OMtfHTAt4NR2oRKtpcRsrBlVNFFCraVa+3E1DN/kcEMaNDFJ4737Zta6jK9irGdfOwvtt1t4Og2fWKtUNCix2Almjiu0t58miuHhZenB4xRm4kpnc5nzfu0x/Ur4R95OHbKMf/6Zvvd/2v4bHe0iFihZXB8qiXvqZwqVyXCH2pWzj+tFztwpvyfj+Z1k4LIuo3shbG9GlK8mSl0OfL9WdSR/g09NBRg1aJtEKsJreensTEO9esJ5dD7JksKo6VsESSAztN4v5xuavtPM+yT2g2vFWpwyY0/6/yxR8hlIo0//24t8be9Lm+G3k1f++Jc6ea8aFYUPF+O6kdZgqD0g2LoAp5e28CjXkMDoq/0l+Ab0obpaMjZlyEZ+S8X+8+kyICpyADmLTWP/Mwmik8ixzABgBz0903w4aExOl8mEi9ws=
+  - secure: tVEuv/7HAhriDudbEP0+30DvPV04pI3XoW3ibHDVdI7qhjtNH4AnYcqJOtI25wZTYr8hUquqkFNM7nl4sSoPPHEgdLL/c9U1bLkmTfQD4l+e6OPL8V2D9qStnSvswDMevtoCAVep+yKU7tDwL+ppNZeC9SX4xigo8MMC0qKhgx/q2CWIOlDVURFbFeEss+RI6nn1nxO+1kyyiZ1O0hyh5Xkn2u9h5ihV3SAeAHfZyvKvhyii74jSjHBHiapKkwUr4WSUkmKwuaqA2OppZXiDf5ah5nbjh1kX8u90jN+1yFH0Aor+M1Qdejs8A5sg9spOU2L0OXlw1wiLj0gzrGEQH6wbTR2T8nyIYYpivnuPUh19WK6FCABCbH3baxJwpZdYrd87Oi2EAPDS8obpNc/fZEj5XrZBVIf8Tk9wvaDrB4JSsyjp8U8G5eKVrY++sRdCTGxpP1W9LJlkVSTW8weX1FWWo6OWnZGo7+Q6xd63wVZ7/dc0TU/h9Ck9ekTeOAU2/to71EnPZzU4Ydv5R/BK1VK0PUIIThosFIvd7UwrnVzmgndovIAfas+XhxgpJCWN+9pXPA46OfFNyYl8naiLdJqCOpl40tWNCE6T8rC60seTUSrDJwGEForCfr3eu2fkl0x5syc7eOimHHECBIGk4dE3TwwIg2kf6PUHMIT433M=

+ 15 - 0
packages/ckeditor5-core/CHANGELOG.md

@@ -1,6 +1,21 @@
 Changelog
 =========
 
+## [1.0.0-beta.1](https://github.com/ckeditor/ckeditor5-core/compare/v1.0.0-alpha.2...v1.0.0-beta.1) (2018-03-15)
+
+### Other changes
+
+* Moved `EditingController`, `DataController` and `EditingKeystrokeHandler` from `StandardEditor` to the `Editor` class. Closes [#110](https://github.com/ckeditor/ckeditor5-core/issues/110). ([5a2031e](https://github.com/ckeditor/ckeditor5-core/commit/5a2031e))
+* Removed the `StandardEditor` class in favor of `DataInterface` and `ElementInterface` mixins. Added `EditorWithUI` interface. Closes [#115](https://github.com/ckeditor/ckeditor5-core/issues/115). Closes [#113](https://github.com/ckeditor/ckeditor5-core/issues/113). Closes https://github.com/ckeditor/ckeditor5/issues/303. ([fe81992](https://github.com/ckeditor/ckeditor5-core/commit/fe81992))
+* `Command` should listen to `model.Document#event:change`. ([912570d](https://github.com/ckeditor/ckeditor5-core/commit/912570d))
+* Changed `config.lang` to `config.language` to align to the naming convention. ([8720973](https://github.com/ckeditor/ckeditor5-core/commit/8720973))
+* Removed `loadDataFromElement()` method from `ElementApiMixin`. Closes [#120](https://github.com/ckeditor/ckeditor5-core/issues/120). ([4976e10](https://github.com/ckeditor/ckeditor5-core/commit/4976e10))
+
+### BREAKING CHANGES
+
+* The `StandardEditor` class was removed. Use `Editor` class with `DataInterface` and `ElementInterface` mixins.
+
+
 ## [1.0.0-alpha.2](https://github.com/ckeditor/ckeditor5-core/compare/v1.0.0-alpha.1...v1.0.0-alpha.2) (2017-11-14)
 
 ### Other changes

+ 1 - 1
packages/ckeditor5-core/LICENSE.md

@@ -2,7 +2,7 @@ Software License Agreement
 ==========================
 
 **CKEditor 5 Core Editor Architecture** – https://github.com/ckeditor/ckeditor5-core <br>
-Copyright (c) 2003-2017, [CKSource](http://cksource.com) Frederico Knabben. All rights reserved.
+Copyright (c) 2003-2018, [CKSource](http://cksource.com) Frederico Knabben. All rights reserved.
 
 Licensed under the terms of any of the following licenses at your choice:
 

+ 3 - 1
packages/ckeditor5-core/README.md

@@ -4,7 +4,9 @@ CKEditor 5 core editor architecture
 [![Join the chat at https://gitter.im/ckeditor/ckeditor5](https://badges.gitter.im/ckeditor/ckeditor5.svg)](https://gitter.im/ckeditor/ckeditor5?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 [![npm version](https://badge.fury.io/js/%40ckeditor%2Fckeditor5-core.svg)](https://www.npmjs.com/package/@ckeditor/ckeditor5-core)
 [![Build Status](https://travis-ci.org/ckeditor/ckeditor5-core.svg?branch=master)](https://travis-ci.org/ckeditor/ckeditor5-core)
-[![Test Coverage](https://codeclimate.com/github/ckeditor/ckeditor5-core/badges/coverage.svg)](https://codeclimate.com/github/ckeditor/ckeditor5-core/coverage)
+[![BrowserStack Status](https://www.browserstack.com/automate/badge.svg?badge_key=d3hvenZqQVZERFQ5d09FWXdyT0ozVXhLaVltRFRjTTUyZGpvQWNmWVhUUT0tLUZqNlJ1YWRUd0RvdEVOaEptM1B2Q0E9PQ==--c9d3dee40b9b4471ff3fb516d9ecf8d09292c7e0)](https://www.browserstack.com/automate/public-build/d3hvenZqQVZERFQ5d09FWXdyT0ozVXhLaVltRFRjTTUyZGpvQWNmWVhUUT0tLUZqNlJ1YWRUd0RvdEVOaEptM1B2Q0E9PQ==--c9d3dee40b9b4471ff3fb516d9ecf8d09292c7e0)
+[![Coverage Status](https://coveralls.io/repos/github/ckeditor/ckeditor5-core/badge.svg?branch=master)](https://coveralls.io/github/ckeditor/ckeditor5-core?branch=master)
+<br>
 [![Dependency Status](https://david-dm.org/ckeditor/ckeditor5-core/status.svg)](https://david-dm.org/ckeditor/ckeditor5-core)
 [![devDependency Status](https://david-dm.org/ckeditor/ckeditor5-core/dev-status.svg)](https://david-dm.org/ckeditor/ckeditor5-core?type=dev)
 

+ 1 - 1
packages/ckeditor5-core/docs/api/core.md

@@ -12,7 +12,7 @@ Together with the {@link api/engine editing engine} and the {@link api/ui standa
 
 ## Documentation
 
-See the introduction to the {@link framework/guides/architecture/intro#Core-editor-architecture core editor's architecture}.
+See the introduction to the {@link framework/guides/architecture/intro#core-editor-architecture core editor's architecture}.
 
 You can also browse the API documentation of this package by using the module tree on the left.
 

+ 1 - 1
packages/ckeditor5-core/lang/translations/ast.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: ast\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/bg.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: bg\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/da.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: da\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/de.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: de\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/el.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: el\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/en-au.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: en_AU\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/en.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: \n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/eo.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: eo\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/es.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: es\n"

+ 14 - 0
packages/ckeditor5-core/lang/translations/et.po

@@ -0,0 +1,14 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language: et\n"
+"Language-Team: Estonian (https://www.transifex.com/ckeditor/teams/11143/et/)\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgctxt "Label for the Save button."
+msgid "Save"
+msgstr "Salvesta"
+
+msgctxt "Label for the Cancel button."
+msgid "Cancel"
+msgstr "Loobu"

+ 14 - 0
packages/ckeditor5-core/lang/translations/eu.po

@@ -0,0 +1,14 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language: eu\n"
+"Language-Team: Basque (https://www.transifex.com/ckeditor/teams/11143/eu/)\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgctxt "Label for the Save button."
+msgid "Save"
+msgstr "Gorde"
+
+msgctxt "Label for the Cancel button."
+msgid "Cancel"
+msgstr "Utzi"

+ 1 - 1
packages/ckeditor5-core/lang/translations/fi.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: fi\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/fr.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: fr\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/gl.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: gl\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/hr.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: hr\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/hu.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: hu\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/it.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: it\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/ja.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: ja\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/km.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: km\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/kn.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: kn\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/ko.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: ko\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/ku.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: ku\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/nb.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: nb\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/ne.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: ne_NP\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/nl.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: nl\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/oc.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: oc\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/pl.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: pl\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/pt-br.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: pt_BR\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/pt.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: pt\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/ro.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: ro\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/ru.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: ru\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/sk.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: sk\n"

+ 14 - 0
packages/ckeditor5-core/lang/translations/sq.po

@@ -0,0 +1,14 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language: sq\n"
+"Language-Team: Albanian (https://www.transifex.com/ckeditor/teams/11143/sq/)\n"
+"Plural-Forms: nplurals=2; plural=(n != 1);\n"
+
+msgctxt "Label for the Save button."
+msgid "Save"
+msgstr "Ruaje"
+
+msgctxt "Label for the Cancel button."
+msgid "Cancel"
+msgstr "Anulo"

+ 1 - 1
packages/ckeditor5-core/lang/translations/sv.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: sv\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/tr.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: tr\n"

+ 14 - 0
packages/ckeditor5-core/lang/translations/tt.po

@@ -0,0 +1,14 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language: tt\n"
+"Language-Team: Tatar (https://www.transifex.com/ckeditor/teams/11143/tt/)\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+msgctxt "Label for the Save button."
+msgid "Save"
+msgstr "Сакла"
+
+msgctxt "Label for the Cancel button."
+msgid "Cancel"
+msgstr ""

+ 14 - 0
packages/ckeditor5-core/lang/translations/ug.po

@@ -0,0 +1,14 @@
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+msgid ""
+msgstr ""
+"Language: ug\n"
+"Language-Team: Uighur (https://www.transifex.com/ckeditor/teams/11143/ug/)\n"
+"Plural-Forms: nplurals=1; plural=0;\n"
+
+msgctxt "Label for the Save button."
+msgid "Save"
+msgstr "ساقلاش"
+
+msgctxt "Label for the Cancel button."
+msgid "Cancel"
+msgstr "قالدۇرۇش"

+ 1 - 1
packages/ckeditor5-core/lang/translations/uk.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: uk\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/zh-cn.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: zh_CN\n"

+ 1 - 1
packages/ckeditor5-core/lang/translations/zh.po

@@ -1,4 +1,4 @@
-# Copyright (c) Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+# Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
 msgid ""
 msgstr ""
 "Language: zh_TW\n"

+ 17 - 17
packages/ckeditor5-core/package.json

@@ -1,31 +1,31 @@
 {
   "name": "@ckeditor/ckeditor5-core",
-  "version": "1.0.0-alpha.2",
+  "version": "1.0.0-beta.1",
   "description": "CKEditor 5 core editor architecture.",
   "keywords": [
     "ckeditor5",
     "ckeditor5-lib"
   ],
   "dependencies": {
-    "@ckeditor/ckeditor5-engine": "^1.0.0-alpha.2",
-    "@ckeditor/ckeditor5-utils": "^1.0.0-alpha.2"
+    "@ckeditor/ckeditor5-engine": "^1.0.0-beta.1",
+    "@ckeditor/ckeditor5-utils": "^1.0.0-beta.1"
   },
   "devDependencies": {
-    "@ckeditor/ckeditor5-autoformat": "^1.0.0-alpha.2",
-    "@ckeditor/ckeditor5-basic-styles": "^1.0.0-alpha.2",
-    "@ckeditor/ckeditor5-block-quote": "^1.0.0-alpha.2",
-    "@ckeditor/ckeditor5-editor-classic": "^1.0.0-alpha.2",
-    "@ckeditor/ckeditor5-essentials": "^1.0.0-alpha.2",
-    "@ckeditor/ckeditor5-heading": "^1.0.0-alpha.2",
-    "@ckeditor/ckeditor5-image": "^1.0.0-alpha.2",
-    "@ckeditor/ckeditor5-link": "^1.0.0-alpha.2",
-    "@ckeditor/ckeditor5-list": "^1.0.0-alpha.2",
-    "@ckeditor/ckeditor5-paragraph": "^1.0.0-alpha.2",
-    "@ckeditor/ckeditor5-ui": "^1.0.0-alpha.2",
-    "eslint": "^4.8.0",
-    "eslint-config-ckeditor5": "^1.0.6",
+    "@ckeditor/ckeditor5-autoformat": "^1.0.0-beta.1",
+    "@ckeditor/ckeditor5-basic-styles": "^1.0.0-beta.1",
+    "@ckeditor/ckeditor5-block-quote": "^1.0.0-beta.1",
+    "@ckeditor/ckeditor5-editor-classic": "^1.0.0-beta.1",
+    "@ckeditor/ckeditor5-essentials": "^1.0.0-beta.1",
+    "@ckeditor/ckeditor5-heading": "^1.0.0-beta.1",
+    "@ckeditor/ckeditor5-image": "^1.0.0-beta.1",
+    "@ckeditor/ckeditor5-link": "^1.0.0-beta.1",
+    "@ckeditor/ckeditor5-list": "^1.0.0-beta.1",
+    "@ckeditor/ckeditor5-paragraph": "^1.0.0-beta.1",
+    "@ckeditor/ckeditor5-ui": "^1.0.0-beta.1",
+    "eslint": "^4.15.0",
+    "eslint-config-ckeditor5": "^1.0.7",
     "husky": "^0.14.3",
-    "lint-staged": "^4.2.3"
+    "lint-staged": "^6.0.0"
   },
   "engines": {
     "node": ">=6.0.0",

+ 4 - 4
packages/ckeditor5-core/src/command.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -45,7 +45,7 @@ export default class Command {
 		 * For example, the `bold` command's value is whether the selection starts in a bolded text.
 		 * And the value of the `link` command may be an object with links details.
 		 *
-		 * It's possible for a command to have no value (e.g. for stateless actions such as `uploadImage`).
+		 * It's possible for a command to have no value (e.g. for stateless actions such as `imageUpload`).
 		 *
 		 * @observable
 		 * @readonly
@@ -66,7 +66,7 @@ export default class Command {
 		this.decorate( 'execute' );
 
 		// By default every command is refreshed when changes are applied to the model.
-		this.listenTo( this.editor.document, 'changesDone', () => {
+		this.listenTo( this.editor.model.document, 'change', () => {
 			this.refresh();
 		} );
 
@@ -99,7 +99,7 @@ export default class Command {
 	 * in this method.
 	 *
 	 * This method is automatically called when
-	 * {@link module:engine/model/document~Document#event:changesDone any changes are applied to the model}.
+	 * {@link module:engine/model/document~Document#event:change any changes are applied to the document}.
 	 */
 	refresh() {
 		this.isEnabled = true;

+ 8 - 4
packages/ckeditor5-core/src/commandcollection.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -70,7 +70,7 @@ export default class CommandCollection {
 	/**
 	 * Returns iterator of command names.
 	 *
-	 * @returns {Iterator.<String>}
+	 * @returns {Iterable.<String>}
 	 */
 	* names() {
 		yield* this._commands.keys();
@@ -79,14 +79,18 @@ export default class CommandCollection {
 	/**
 	 * Returns iterator of command instances.
 	 *
-	 * @returns {Iterator.<module:core/command~Command>}
+	 * @returns {Iterable.<module:core/command~Command>}
 	 */
 	* commands() {
 		yield* this._commands.values();
 	}
 
 	/**
-	 * Collection iterator.
+	 * Iterable interface.
+	 *
+	 * Returns `[ commandName, commandInstance ]` pairs.
+	 *
+	 * @returns {Iterable.<Array>}
 	 */
 	[ Symbol.iterator ]() {
 		return this._commands[ Symbol.iterator ]();

+ 2 - 2
packages/ckeditor5-core/src/editingkeystrokehandler.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -11,7 +11,7 @@ import KeystrokeHandler from '@ckeditor/ckeditor5-utils/src/keystrokehandler';
 
 /**
  * A keystroke handler for editor editing. Its instance is available
- * in {@link module:core/editor/standardeditor~StandardEditor#keystrokes} so plugins
+ * in {@link module:core/editor/editor~Editor#keystrokes} so plugins
  * can register their keystrokes.
  *
  * E.g. an undo plugin would do this:

+ 63 - 39
packages/ckeditor5-core/src/editor/editor.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -8,19 +8,26 @@
  */
 
 import Config from '@ckeditor/ckeditor5-utils/src/config';
+import EditingController from '@ckeditor/ckeditor5-engine/src/controller/editingcontroller';
 import PluginCollection from '../plugincollection';
 import CommandCollection from '../commandcollection';
 import Locale from '@ckeditor/ckeditor5-utils/src/locale';
 import DataController from '@ckeditor/ckeditor5-engine/src/controller/datacontroller';
-import Document from '@ckeditor/ckeditor5-engine/src/model/document';
+import Conversion from '@ckeditor/ckeditor5-engine/src/conversion/conversion';
+import Model from '@ckeditor/ckeditor5-engine/src/model/model';
+import EditingKeystrokeHandler from '../editingkeystrokehandler';
 
 import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
 import mix from '@ckeditor/ckeditor5-utils/src/mix';
 
 /**
- * Class representing a basic editor. It contains a base architecture, without much additional logic.
+ * Class representing the base of the editor. It is the API all plugins can expect to get when using `editor` property.
+ * It should be enough to implement editing part of feature (schema definition, conversion, commands, keystrokes, etc.).
+ * However it does not define editor UI, which is defined in {@link module:core/editor/editorwithui~EditorWithUI}.
  *
- * See also {@link module:core/editor/standardeditor~StandardEditor}.
+ * All editors implementation (like {@link module:editor-classic/classiceditor~ClassicEditor} or
+ * {@link module:editor-inline/inlineeditor~InlineEditor}) should extend this class. They can add their
+ * own methods and properties.
  *
  * @mixes module:utils/observablemixin~ObservableMixin
  */
@@ -63,7 +70,7 @@ export default class Editor {
 		 * @readonly
 		 * @member {module:utils/locale~Locale}
 		 */
-		this.locale = new Locale( this.config.get( 'lang' ) );
+		this.locale = new Locale( this.config.get( 'language' ) );
 
 		/**
 		 * Shorthand for {@link module:utils/locale~Locale#t}.
@@ -74,55 +81,70 @@ export default class Editor {
 		this.t = this.locale.t;
 
 		/**
-		 * The editor's model document.
+		 * Defines whether this editor is in read-only mode.
+		 *
+		 * In read-only mode the editor {@link #commands commands} are disabled so it is not possible
+		 * to modify document using them.
 		 *
-		 * The center of the editor's abstract data model. The document contains
-		 * {@link module:engine/model/document~Document#getRoot all editing roots},
-		 * {@link module:engine/model/document~Document#selection} and allows
-		 * applying changes to through the {@link module:engine/model/document~Document#batch batch interface}.
+		 * @observable
+		 * @member {Boolean} #isReadOnly
+		 */
+		this.set( 'isReadOnly', false );
+
+		/**
+		 * The editor's model.
 		 *
-		 * Besides the model document, the editor usually contains two controllers –
-		 * {@link #data data controller} and {@link #editing editing controller}.
-		 * The former is used e.g. when setting or retrieving editor data and contains a useful
-		 * set of methods for operating on the content. The latter controls user input and rendering
-		 * the content for editing.
+		 * The center of the editor's abstract data model.
 		 *
 		 * @readonly
-		 * @member {module:engine/model/document~Document}
+		 * @member {module:engine/model/model~Model}
 		 */
-		this.document = new Document();
+		this.model = new Model();
 
 		/**
 		 * The {@link module:engine/controller/datacontroller~DataController data controller}.
+		 * Used e.g. for setting or retrieving editor data.
 		 *
 		 * @readonly
 		 * @member {module:engine/controller/datacontroller~DataController}
 		 */
-		this.data = new DataController( this.document );
+		this.data = new DataController( this.model );
 
 		/**
-		 * Defines whether this editor is in read-only mode.
-		 *
-		 * In read-only mode the editor {@link #commands commands} are disabled so it is not possible
-		 * to modify document using them.
+		 * The {@link module:engine/controller/editingcontroller~EditingController editing controller}.
+		 * Controls user input and rendering the content for editing.
 		 *
-		 * @observable
-		 * @member {Boolean} #isReadOnly
+		 * @readonly
+		 * @member {module:engine/controller/editingcontroller~EditingController}
 		 */
-		this.set( 'isReadOnly', false );
+		this.editing = new EditingController( this.model );
+		this.editing.view.document.bind( 'isReadOnly' ).to( this );
 
 		/**
-		 * The {@link module:engine/controller/editingcontroller~EditingController editing controller}.
+		 * Conversion manager to which conversion dispatchers are registered. Used to add converters to the editor.
 		 *
-		 * This property is set by more specialized editor classes (such as {@link module:core/editor/standardeditor~StandardEditor}),
-		 * however, it's required for features to work as their engine-related parts will try to connect converters.
+		 * See {@link module:engine/conversion/conversion~Conversion#for} to learn how to use conversion helpers in order to
+		 * add converters to the editor.
 		 *
-		 * When defining a virtual editor class, like one working in Node.js, it's possible to plug a virtual
-		 * editing controller which only instantiates necessary properties, but without any observers and listeners.
+		 * @readonly
+		 * @member {module:engine/conversion/conversion~Conversion}
+		 */
+		this.conversion = new Conversion();
+
+		this.conversion.register( 'downcast', [ this.editing.downcastDispatcher, this.data.downcastDispatcher ] );
+		this.conversion.register( 'editingDowncast', [ this.editing.downcastDispatcher ] );
+		this.conversion.register( 'dataDowncast', [ this.data.downcastDispatcher ] );
+
+		this.conversion.register( 'upcast', [ this.data.upcastDispatcher ] );
+
+		/**
+		 * Instance of the {@link module:core/editingkeystrokehandler~EditingKeystrokeHandler}.
 		 *
 		 * @readonly
-		 * @member {module:engine/controller/editingcontroller~EditingController} #editing
+		 * @member {module:core/editingkeystrokehandler~EditingKeystrokeHandler}
 		 */
+		this.keystrokes = new EditingKeystrokeHandler( this );
+		this.keystrokes.listenTo( this.editing.view.document );
 	}
 
 	/**
@@ -174,8 +196,10 @@ export default class Editor {
 
 		return this.plugins.destroy()
 			.then( () => {
-				this.document.destroy();
+				this.model.destroy();
 				this.data.destroy();
+				this.editing.destroy();
+				this.keystrokes.destroy();
 			} );
 	}
 
@@ -225,12 +249,6 @@ mix( Editor, ObservableMixin );
  * @event pluginsReady
  */
 
-/**
- * Fired when the editor UI is ready. This event won't be fired if the editor has no UI.
- *
- * @event uiReady
- */
-
 /**
  * Fired when the data loaded to the editor is ready. If a specific editor doesn't load
  * any data initially, this event will be fired right before {@link #event:ready}.
@@ -239,9 +257,15 @@ mix( Editor, ObservableMixin );
  */
 
 /**
- * Fired when {@link #event:pluginsReady plugins}, {@link #event:uiReady UI} and {@link #event:dataReady data} and all additional
+ * Fired when {@link #event:pluginsReady plugins}, and {@link #event:dataReady data} and all additional
  * editor components are ready.
  *
+ * Note: This event is most useful for plugin developers. When integrating the editor with your website or
+ * application you do not have to listen to `editor#ready` because when the promise returned by the static
+ * {@link module:core/editor/editor~Editor.create `Editor.create()`} event is resolved, the editor is already ready.
+ * In fact, since the first moment when the editor instance is available to you is inside `then()`'s callback,
+ * you cannot even add a listener to the `editor#ready` event.
+ *
  * @event ready
  */
 

+ 38 - 1
packages/ckeditor5-core/src/editor/editorconfig.jsdoc

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -67,6 +67,11 @@
  *			removePlugins: [ 'Bold', 'Italic' ]
  *		};
  *
+ * **Note:** Be careful when removing plugins using `config.removePlugins` from CKEditor builds.
+ * If removed plugins were providing toolbar buttons, the default toolbar configuration included in a build
+ * will become invalid. In such case you need to provide the updated
+ * {@link module:core/editor/editorconfig~EditorConfig#toolbar toolbar configuration}.
+ *
  * @member {Array.<String>} module:core/editor/editorconfig~EditorConfig#removePlugins
  */
 
@@ -106,3 +111,35 @@
  *
  * @member {Array.<String>|Object} module:core/editor/editorconfig~EditorConfig#toolbar
  */
+
+/**
+ * Editor UI's language.
+ *
+ * The language code is defined in the [ISO 639-1](https://en.wikipedia.org/wiki/ISO_639-1) standard.
+ * CKEditor 5 currently supports around 20 languages and the number is growing.
+ *
+ * Note: You don't have to specify this option if your build is optimized for one language or if it's the default language
+ * (English is the default language for CDN builds).
+ *
+ * Simple usage:
+ *
+ *		ClassicEditor
+ *			.create( document.querySelector( '#editor' ), {
+ *				language: 'de'
+ *			} )
+ *			.then( editor => {
+ *				console.log( editor );
+ *			} )
+ *			.catch( error => {
+ *				console.error( error );
+ *			} );
+ *
+ * After this step you need to attach the corresponding translation file. Translation files are available at CDN for predefined builds:
+ *		`<script src="https://cdn.ckeditor.com/ckeditor5/[version.number]/[distribution]/lang/[lang].js"></script>`
+ *
+ * But you can add them manually by coping from the `node_modules/@ckeditor/ckeditor5-build-[name]/build/lang/[lang].js'`.
+ *
+ * Check the {@glink features/ui-language UI language guide} for more information about the localization options and translation process.
+ *
+ * @member {String} module:core/editor/editorconfig~EditorConfig#language
+ */

+ 1 - 1
packages/ckeditor5-core/src/editor/editorui.jsdoc

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 31 - 0
packages/ckeditor5-core/src/editor/editorwithui.jsdoc

@@ -0,0 +1,31 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @module core/editor/editorwithui
+ */
+
+/**
+ * Interface defining UI part of the editor. Most editor (like {@link module:editor-classic/classiceditor~ClassicEditor} or
+ * {@link module:editor-inline/inlineeditor~InlineEditor}) implements this interface, however it is not required to do so. Editors with external UI (i.e. Bootstrap based) or headless editor may not implement this interface. Keep it in mind when developing features.
+ *
+ * @interface EditorWithUI
+ */
+
+/**
+ * Editor UI instance.
+ *
+ * @readonly
+ * @member {module:core/editor/editorui~EditorUI} #ui
+ */
+
+/**
+ * Fired when the editor UI is ready.
+ *
+ * Fired after {@link module:core/editor/editor~Editor#event:pluginsReady}, before
+ * {@link module:core/editor/editor~Editor#event:dataReady}.
+ *
+ * @event uiReady
+ */

+ 0 - 175
packages/ckeditor5-core/src/editor/standardeditor.js

@@ -1,175 +0,0 @@
-/**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/**
- * @module core/editor/standardeditor
- */
-
-import Editor from './editor';
-import EditingKeystrokeHandler from '../editingkeystrokehandler';
-import EditingController from '@ckeditor/ckeditor5-engine/src/controller/editingcontroller';
-import isFunction from '@ckeditor/ckeditor5-utils/src/lib/lodash/isFunction';
-
-import getDataFromElement from '@ckeditor/ckeditor5-utils/src/dom/getdatafromelement';
-import setDataInElement from '@ckeditor/ckeditor5-utils/src/dom/setdatainelement';
-
-/**
- * Class representing a typical browser-based editor. It handles a single source element and
- * uses {@link module:engine/controller/editingcontroller~EditingController}.
- *
- * @extends module:core/editor/editor~Editor
- */
-export default class StandardEditor extends Editor {
-	/**
-	 * Creates a new instance of the standard editor.
-	 *
-	 * @param {HTMLElement} element The DOM element that will be the source
-	 * for the created editor.
-	 * @param {Object} config The editor config.
-	 */
-	constructor( element, config ) {
-		super( config );
-
-		/**
-		 * The element on which the editor has been initialized.
-		 *
-		 * @readonly
-		 * @member {HTMLElement}
-		 */
-		this.element = element;
-
-		// Documented in Editor.
-		this.editing = new EditingController( this.document );
-		this.editing.view.bind( 'isReadOnly' ).to( this );
-
-		/**
-		 * Instance of the {@link module:core/editingkeystrokehandler~EditingKeystrokeHandler}.
-		 *
-		 * @readonly
-		 * @member {module:core/editingkeystrokehandler~EditingKeystrokeHandler}
-		 */
-		this.keystrokes = new EditingKeystrokeHandler( this );
-
-		/**
-		 * Editor UI instance.
-		 *
-		 * This property is set by more specialized editor constructors. However, it's required
-		 * for plugins to work (their UI-related part will try to interact with editor UI),
-		 * so every editor class which is meant to work with default plugins should set this property.
-		 *
-		 * @readonly
-		 * @member {module:core/editor/editorui~EditorUI} #ui
-		 */
-
-		this.keystrokes.listenTo( this.editing.view );
-
-		this._attachToForm();
-	}
-
-	/**
-	 * @inheritDoc
-	 */
-	destroy() {
-		return Promise.resolve()
-			.then( () => this.keystrokes.destroy() )
-			.then( () => this.editing.destroy() )
-			.then( super.destroy() );
-	}
-
-	/**
-	 * Sets the data in the editor's main root.
-	 *
-	 * @param {*} data The data to load.
-	 */
-	setData( data ) {
-		this.data.set( data );
-	}
-
-	/**
-	 * Gets the data from the editor's main root.
-	 */
-	getData() {
-		return this.data.get();
-	}
-
-	/**
-	 * Updates the {@link #element editor element}'s content with the data.
-	 */
-	updateEditorElement() {
-		setDataInElement( this.element, this.getData() );
-	}
-
-	/**
-	 * Loads the data from the {@link #element editor element} to the main root.
-	 */
-	loadDataFromEditorElement() {
-		this.setData( getDataFromElement( this.element ) );
-	}
-
-	/**
-	 * Checks if editor is initialized on textarea element that belongs to a form. If yes - updates editor's element
-	 * contents before submitting the form.
-	 *
-	 * @private
-	 */
-	_attachToForm() {
-		const element = this.element;
-
-		// Only when replacing a textarea which is inside of a form element.
-		if ( element && element.tagName.toLowerCase() === 'textarea' && element.form ) {
-			let originalSubmit;
-			const form = element.form;
-			const onSubmit = () => this.updateEditorElement();
-
-			// Replace the original form#submit() to call a custom submit function first.
-			// Check if #submit is a function because the form might have an input named "submit".
-			if ( isFunction( form.submit ) ) {
-				originalSubmit = form.submit;
-
-				form.submit = () => {
-					onSubmit();
-					originalSubmit.apply( form );
-				};
-			}
-
-			// Update the replaced textarea with data before each form#submit event.
-			form.addEventListener( 'submit', onSubmit );
-
-			// Remove the submit listener and revert the original submit method on
-			// editor#destroy.
-			this.on( 'destroy', () => {
-				form.removeEventListener( 'submit', onSubmit );
-
-				if ( originalSubmit ) {
-					form.submit = originalSubmit;
-				}
-			} );
-		}
-	}
-
-	/**
-	 * Creates a standard editor instance.
-	 *
-	 * @param {HTMLElement} element See {@link module:core/editor/standardeditor~StandardEditor}'s param.
-	 * @param {Object} config The editor config. You can find the list of config options in
-	 * {@link module:core/editor/editorconfig~EditorConfig}.
-	 * @returns {Promise} Promise resolved once editor is ready.
-	 * @returns {module:core/editor/standardeditor~StandardEditor} return.editor The editor instance.
-	 */
-	static create( element, config ) {
-		return new Promise( resolve => {
-			const editor = new this( element, config );
-
-			resolve(
-				editor.initPlugins()
-					.then( () => {
-						editor.fire( 'dataReady' );
-						editor.fire( 'ready' );
-					} )
-					.then( () => editor )
-			);
-		} );
-	}
-}

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

@@ -0,0 +1,63 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+import isFunction from '@ckeditor/ckeditor5-utils/src/lib/lodash/isFunction';
+import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+
+/**
+ * @module core/editor/utils/attachtoform
+ */
+
+/**
+ * Checks if editor is initialized on textarea element that belongs to a form. If yes - updates editor's element
+ * contents before submitting the form.
+ *
+ * This helper requires {@link module:core/editor/utils/elementapimixin~ElementApi ElementApi interface}.
+ *
+ * @param {module:core/editor/editor~Editor} editor Editor instance.
+ */
+export default function attachToForm( editor ) {
+	if ( !isFunction( editor.updateElement ) ) {
+		/**
+		 * {@link module:core/editor/utils/elementapimixin~ElementApi ElementApi interface} is required.
+		 *
+		 * @error attachtoform-missing-elementapi-interface
+		 */
+		throw new CKEditorError( 'attachtoform-missing-elementapi-interface: ElementApi interface is required.' );
+	}
+
+	const element = editor.element;
+
+	// Only when replacing a textarea which is inside of a form element.
+	if ( element && element.tagName.toLowerCase() === 'textarea' && element.form ) {
+		let originalSubmit;
+		const form = element.form;
+		const onSubmit = () => editor.updateElement();
+
+		// Replace the original form#submit() to call a custom submit function first.
+		// Check if #submit is a function because the form might have an input named "submit".
+		if ( isFunction( form.submit ) ) {
+			originalSubmit = form.submit;
+
+			form.submit = () => {
+				onSubmit();
+				originalSubmit.apply( form );
+			};
+		}
+
+		// Update the replaced textarea with data before each form#submit event.
+		form.addEventListener( 'submit', onSubmit );
+
+		// Remove the submit listener and revert the original submit method on
+		// editor#destroy.
+		editor.on( 'destroy', () => {
+			form.removeEventListener( 'submit', onSubmit );
+
+			if ( originalSubmit ) {
+				form.submit = originalSubmit;
+			}
+		} );
+	}
+}

+ 53 - 0
packages/ckeditor5-core/src/editor/utils/dataapimixin.js

@@ -0,0 +1,53 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/**
+ * @module core/editor/utils/dataapimixin
+ */
+
+/**
+ * Implementation of the {@link module:core/editor/utils/dataapimixin~DataApi}.
+ *
+ * @mixin DataApiMixin
+ * @implements module:core/editor/utils/dataapimixin~DataApi
+ */
+const DataApiMixin = {
+	/**
+	 * @inheritDoc
+	 */
+	setData( data ) {
+		this.data.set( data );
+	},
+
+	/**
+	 * @inheritDoc
+	 */
+	getData() {
+		return this.data.get();
+	}
+};
+
+export default DataApiMixin;
+
+/**
+ * Interface for setting and getting data to/from the editor's main root element
+ * using the {@link module:core/editor/editor~Editor#data data pipeline}.
+ *
+ * @interface DataApi
+ */
+
+/**
+ * Sets the data in the editor's main root.
+ *
+ * @method #setData
+ * @param {String} data Input data.
+ */
+
+/**
+ * Gets the data from the editor's main root.
+ *
+ * @method #getData
+ * @returns {String} Output data.
+ */

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

@@ -0,0 +1,49 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+import setDataInElement from '@ckeditor/ckeditor5-utils/src/dom/setdatainelement';
+
+/**
+ * @module core/editor/utils/elementapimixin
+ */
+
+/**
+ * Implementation of the {@link module:core/editor/utils/elementapimixin~ElementApi}.
+ *
+ * @mixin ElementApiMixin
+ * @implements module:core/editor/utils/elementapimixin~ElementApi
+ */
+const ElementApiMixin = {
+	/**
+	 * @inheritDoc
+	 */
+	updateElement() {
+		setDataInElement( this.element, this.data.get() );
+	}
+};
+
+export default ElementApiMixin;
+
+/**
+ * Interface describing an editor which replaced a DOM element (was "initialized on an element").
+ *
+ * Such an editor should provide a method to
+ * {@link module:core/editor/utils/elementapimixin~ElementApi#updateElement update the replaced element with the current data}.
+ *
+ * @interface ElementApi
+ */
+
+/**
+ * The element on which the editor has been initialized.
+ *
+ * @readonly
+ * @member {HTMLElement} #element
+ */
+
+/**
+ * Updates the {@link #element editor element}'s content with the data.
+ *
+ * @method #updateElement
+ */

+ 11 - 1
packages/ckeditor5-core/src/plugin.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -24,6 +24,16 @@ export default class Plugin {
 		/**
 		 * The editor instance.
 		 *
+		 * Note that most editors implements {@link module:core/editor/editorwithui~EditorWithUI} interface in addition
+		 * to the base {@link module:core/editor/editor~Editor} interface. However, editors with external UI
+		 * (i.e. Bootstrap based) or headless editor may not implement {@link module:core/editor/editorwithui~EditorWithUI}
+		 * interface.
+		 *
+		 * Because of above, to make plugins more universal, it is recommended to split features into:
+		 *  - "Editing" part which use only {@link module:core/editor/editor~Editor} interface,
+		 *  - "UI" part which use both {@link module:core/editor/editor~Editor} interface and
+		 *  {@link module:core/editor/editorwithui~EditorWithUI} interface.
+		 *
 		 * @readonly
 		 * @member {module:core/editor/editor~Editor} #editor
 		 */

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

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -55,7 +55,11 @@ export default class PluginCollection {
 	}
 
 	/**
-	 * Collection iterator. Returns `[ PluginConstructor, pluginInstance ]` pairs.
+	 * Iterable interface.
+	 *
+	 * Returns `[ PluginConstructor, pluginInstance ]` pairs.
+	 *
+	 * @returns {Iterable.<Array>}
 	 */
 	* [ Symbol.iterator ]() {
 		for ( const entry of this._plugins ) {
@@ -116,7 +120,7 @@ export default class PluginCollection {
 			 * that you tried loading plugins by name. However, unlike CKEditor 4, CKEditor 5 does not implement a "plugin loader".
 			 * This means that CKEditor 5 does not know where to load the plugin modules from. Therefore, you need to
 			 * provide each plugin through reference (as a constructor function). Check out the examples in
-			 * {@glink builds/guides/integration/advanced-setup#Scenario-2-Building-from-source "Building from source"}.
+			 * {@glink builds/guides/integration/advanced-setup#scenario-2-building-from-source "Building from source"}.
 			 *
 			 * @error plugincollection-plugin-not-found
 			 * @param {Array.<String>} plugins The name of the plugins which could not be loaded.

+ 113 - 113
packages/ckeditor5-core/tests/_utils-tests/articlepluginset.js

@@ -1,113 +1,113 @@
-/**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* global document */
-
-import ArticlePluginSet from '../_utils/articlepluginset';
-import ClassicTestEditor from '../_utils/classictesteditor';
-
-import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
-import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
-import Autoformat from '@ckeditor/ckeditor5-autoformat/src/autoformat';
-import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
-import Heading from '@ckeditor/ckeditor5-heading/src/heading';
-import Image from '@ckeditor/ckeditor5-image/src/image';
-import ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption';
-import ImageStyle from '@ckeditor/ckeditor5-image/src/imagestyle';
-import ImageToolbar from '@ckeditor/ckeditor5-image/src/imagetoolbar';
-import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
-import Link from '@ckeditor/ckeditor5-link/src/link';
-import List from '@ckeditor/ckeditor5-list/src/list';
-
-import normalizeHtml from '@ckeditor/ckeditor5-utils/tests/_utils/normalizehtml';
-
-describe( 'ArticlePluginSet', () => {
-	let editor, editorElement;
-
-	beforeEach( () => {
-		editorElement = document.createElement( 'div' );
-		document.body.appendChild( editorElement );
-
-		return ClassicTestEditor.create( editorElement, { plugins: [ ArticlePluginSet ] } )
-			.then( newEditor => {
-				editor = newEditor;
-			} );
-	} );
-
-	afterEach( () => {
-		editor.destroy();
-
-		editorElement.remove();
-	} );
-
-	it( 'should be loaded', () => {
-		expect( editor.plugins.get( ArticlePluginSet ) ).to.be.instanceOf( ArticlePluginSet );
-	} );
-
-	it( 'should load all its dependencies', () => {
-		expect( editor.plugins.get( Essentials ) ).to.be.instanceOf( Essentials );
-
-		expect( editor.plugins.get( Paragraph ) ).to.be.instanceOf( Paragraph );
-		expect( editor.plugins.get( Autoformat ) ).to.be.instanceOf( Autoformat );
-		expect( editor.plugins.get( Bold ) ).to.be.instanceOf( Bold );
-		expect( editor.plugins.get( Heading ) ).to.be.instanceOf( Heading );
-		expect( editor.plugins.get( Image ) ).to.be.instanceOf( Image );
-		expect( editor.plugins.get( ImageCaption ) ).to.be.instanceOf( ImageCaption );
-		expect( editor.plugins.get( ImageStyle ) ).to.be.instanceOf( ImageStyle );
-		expect( editor.plugins.get( ImageToolbar ) ).to.be.instanceOf( ImageToolbar );
-		expect( editor.plugins.get( Italic ) ).to.be.instanceOf( Italic );
-		expect( editor.plugins.get( Link ) ).to.be.instanceOf( Link );
-		expect( editor.plugins.get( List ) ).to.be.instanceOf( List );
-	} );
-
-	it( 'loads data', () => {
-		const data =
-			'<h2>Heading 1</h2>' +
-			'<p>Paragraph</p>' +
-			'<p><strong>Bold</strong> <i>Italic</i> <a href="foo">Link</a></p>' +
-			'<ul>' +
-				'<li>UL List item 1</li>' +
-				'<li>UL List item 2</li>' +
-			'</ul>' +
-			'<ol>' +
-				'<li>OL List item 1</li>' +
-				'<li>OL List item 2</li>' +
-			'</ol>' +
-			'<figure class="image image-style-side">' +
-				'<img alt="bar" src="foo">' +
-				'<figcaption>Caption</figcaption>' +
-			'</figure>' +
-			'<blockquote>' +
-				'<p>Quote</p>' +
-				'<ul><li>Quoted UL List item 1</li></ul>' +
-			'</blockquote>';
-
-		// Can't use data twice due to https://github.com/ckeditor/ckeditor5-utils/issues/128.
-		const expectedOutput =
-			'<h2>Heading 1</h2>' +
-			'<p>Paragraph</p>' +
-			'<p><strong>Bold</strong> <i>Italic</i> <a href="foo">Link</a></p>' +
-			'<ul>' +
-				'<li>UL List item 1</li>' +
-				'<li>UL List item 2</li>' +
-			'</ul>' +
-			'<ol>' +
-				'<li>OL List item 1</li>' +
-				'<li>OL List item 2</li>' +
-			'</ol>' +
-			'<figure class="image image-style-side">' +
-				'<img alt="bar" src="foo"></img>' +
-				'<figcaption>Caption</figcaption>' +
-			'</figure>' +
-			'<blockquote>' +
-				'<p>Quote</p>' +
-				'<ul><li>Quoted UL List item 1</li></ul>' +
-			'</blockquote>';
-
-		editor.setData( data );
-
-		expect( normalizeHtml( editor.getData() ) ).to.equal( expectedOutput );
-	} );
-} );
+// /**
+//  * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+//  * For licensing, see LICENSE.md.
+//  */
+//
+// /* global document */
+//
+// import ArticlePluginSet from '../_utils/articlepluginset';
+// import ClassicTestEditor from '../_utils/classictesteditor';
+//
+// import Essentials from '@ckeditor/ckeditor5-essentials/src/essentials';
+// import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph';
+// import Autoformat from '@ckeditor/ckeditor5-autoformat/src/autoformat';
+// import Bold from '@ckeditor/ckeditor5-basic-styles/src/bold';
+// import Heading from '@ckeditor/ckeditor5-heading/src/heading';
+// import Image from '@ckeditor/ckeditor5-image/src/image';
+// import ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption';
+// import ImageStyle from '@ckeditor/ckeditor5-image/src/imagestyle';
+// import ImageToolbar from '@ckeditor/ckeditor5-image/src/imagetoolbar';
+// import Italic from '@ckeditor/ckeditor5-basic-styles/src/italic';
+// import Link from '@ckeditor/ckeditor5-link/src/link';
+// import List from '@ckeditor/ckeditor5-list/src/list';
+//
+// import normalizeHtml from '@ckeditor/ckeditor5-utils/tests/_utils/normalizehtml';
+//
+// describe( 'ArticlePluginSet', () => {
+// 	let editor, editorElement;
+//
+// 	beforeEach( () => {
+// 		editorElement = document.createElement( 'div' );
+// 		document.body.appendChild( editorElement );
+//
+// 		return ClassicTestEditor.create( editorElement, { plugins: [ ArticlePluginSet ] } )
+// 			.then( newEditor => {
+// 				editor = newEditor;
+// 			} );
+// 	} );
+//
+// 	afterEach( () => {
+// 		editor.destroy();
+//
+// 		editorElement.remove();
+// 	} );
+//
+// 	it( 'should be loaded', () => {
+// 		expect( editor.plugins.get( ArticlePluginSet ) ).to.be.instanceOf( ArticlePluginSet );
+// 	} );
+//
+// 	it( 'should load all its dependencies', () => {
+// 		expect( editor.plugins.get( Essentials ) ).to.be.instanceOf( Essentials );
+//
+// 		expect( editor.plugins.get( Paragraph ) ).to.be.instanceOf( Paragraph );
+// 		expect( editor.plugins.get( Autoformat ) ).to.be.instanceOf( Autoformat );
+// 		expect( editor.plugins.get( Bold ) ).to.be.instanceOf( Bold );
+// 		expect( editor.plugins.get( Heading ) ).to.be.instanceOf( Heading );
+// 		expect( editor.plugins.get( Image ) ).to.be.instanceOf( Image );
+// 		expect( editor.plugins.get( ImageCaption ) ).to.be.instanceOf( ImageCaption );
+// 		expect( editor.plugins.get( ImageStyle ) ).to.be.instanceOf( ImageStyle );
+// 		expect( editor.plugins.get( ImageToolbar ) ).to.be.instanceOf( ImageToolbar );
+// 		expect( editor.plugins.get( Italic ) ).to.be.instanceOf( Italic );
+// 		expect( editor.plugins.get( Link ) ).to.be.instanceOf( Link );
+// 		expect( editor.plugins.get( List ) ).to.be.instanceOf( List );
+// 	} );
+//
+// 	it( 'loads data', () => {
+// 		const data =
+// 			'<h2>Heading 1</h2>' +
+// 			'<p>Paragraph</p>' +
+// 			'<p><strong>Bold</strong> <i>Italic</i> <a href="foo">Link</a></p>' +
+// 			'<ul>' +
+// 				'<li>UL List item 1</li>' +
+// 				'<li>UL List item 2</li>' +
+// 			'</ul>' +
+// 			'<ol>' +
+// 				'<li>OL List item 1</li>' +
+// 				'<li>OL List item 2</li>' +
+// 			'</ol>' +
+// 			'<figure class="image image-style-side">' +
+// 				'<img alt="bar" src="foo">' +
+// 				'<figcaption>Caption</figcaption>' +
+// 			'</figure>' +
+// 			'<blockquote>' +
+// 				'<p>Quote</p>' +
+// 				'<ul><li>Quoted UL List item 1</li></ul>' +
+// 			'</blockquote>';
+//
+// 		// Can't use data twice due to https://github.com/ckeditor/ckeditor5-utils/issues/128.
+// 		const expectedOutput =
+// 			'<h2>Heading 1</h2>' +
+// 			'<p>Paragraph</p>' +
+// 			'<p><strong>Bold</strong> <i>Italic</i> <a href="foo">Link</a></p>' +
+// 			'<ul>' +
+// 				'<li>UL List item 1</li>' +
+// 				'<li>UL List item 2</li>' +
+// 			'</ul>' +
+// 			'<ol>' +
+// 				'<li>OL List item 1</li>' +
+// 				'<li>OL List item 2</li>' +
+// 			'</ol>' +
+// 			'<figure class="image image-style-side">' +
+// 				'<img alt="bar" src="foo"></img>' +
+// 				'<figcaption>Caption</figcaption>' +
+// 			'</figure>' +
+// 			'<blockquote>' +
+// 				'<p>Quote</p>' +
+// 				'<ul><li>Quoted UL List item 1</li></ul>' +
+// 			'</blockquote>';
+//
+// 		editor.setData( data );
+//
+// 		expect( normalizeHtml( editor.getData() ) ).to.equal( expectedOutput );
+// 	} );
+// } );

+ 25 - 14
packages/ckeditor5-core/tests/_utils-tests/classictesteditor.js

@@ -1,11 +1,11 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
 /* globals document */
 
-import StandardEditor from '../../src/editor/standardeditor';
+import Editor from '../../src/editor/editor';
 import ClassicTestEditor from '../../tests/_utils/classictesteditor';
 
 import Plugin from '../../src/plugin';
@@ -15,6 +15,10 @@ import ClassicTestEditorUI from '../../tests/_utils/classictesteditorui';
 import BoxedEditorUIView from '@ckeditor/ckeditor5-ui/src/editorui/boxed/boxededitoruiview';
 import InlineEditableUIView from '@ckeditor/ckeditor5-ui/src/editableui/inline/inlineeditableuiview';
 
+import DataApiMixin from '../../src/editor/utils/dataapimixin';
+import ElementApiMixin from '../../src/editor/utils/elementapimixin';
+import RootElement from '@ckeditor/ckeditor5-engine/src/model/rootelement';
+
 import { getData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 import testUtils from '../../tests/_utils/utils';
 
@@ -32,18 +36,11 @@ describe( 'ClassicTestEditor', () => {
 		it( 'creates an instance of editor', () => {
 			const editor = new ClassicTestEditor( editorElement, { foo: 1 } );
 
-			expect( editor ).to.be.instanceof( StandardEditor );
+			expect( editor ).to.be.instanceof( Editor );
 			expect( editor.config.get( 'foo' ) ).to.equal( 1 );
 			expect( editor.element ).to.equal( editorElement );
 			expect( editor.ui ).to.be.instanceOf( ClassicTestEditorUI );
 			expect( editor.ui.view ).to.be.instanceOf( BoxedEditorUIView );
-		} );
-
-		it( 'creates model and view roots', () => {
-			const editor = new ClassicTestEditor( editorElement );
-
-			expect( editor.document.getRoot() ).to.have.property( 'name', '$root' );
-			expect( editor.editing.view.getRoot() ).to.have.property( 'name', 'div' );
 			expect( editor.data.processor ).to.be.instanceof( HtmlDataProcessor );
 		} );
 
@@ -55,6 +52,20 @@ describe( 'ClassicTestEditor', () => {
 			expect( editor.ui.view.editableElement.tagName ).to.equal( 'DIV' );
 			expect( editor.ui.view.editableElement ).to.equal( editor.ui.view.editable.element );
 		} );
+
+		it( 'creates main root element', () => {
+			const editor = new ClassicTestEditor( editorElement );
+
+			expect( editor.model.document.getRoot( 'main' ) ).to.instanceof( RootElement );
+		} );
+
+		it( 'mixes DataApiMixin', () => {
+			expect( testUtils.isMixed( ClassicTestEditor, DataApiMixin ) ).to.true;
+		} );
+
+		it( 'mixes ElementApiMixin', () => {
+			expect( testUtils.isMixed( ClassicTestEditor, ElementApiMixin ) ).to.true;
+		} );
 	} );
 
 	describe( 'create()', () => {
@@ -68,7 +79,7 @@ describe( 'ClassicTestEditor', () => {
 				} );
 		} );
 
-		it( 'creates and initilizes the UI', () => {
+		it( 'creates and initializes the UI', () => {
 			return ClassicTestEditor.create( editorElement, { foo: 1 } )
 				.then( editor => {
 					expect( editor.ui ).to.be.instanceOf( ClassicTestEditorUI );
@@ -81,13 +92,13 @@ describe( 'ClassicTestEditor', () => {
 
 			class PluginTextInRoot extends Plugin {
 				init() {
-					this.editor.document.schema.allow( { name: '$text', inside: '$root' } );
+					this.editor.model.schema.extend( '$text', { allowIn: '$root' } );
 				}
 			}
 
 			return ClassicTestEditor.create( editorElement, { plugins: [ PluginTextInRoot ] } )
 				.then( editor => {
-					expect( getData( editor.document, { withoutSelection: true } ) ).to.equal( 'foo' );
+					expect( getData( editor.model, { withoutSelection: true } ) ).to.equal( 'foo' );
 				} );
 		} );
 
@@ -141,7 +152,7 @@ describe( 'ClassicTestEditor', () => {
 		it( 'destroys UI and calls super.destroy()', () => {
 			return ClassicTestEditor.create( editorElement, { foo: 1 } )
 				.then( editor => {
-					const superSpy = testUtils.sinon.spy( StandardEditor.prototype, 'destroy' );
+					const superSpy = testUtils.sinon.spy( Editor.prototype, 'destroy' );
 					const uiSpy = sinon.spy( editor.ui, 'destroy' );
 
 					return editor.destroy()

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

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

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

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 26 - 10
packages/ckeditor5-core/tests/_utils-tests/modeltesteditor.js

@@ -1,13 +1,16 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
 import Editor from '../../src/editor/editor';
+import EditingController from '@ckeditor/ckeditor5-engine/src/controller/editingcontroller';
 import ModelTestEditor from '../../tests/_utils/modeltesteditor';
 
 import Plugin from '../../src/plugin';
 import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
+import DataApiMixin from '../../src/editor/utils/dataapimixin';
+import RootElement from '@ckeditor/ckeditor5-engine/src/model/rootelement';
 
 import { getData, setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
 
@@ -21,15 +24,28 @@ describe( 'ModelTestEditor', () => {
 			const editor = new ModelTestEditor( { foo: 1 } );
 
 			expect( editor ).to.be.instanceof( Editor );
-
 			expect( editor.config.get( 'foo' ) ).to.equal( 1 );
+			expect( editor.data.processor ).to.be.instanceof( HtmlDataProcessor );
 		} );
 
-		it( 'creates model and view roots', () => {
+		it( 'should disable editing pipeline', () => {
+			const spy = sinon.spy( EditingController.prototype, 'destroy' );
 			const editor = new ModelTestEditor( { foo: 1 } );
 
-			expect( editor.document.getRoot() ).to.have.property( 'name', '$root' );
-			expect( editor.data.processor ).to.be.instanceof( HtmlDataProcessor );
+			sinon.assert.calledOnce( spy );
+
+			spy.restore();
+			return editor.destroy();
+		} );
+
+		it( 'creates main root element', () => {
+			const editor = new ModelTestEditor();
+
+			expect( editor.model.document.getRoot( 'main' ) ).to.instanceof( RootElement );
+		} );
+
+		it( 'mixes DataApiMixin', () => {
+			expect( testUtils.isMixed( ModelTestEditor, DataApiMixin ) ).to.true;
 		} );
 	} );
 
@@ -76,16 +92,16 @@ describe( 'ModelTestEditor', () => {
 				.then( newEditor => {
 					editor = newEditor;
 
-					editor.document.schema.allow( { name: '$text', inside: '$root' } );
+					editor.model.schema.extend( '$text', { allowIn: '$root' } );
 				} );
 		} );
 
 		it( 'should set data of the first root', () => {
-			editor.document.createRoot( '$root', 'secondRoot' );
+			editor.model.document.createRoot( '$root', 'secondRoot' );
 
 			editor.setData( 'foo' );
 
-			expect( getData( editor.document, { rootName: 'main', withoutSelection: true } ) ).to.equal( 'foo' );
+			expect( getData( editor.model, { rootName: 'main', withoutSelection: true } ) ).to.equal( 'foo' );
 		} );
 	} );
 
@@ -97,12 +113,12 @@ describe( 'ModelTestEditor', () => {
 				.then( newEditor => {
 					editor = newEditor;
 
-					editor.document.schema.allow( { name: '$text', inside: '$root' } );
+					editor.model.schema.extend( '$text', { allowIn: '$root' } );
 				} );
 		} );
 
 		it( 'should set data of the first root', () => {
-			setData( editor.document, 'foo' );
+			setData( editor.model, 'foo' );
 
 			expect( editor.getData() ).to.equal( 'foo' );
 		} );

+ 82 - 0
packages/ckeditor5-core/tests/_utils-tests/utils.js

@@ -0,0 +1,82 @@
+/**
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+import testUtils from '../_utils/utils';
+import mix from '@ckeditor/ckeditor5-utils/src/mix';
+
+testUtils.createSinonSandbox();
+
+describe( 'utils', () => {
+	describe( 'checkAssertions()', () => {
+		it( 'does not throw an error if at least one assertion passed', () => {
+			const assertionRed = testUtils.sinon.stub().callsFake( () => {
+				expect( 1 ).to.equal( 2 );
+			} );
+			const assertionGreen = testUtils.sinon.stub().callsFake( () => {
+				expect( 1 ).to.equal( 1 );
+			} );
+
+			expect( () => {
+				testUtils.checkAssertions( assertionRed, assertionGreen );
+			} ).to.not.throw();
+		} );
+
+		it( 'throws all errors if any assertion did not pass', () => {
+			const assertionRed = testUtils.sinon.stub().callsFake( () => {
+				expect( 1 ).to.equal( 2 );
+			} );
+			const assertionGreen = testUtils.sinon.stub().callsFake( () => {
+				expect( 2 ).to.equal( 1 );
+			} );
+
+			expect( () => {
+				testUtils.checkAssertions( assertionRed, assertionGreen );
+			} ).to.throw( Error, 'expected 1 to equal 2\n\nexpected 2 to equal 1' );
+		} );
+
+		it( 'does not execute all assertions if the first one passed', () => {
+			const assertionRed = testUtils.sinon.stub().callsFake( () => {
+				expect( 1 ).to.equal( 1 );
+			} );
+			const assertionGreen = testUtils.sinon.stub();
+
+			testUtils.checkAssertions( assertionRed, assertionGreen );
+			expect( assertionGreen.called ).to.equal( false );
+		} );
+	} );
+
+	describe( 'isMixed()', () => {
+		let mixin, CustomClass;
+
+		beforeEach( () => {
+			CustomClass = class {};
+			mixin = {
+				foo() {
+					return 'bar';
+				}
+			};
+		} );
+
+		it( 'should return true when given mixin is mixed to target class', () => {
+			mix( CustomClass, mixin );
+
+			expect( testUtils.isMixed( CustomClass, mixin ) ).to.true;
+		} );
+
+		it( 'should return false when given mixin is not mixed to target class', () => {
+			expect( testUtils.isMixed( CustomClass, mixin ) ).to.false;
+		} );
+
+		it( 'should return false when class has mixin like interface', () => {
+			CustomClass = class {
+				foo() {
+					return 'biz';
+				}
+			};
+
+			expect( testUtils.isMixed( CustomClass, mixin ) ).to.false;
+		} );
+	} );
+} );

+ 13 - 9
packages/ckeditor5-core/tests/_utils-tests/virtualtesteditor.js

@@ -1,13 +1,15 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
-import StandardEditor from '../../src/editor/standardeditor';
+import Editor from '../../src/editor/editor';
 import VirtualTestEditor from '../../tests/_utils/virtualtesteditor';
 
 import Plugin from '../../src/plugin';
 import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
+import DataApiMixin from '../../src/editor/utils/dataapimixin';
+import RootElement from '@ckeditor/ckeditor5-engine/src/model/rootelement';
 
 import testUtils from '../../tests/_utils/utils';
 
@@ -18,17 +20,19 @@ describe( 'VirtualTestEditor', () => {
 		it( 'creates an instance of editor', () => {
 			const editor = new VirtualTestEditor( { foo: 1 } );
 
-			expect( editor ).to.be.instanceof( StandardEditor );
-
+			expect( editor ).to.be.instanceof( Editor );
+			expect( editor.data.processor ).to.be.instanceof( HtmlDataProcessor );
 			expect( editor.config.get( 'foo' ) ).to.equal( 1 );
 		} );
 
-		it( 'creates model and view roots', () => {
-			const editor = new VirtualTestEditor( { foo: 1 } );
+		it( 'creates main root element', () => {
+			const editor = new VirtualTestEditor();
 
-			expect( editor.document.getRoot() ).to.have.property( 'name', '$root' );
-			expect( editor.editing.view.getRoot() ).to.have.property( 'name', 'div' );
-			expect( editor.data.processor ).to.be.instanceof( HtmlDataProcessor );
+			expect( editor.model.document.getRoot( 'main' ) ).to.instanceof( RootElement );
+		} );
+
+		it( 'mixes DataApiMixin', () => {
+			expect( testUtils.isMixed( VirtualTestEditor, DataApiMixin ) ).to.true;
 		} );
 	} );
 

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

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 21 - 8
packages/ckeditor5-core/tests/_utils/classictesteditor.js

@@ -1,30 +1,36 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
-import StandardEditor from '../../src/editor/standardeditor';
+import Editor from '../../src/editor/editor';
+import ElementApiMixin from '../../src/editor/utils/elementapimixin';
+import DataApiMixin from '../../src/editor/utils/dataapimixin';
 import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
 import ClassicTestEditorUI from './classictesteditorui';
 import BoxedEditorUIView from '@ckeditor/ckeditor5-ui/src/editorui/boxed/boxededitoruiview';
 import ElementReplacer from '@ckeditor/ckeditor5-utils/src/elementreplacer';
 import InlineEditableUIView from '@ckeditor/ckeditor5-ui/src/editableui/inline/inlineeditableuiview';
+import getDataFromElement from '@ckeditor/ckeditor5-utils/src/dom/getdatafromelement';
+import mix from '@ckeditor/ckeditor5-utils/src/mix';
 
 /**
  * A simplified classic editor. Useful for testing features.
  *
  * @memberOf tests.core._utils
- * @extends core.editor.StandardEditor
+ * @extends core.editor.Editor
  */
-export default class ClassicTestEditor extends StandardEditor {
+export default class ClassicTestEditor extends Editor {
 	/**
 	 * @inheritDoc
 	 */
 	constructor( element, config ) {
-		super( element, config );
+		super( config );
 
-		this.document.createRoot();
-		this.editing.createRoot( 'div' );
+		// The element on which the editor has been initialized.
+		this.element = element;
+
+		// Use the HTML data processor in this editor.
 		this.data.processor = new HtmlDataProcessor();
 
 		this.ui = new ClassicTestEditorUI( this, new BoxedEditorUIView( this.locale ) );
@@ -34,7 +40,11 @@ export default class ClassicTestEditor extends StandardEditor {
 		this.ui.view.main.add( this.ui.view.editable );
 		this.ui.view.editableElement = this.ui.view.editable.element;
 
+		// A helper to easily replace the editor#element with editor.editable#element.
 		this._elementReplacer = new ElementReplacer();
+
+		// Create the ("main") root element of the model tree.
+		this.model.document.createRoot();
 	}
 
 	/**
@@ -62,7 +72,7 @@ export default class ClassicTestEditor extends StandardEditor {
 						editor.fire( 'uiReady' );
 					} )
 					.then( () => editor.editing.view.attachDomRoot( editor.ui.view.editableElement ) )
-					.then( () => editor.loadDataFromEditorElement() )
+					.then( () => editor.data.init( getDataFromElement( element ) ) )
 					.then( () => {
 						editor.fire( 'dataReady' );
 						editor.fire( 'ready' );
@@ -72,3 +82,6 @@ export default class ClassicTestEditor extends StandardEditor {
 		} );
 	}
 }
+
+mix( ClassicTestEditor, DataApiMixin );
+mix( ClassicTestEditor, ElementApiMixin );

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

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 11 - 18
packages/ckeditor5-core/tests/_utils/modeltesteditor.js

@@ -1,10 +1,12 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
 import Editor from '../../src/editor/editor';
+import DataApiMixin from '../../src/editor/utils/dataapimixin';
 import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
+import mix from '@ckeditor/ckeditor5-utils/src/mix';
 
 /**
  * A simple editor implementation with a functional model part of the engine (the document).
@@ -18,31 +20,20 @@ export default class ModelTestEditor extends Editor {
 	constructor( config ) {
 		super( config );
 
-		this.document.createRoot();
-
+		// Use the HTML data processor in this editor.
 		this.data.processor = new HtmlDataProcessor();
-	}
 
-	/**
-	 * Sets the data in the editor's main root.
-	 *
-	 * @param {*} data The data to load.
-	 */
-	setData( data ) {
-		this.data.set( data );
-	}
+		// Disable editing pipeline.
+		this.editing.destroy();
 
-	/**
-	 * Gets the data from the editor's main root.
-	 */
-	getData() {
-		return this.data.get();
+		// Create the ("main") root element of the model tree.
+		this.model.document.createRoot();
 	}
 
 	/**
 	 * Creates a virtual, element-less editor instance.
 	 *
-	 * @param {Object} config See {@link core.editor.StandardEditor}'s param.
+	 * @param {Object} config See {@link core.editor.Editor}'s param.
 	 * @returns {Promise} Promise resolved once editor is ready.
 	 * @returns {core.editor.VirtualTestEditor} return.editor The editor instance.
 	 */
@@ -61,3 +52,5 @@ export default class ModelTestEditor extends Editor {
 		} );
 	}
 }
+
+mix( ModelTestEditor, DataApiMixin );

+ 64 - 1
packages/ckeditor5-core/tests/_utils/utils.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -31,6 +31,69 @@ const utils = {
 		afterEach( () => {
 			utils.sinon.restore();
 		} );
+	},
+
+	/**
+	 * Executes specified assertions. It expects that at least one function will not throw an error.
+	 *
+	 * Some of the tests fail because different browsers renders selection differently when it comes to element boundaries.
+	 * Using this method we can check few scenarios.
+	 *
+	 * See https://github.com/ckeditor/ckeditor5-core/issues/107.
+	 *
+	 * Usage:
+	 *
+	 *      it( 'test', () => {
+	 *          // Test bootstrapping...
+	 *
+	 *          const assertEdge = () => {
+	 *              // expect();
+	 *          };
+	 *
+	 *          const assertAll = () => {
+	 *              // expect();
+	 *          };
+	 *
+	 *          testUtils.checkAssertions( assertEdge, assertAll );
+	 *      } );
+	 *
+	 * @param {...Function} assertions Functions that will be executed.
+	 */
+	checkAssertions( ...assertions ) {
+		const errors = [];
+
+		for ( const assertFn of assertions ) {
+			try {
+				assertFn();
+
+				return;
+			} catch ( err ) {
+				errors.push( err.message );
+			}
+		}
+
+		throw new Error( errors.join( '\n\n' ) );
+	},
+
+	/**
+	 * Checks if given mixin i mixed to given class using {@link module:utils/mix mix} util.
+	 *
+	 * @param {Function} targetClass Class to check.
+	 * @param {Object} mixin Mixin to check.
+	 * @returns {Boolean} `True` when mixin is mixed to to target class, `false` otherwise.
+	 */
+	isMixed( targetClass, mixin ) {
+		let isValid = true;
+
+		for ( const property in mixin ) {
+			if ( mixin.hasOwnProperty( property ) ) {
+				if ( targetClass.prototype[ property ] !== mixin[ property ] ) {
+					isValid = false;
+				}
+			}
+		}
+
+		return isValid;
 	}
 };
 

+ 13 - 9
packages/ckeditor5-core/tests/_utils/virtualtesteditor.js

@@ -1,10 +1,12 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
-import StandardEditor from '../../src/editor/standardeditor';
+import Editor from '../../src/editor/editor';
+import DataApiMixin from '../../src/editor/utils/dataapimixin';
 import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
+import mix from '@ckeditor/ckeditor5-utils/src/mix';
 
 /**
  * A simple editor implementation useful for testing the engine part of the features.
@@ -14,21 +16,21 @@ import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/html
  *
  * @memberOf tests.core._utils
  */
-export default class VirtualTestEditor extends StandardEditor {
+export default class VirtualTestEditor extends Editor {
 	constructor( config ) {
-		super( null, config );
-
-		this.document.createRoot();
-
-		this.editing.createRoot( 'div' );
+		super( config );
 
+		// Use the HTML data processor in this editor.
 		this.data.processor = new HtmlDataProcessor();
+
+		// Create the ("main") root element of the model tree.
+		this.model.document.createRoot();
 	}
 
 	/**
 	 * Creates a virtual, element-less editor instance.
 	 *
-	 * @param {Object} config See {@link core.editor.StandardEditor}'s param.
+	 * @param {Object} config See {@link core.editor.Editor}'s param.
 	 * @returns {Promise} Promise resolved once editor is ready.
 	 * @returns {core.editor.VirtualTestEditor} return.editor The editor instance.
 	 */
@@ -47,3 +49,5 @@ export default class VirtualTestEditor extends StandardEditor {
 		} );
 	}
 }
+
+mix( VirtualTestEditor, DataApiMixin );

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

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -34,10 +34,10 @@ describe( 'Command', () => {
 			expect( command.isEnabled ).to.be.false;
 		} );
 
-		it( 'adds a listener which refreshed the command on editor.document#changesDone', () => {
+		it( 'adds a listener which refreshes the command on editor.model.Document#event:change', () => {
 			sinon.spy( command, 'refresh' );
 
-			editor.document.fire( 'changesDone' );
+			editor.model.document.fire( 'change' );
 
 			expect( command.refresh.calledOnce ).to.be.true;
 		} );

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

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 1
packages/ckeditor5-core/tests/editingkeystrokehandler.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 57 - 10
packages/ckeditor5-core/tests/editor/editor.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -8,11 +8,13 @@
 import Editor from '../../src/editor/editor';
 import Plugin from '../../src/plugin';
 import Config from '@ckeditor/ckeditor5-utils/src/config';
+import EditingController from '@ckeditor/ckeditor5-engine/src/controller/editingcontroller';
 import PluginCollection from '../../src/plugincollection';
 import CommandCollection from '../../src/commandcollection';
 import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
 import Locale from '@ckeditor/ckeditor5-utils/src/locale';
 import Command from '../../src/command';
+import EditingKeystrokeHandler from '../../src/editingkeystrokehandler';
 
 class PluginA extends Plugin {
 	constructor( editor ) {
@@ -103,6 +105,8 @@ describe( 'Editor', () => {
 
 			expect( editor.config ).to.be.an.instanceof( Config );
 			expect( editor.commands ).to.be.an.instanceof( CommandCollection );
+			expect( editor.editing ).to.be.instanceof( EditingController );
+			expect( editor.keystrokes ).to.be.instanceof( EditingKeystrokeHandler );
 
 			expect( editor.plugins ).to.be.an.instanceof( PluginCollection );
 			expect( getPlugins( editor ) ).to.be.empty;
@@ -133,6 +137,25 @@ describe( 'Editor', () => {
 
 			expect( editor.config.get( 'bar' ) ).to.equal( 'foo' );
 		} );
+
+		it( 'should bind editing.view.document#isReadOnly to the editor', () => {
+			const editor = new Editor();
+
+			editor.isReadOnly = false;
+
+			expect( editor.editing.view.document.isReadOnly ).to.false;
+
+			editor.isReadOnly = true;
+
+			expect( editor.editing.view.document.isReadOnly ).to.true;
+		} );
+
+		it( 'should activate #keystrokes', () => {
+			const spy = sinon.spy( EditingKeystrokeHandler.prototype, 'listenTo' );
+			const editor = new Editor();
+
+			sinon.assert.calledWith( spy, editor.editing.view.document );
+		} );
 	} );
 
 	describe( 'plugins', () => {
@@ -151,10 +174,10 @@ describe( 'Editor', () => {
 			expect( editor.t ).to.equal( editor.locale.t );
 		} );
 
-		it( 'is configured with the config.lang', () => {
-			const editor = new Editor( { lang: 'pl' } );
+		it( 'is configured with the config.language', () => {
+			const editor = new Editor( { language: 'pl' } );
 
-			expect( editor.locale.lang ).to.equal( 'pl' );
+			expect( editor.locale.language ).to.equal( 'pl' );
 		} );
 	} );
 
@@ -177,6 +200,26 @@ describe( 'Editor', () => {
 		} );
 	} );
 
+	describe( 'conversion', () => {
+		it( 'should have conversion property', () => {
+			const editor = new Editor();
+
+			expect( editor ).to.have.property( 'conversion' );
+		} );
+
+		it( 'should have defined default conversion groups', () => {
+			const editor = new Editor();
+
+			expect( () => {
+				// Would throw if any of this group won't exist.
+				editor.conversion.for( 'downcast' );
+				editor.conversion.for( 'editingDowncast' );
+				editor.conversion.for( 'dataDowncast' );
+				editor.conversion.for( 'upcast' );
+			} ).not.to.throw();
+		} );
+	} );
+
 	describe( 'destroy()', () => {
 		it( 'should fire "destroy"', () => {
 			const editor = new Editor();
@@ -192,15 +235,19 @@ describe( 'Editor', () => {
 		it( 'should destroy all components it initialized', () => {
 			const editor = new Editor();
 
-			const spy1 = sinon.spy( editor.data, 'destroy' );
-			const spy2 = sinon.spy( editor.document, 'destroy' );
-			const spy3 = sinon.spy( editor.plugins, 'destroy' );
+			const dataDestroySpy = sinon.spy( editor.data, 'destroy' );
+			const modelDestroySpy = sinon.spy( editor.model, 'destroy' );
+			const editingDestroySpy = sinon.spy( editor.editing, 'destroy' );
+			const pluginsDestroySpy = sinon.spy( editor.plugins, 'destroy' );
+			const keystrokesDestroySpy = sinon.spy( editor.keystrokes, 'destroy' );
 
 			return editor.destroy()
 				.then( () => {
-					expect( spy1.calledOnce ).to.be.true;
-					expect( spy2.calledOnce ).to.be.true;
-					expect( spy3.calledOnce ).to.be.true;
+					sinon.assert.calledOnce( dataDestroySpy );
+					sinon.assert.calledOnce( modelDestroySpy );
+					sinon.assert.calledOnce( editingDestroySpy );
+					sinon.assert.calledOnce( pluginsDestroySpy );
+					sinon.assert.calledOnce( keystrokesDestroySpy );
 				} );
 		} );
 	} );

+ 0 - 385
packages/ckeditor5-core/tests/editor/standardeditor.js

@@ -1,385 +0,0 @@
-/**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* globals document, Event */
-
-import Editor from '../../src/editor/editor';
-import StandardEditor from '../../src/editor/standardeditor';
-import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
-import { getData, setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
-
-import EditingController from '@ckeditor/ckeditor5-engine/src/controller/editingcontroller';
-import EditingKeystrokeHandler from '../../src/editingkeystrokehandler';
-import Plugin from '../../src/plugin';
-
-describe( 'StandardEditor', () => {
-	let editorElement;
-
-	beforeEach( () => {
-		editorElement = document.createElement( 'div' );
-		document.body.appendChild( editorElement );
-	} );
-
-	describe( 'constructor()', () => {
-		it( 'sets all properties', () => {
-			const editor = new StandardEditor( editorElement, { foo: 1 } );
-
-			expect( editor ).to.have.property( 'element', editorElement );
-			expect( editor.editing ).to.be.instanceof( EditingController );
-			expect( editor.keystrokes ).to.be.instanceof( EditingKeystrokeHandler );
-		} );
-
-		it( 'should bind editing.view#isReadOnly to the editor', () => {
-			const editor = new StandardEditor( editorElement, { foo: 1 } );
-
-			editor.isReadOnly = false;
-
-			expect( editor.editing.view.isReadOnly ).to.false;
-
-			editor.isReadOnly = true;
-
-			expect( editor.editing.view.isReadOnly ).to.true;
-		} );
-
-		it( 'activates #keystrokes', () => {
-			const spy = sinon.spy( EditingKeystrokeHandler.prototype, 'listenTo' );
-			const editor = new StandardEditor( editorElement, { foo: 1 } );
-
-			sinon.assert.calledWith( spy, editor.editing.view );
-		} );
-
-		it( 'sets config', () => {
-			const editor = new StandardEditor( editorElement, { foo: 1 } );
-
-			expect( editor.config.get( 'foo' ) ).to.equal( 1 );
-		} );
-	} );
-
-	describe( 'destroy()', () => {
-		it( 'returns a Promise', () => {
-			const editor = new StandardEditor( editorElement, { foo: 1 } );
-
-			expect( editor.destroy() ).to.be.an.instanceof( Promise );
-		} );
-
-		it( 'destroys the #keystrokes', () => {
-			const editor = new StandardEditor( editorElement, { foo: 1 } );
-			const spy = sinon.spy( editor.keystrokes, 'destroy' );
-
-			sinon.assert.notCalled( spy );
-
-			return editor.destroy()
-				.then( () => {
-					sinon.assert.calledOnce( spy );
-				} );
-		} );
-
-		it( 'destroys the #editing', () => {
-			const editor = new StandardEditor( editorElement, { foo: 1 } );
-			const spy = sinon.spy( editor.editing, 'destroy' );
-
-			sinon.assert.notCalled( spy );
-
-			return editor.destroy()
-				.then( () => {
-					sinon.assert.calledOnce( spy );
-				} );
-		} );
-
-		it( 'destroys the parent', () => {
-			const editor = new StandardEditor( editorElement, { foo: 1 } );
-			const spy = sinon.spy( Editor.prototype, 'destroy' );
-
-			sinon.assert.notCalled( spy );
-
-			return editor.destroy()
-				.then( () => {
-					sinon.assert.calledOnce( spy );
-				} );
-		} );
-	} );
-
-	describe( 'create()', () => {
-		it( 'initializes editor with plugins and config', () => {
-			class PluginFoo extends Plugin {}
-
-			return StandardEditor.create( editorElement, { foo: 1, plugins: [ PluginFoo ] } )
-				.then( editor => {
-					expect( editor ).to.be.instanceof( StandardEditor );
-
-					expect( editor.config.get( 'foo' ) ).to.equal( 1 );
-					expect( editor ).to.have.property( 'element', editorElement );
-
-					expect( editor.plugins.get( PluginFoo ) ).to.be.instanceof( PluginFoo );
-				} );
-		} );
-
-		it( 'fires all events in the right order', () => {
-			const fired = [];
-
-			function spy( evt ) {
-				fired.push( evt.name );
-			}
-
-			class EventWatcher extends Plugin {
-				init() {
-					this.editor.on( 'pluginsReady', spy );
-					this.editor.on( 'dataReady', spy );
-					this.editor.on( 'ready', spy );
-				}
-			}
-
-			return StandardEditor.create( editorElement, { plugins: [ EventWatcher ] } )
-				.then( () => {
-					expect( fired ).to.deep.equal( [ 'pluginsReady', 'dataReady', 'ready' ] );
-				} );
-		} );
-	} );
-
-	describe( 'setData()', () => {
-		let editor;
-
-		beforeEach( () => {
-			return StandardEditor.create( editorElement )
-				.then( newEditor => {
-					editor = newEditor;
-
-					editor.data.processor = new HtmlDataProcessor();
-
-					editor.document.schema.allow( { name: '$text', inside: '$root' } );
-				} );
-		} );
-
-		it( 'should set data of the first root', () => {
-			editor.document.createRoot();
-			editor.document.createRoot( '$root', 'secondRoot' );
-
-			editor.editing.createRoot( 'div' );
-			editor.editing.createRoot( 'div', 'secondRoot' );
-
-			editor.setData( 'foo' );
-
-			expect( getData( editor.document, { rootName: 'main', withoutSelection: true } ) ).to.equal( 'foo' );
-		} );
-	} );
-
-	describe( 'getData()', () => {
-		let editor;
-
-		beforeEach( () => {
-			return StandardEditor.create( editorElement )
-				.then( newEditor => {
-					editor = newEditor;
-
-					editor.data.processor = new HtmlDataProcessor();
-
-					editor.document.schema.allow( { name: '$text', inside: '$root' } );
-				} );
-		} );
-
-		it( 'should get data of the first root', () => {
-			editor.document.createRoot();
-			editor.document.createRoot( '$root', 'secondRoot' );
-
-			editor.editing.createRoot( 'div' );
-			editor.editing.createRoot( 'div', 'secondRoot' );
-
-			setData( editor.document, 'foo' );
-
-			expect( editor.getData() ).to.equal( 'foo' );
-		} );
-	} );
-
-	describe( 'updateEditorElement()', () => {
-		it( 'sets data to editor element', () => {
-			const editor = new StandardEditor( editorElement );
-
-			editor.data.get = () => '<p>foo</p>';
-
-			editor.updateEditorElement();
-
-			expect( editorElement.innerHTML ).to.equal( '<p>foo</p>' );
-		} );
-	} );
-
-	describe( 'loadDataFromEditorElement()', () => {
-		it( 'sets data to editor element', () => {
-			const editor = new StandardEditor( editorElement );
-
-			sinon.stub( editor.data, 'set' );
-			editorElement.innerHTML = '<p>foo</p>';
-
-			editor.loadDataFromEditorElement();
-
-			expect( editor.data.set.calledWithExactly( '<p>foo</p>' ) ).to.be.true;
-		} );
-	} );
-
-	describe( 'attaching to a form', () => {
-		let editor, form, textarea, submitStub;
-
-		beforeEach( () => {
-			form = document.createElement( 'form' );
-			textarea = document.createElement( 'textarea' );
-			form.appendChild( textarea );
-			document.body.appendChild( form );
-			submitStub = sinon.stub( form, 'submit' );
-
-			// Prevents page realods in Firefox ;|
-			form.addEventListener( 'submit', evt => {
-				evt.preventDefault();
-			} );
-		} );
-
-		afterEach( () => {
-			submitStub.restore();
-			form.remove();
-		} );
-
-		it( 'should update editor#element after calling the submit() method', () => {
-			return createEditor( textarea )
-				.then( editor => {
-					expect( textarea.value ).to.equal( '' );
-
-					// Submit method is replaced by our implementation.
-					expect( form.submit ).to.not.equal( submitStub );
-					form.submit();
-
-					expect( textarea.value ).to.equal( '<p>foo</p>' );
-					sinon.assert.calledOnce( submitStub );
-
-					// Check if original function was called in correct context.
-					sinon.assert.calledOn( submitStub, form );
-
-					return editor.destroy();
-				} );
-		} );
-
-		it( 'should update editor#element after the "submit" event', () => {
-			return createEditor( textarea )
-				.then( editor => {
-					expect( textarea.value ).to.equal( '' );
-
-					form.dispatchEvent( new Event( 'submit', {
-						// We need to be able to do preventDefault() to prevent page reloads in Firefox.
-						cancelable: true
-					} ) );
-
-					expect( textarea.value ).to.equal( '<p>foo</p>' );
-
-					return editor.destroy();
-				} );
-		} );
-
-		it( 'should not update editor#element if it is not a textarea in a form', () => {
-			const element = document.createElement( 'div' );
-			form.appendChild( element );
-
-			return createEditor( element )
-				.then( editor => {
-					expect( textarea.value ).to.equal( '' );
-
-					// Submit method is not replaced by our implementation.
-					expect( form.submit ).to.equal( submitStub );
-					form.submit();
-
-					expect( textarea.value ).to.equal( '' );
-
-					return editor.destroy();
-				} )
-				.then( () => {
-					element.remove();
-				} );
-		} );
-
-		it( 'should not update editor#element not belonging to a form', () => {
-			const textarea = document.createElement( 'textarea' );
-			document.body.appendChild( textarea );
-
-			return createEditor( textarea )
-				.then( editor => {
-					expect( textarea.value ).to.equal( '' );
-
-					// Submit method is not replaced by our implementation.
-					expect( form.submit ).to.equal( submitStub );
-					form.submit();
-
-					expect( textarea.value ).to.equal( '' );
-
-					return editor.destroy();
-				} )
-				.then( () => {
-					textarea.remove();
-				} );
-		} );
-
-		it( 'should not update editor#element after destruction of the editor - form.submit()', () => {
-			return createEditor( textarea )
-				.then( editor => editor.destroy() )
-				.then( () => {
-					expect( textarea.value ).to.equal( '' );
-
-					// Submit method is no longer replaced by our implementation.
-					expect( form.submit ).to.equal( submitStub );
-					form.submit();
-
-					expect( textarea.value ).to.equal( '' );
-				} );
-		} );
-
-		it( 'should not update the editor#element after destruction of the editor - "submit" event', () => {
-			return createEditor( textarea )
-				.then( editor => editor.destroy() )
-				.then( () => {
-					expect( textarea.value ).to.equal( '' );
-
-					form.dispatchEvent( new Event( 'submit', {
-						// We need to be able to do preventDefault() to prevent page reloads in Firefox.
-						cancelable: true
-					} ) );
-
-					expect( textarea.value ).to.equal( '' );
-				} );
-		} );
-
-		it( 'should not replace submit() method when one of the elements in a form is named "submit"', () => {
-			// Restore stub since we want to mask submit function with input with name="submit".
-			submitStub.restore();
-
-			const input = document.createElement( 'input' );
-			input.setAttribute( 'name', 'submit' );
-			form.appendChild( input );
-
-			return createEditor( textarea )
-				.then( () => {
-					expect( form.submit ).to.equal( input );
-					expect( textarea.value ).to.equal( '' );
-
-					form.dispatchEvent( new Event( 'submit', {
-						// We need to be able to do preventDefault() to prevent page reloads in Firefox.
-						cancelable: true
-					} ) );
-
-					expect( textarea.value ).to.equal( '<p>foo</p>' );
-
-					return editor.destroy();
-				} )
-				.then( () => {
-					expect( form.submit ).to.equal( input );
-					input.remove();
-				} );
-		} );
-
-		function createEditor( element ) {
-			return StandardEditor.create( element )
-				.then( newEditor => {
-					editor = newEditor;
-					editor.data.get = () => '<p>foo</p>';
-
-					return editor;
-				} );
-		}
-	} );
-} );

+ 176 - 0
packages/ckeditor5-core/tests/editor/utils/attachtoform.js

@@ -0,0 +1,176 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+import attachToForm from '../../../src/editor/utils/attachtoform';
+import ElementApiMixin from '../../../src/editor/utils/elementapimixin';
+import Editor from '../../../src/editor/editor';
+import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
+import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
+import mix from '@ckeditor/ckeditor5-utils/src/mix';
+
+/* global document, Event */
+
+describe( 'attachToForm()', () => {
+	let editor, form, textarea, submitStub;
+
+	beforeEach( () => {
+		form = document.createElement( 'form' );
+		textarea = document.createElement( 'textarea' );
+		form.appendChild( textarea );
+		document.body.appendChild( form );
+		submitStub = sinon.stub( form, 'submit' );
+
+		// Prevents page realods in Firefox ;|
+		form.addEventListener( 'submit', evt => {
+			evt.preventDefault();
+		} );
+
+		class CustomEditor extends Editor {}
+		mix( CustomEditor, ElementApiMixin );
+
+		editor = new CustomEditor();
+		editor.data.processor = new HtmlDataProcessor();
+		editor.model.document.createRoot();
+		editor.model.schema.extend( '$text', { allowIn: '$root' } );
+
+		editor.data.set( 'foo bar' );
+	} );
+
+	afterEach( () => {
+		submitStub.restore();
+		form.remove();
+
+		return editor.destroy();
+	} );
+
+	it( 'should throw an error when is used with editor without `ElementApiMixin`', () => {
+		expect( () => {
+			attachToForm( new Editor() );
+		} ).to.throw( CKEditorError, /^attachtoform-missing-elementapi-interface/ );
+	} );
+
+	it( 'should update editor#element after the "submit" event', () => {
+		editor.element = textarea;
+		attachToForm( editor );
+
+		expect( textarea.value ).to.equal( '' );
+
+		form.dispatchEvent( new Event( 'submit', {
+			// We need to be able to do preventDefault() to prevent page reloads in Firefox.
+			cancelable: true
+		} ) );
+
+		expect( textarea.value ).to.equal( 'foo bar' );
+	} );
+
+	it( 'should update editor#element after calling the submit() method', () => {
+		editor.element = textarea;
+		attachToForm( editor );
+
+		expect( textarea.value ).to.equal( '' );
+
+		// Submit method is replaced by our implementation.
+		expect( form.submit ).to.not.equal( submitStub );
+		form.submit();
+
+		expect( textarea.value ).to.equal( 'foo bar' );
+		sinon.assert.calledOnce( submitStub );
+
+		// Check if original function was called in correct context.
+		sinon.assert.calledOn( submitStub, form );
+	} );
+
+	it( 'should not update editor#element if it is not a textarea in a form', () => {
+		const element = document.createElement( 'div' );
+		form.appendChild( element );
+
+		editor.element = element;
+		attachToForm( editor );
+
+		expect( textarea.value ).to.equal( '' );
+
+		// Submit method is not replaced by our implementation.
+		expect( form.submit ).to.equal( submitStub );
+		form.submit();
+
+		expect( textarea.value ).to.equal( '' );
+	} );
+
+	it( 'should not update editor#element not belonging to a form', () => {
+		const standaloneTextarea = document.createElement( 'textarea' );
+		document.body.appendChild( standaloneTextarea );
+
+		editor.element = standaloneTextarea;
+		attachToForm( editor );
+
+		expect( standaloneTextarea.value ).to.equal( '' );
+
+		// Submit method is not replaced by our implementation.
+		expect( form.submit ).to.equal( submitStub );
+		form.submit();
+
+		expect( standaloneTextarea.value ).to.equal( '' );
+
+		standaloneTextarea.remove();
+	} );
+
+	it( 'should not update editor#element after destruction of the editor - form.submit()', () => {
+		editor.element = textarea;
+		attachToForm( editor );
+
+		expect( textarea.value ).to.equal( '' );
+
+		return editor.destroy().then( () => {
+			// Submit method is no longer replaced by our implementation.
+			expect( form.submit ).to.equal( submitStub );
+			form.submit();
+
+			expect( textarea.value ).to.equal( '' );
+		} );
+	} );
+
+	it( 'should not update the editor#element after destruction of the editor - "submit" event', () => {
+		editor.element = textarea;
+		attachToForm( editor );
+
+		expect( textarea.value ).to.equal( '' );
+
+		return editor.destroy().then( () => {
+			form.dispatchEvent( new Event( 'submit', {
+				// We need to be able to do preventDefault() to prevent page reloads in Firefox.
+				cancelable: true
+			} ) );
+
+			expect( textarea.value ).to.equal( '' );
+		} );
+	} );
+
+	it( 'should not replace submit() method when one of the elements in a form is named "submit"', () => {
+		// Restore stub since we want to mask submit function with input with name="submit".
+		submitStub.restore();
+
+		const input = document.createElement( 'input' );
+		input.setAttribute( 'name', 'submit' );
+		form.appendChild( input );
+
+		editor.element = textarea;
+		attachToForm( editor );
+
+		expect( form.submit ).to.equal( input );
+		expect( textarea.value ).to.equal( '' );
+
+		form.dispatchEvent( new Event( 'submit', {
+			// We need to be able to do preventDefault() to prevent page reloads in Firefox.
+			cancelable: true
+		} ) );
+
+		expect( textarea.value ).to.equal( 'foo bar' );
+
+		return editor.destroy().then( () => {
+			expect( form.submit ).to.equal( input );
+			input.remove();
+		} );
+	} );
+} );

+ 53 - 0
packages/ckeditor5-core/tests/editor/utils/dataapimixin.js

@@ -0,0 +1,53 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+import DataApiMixin from '../../../src/editor/utils/dataapimixin';
+import Editor from '../../../src/editor/editor';
+import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
+import mix from '@ckeditor/ckeditor5-utils/src/mix';
+import { getData, setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
+
+describe( 'DataApiMixin', () => {
+	let editor;
+
+	beforeEach( () => {
+		class CustomEditor extends Editor {}
+		mix( CustomEditor, DataApiMixin );
+
+		editor = new CustomEditor();
+		editor.data.processor = new HtmlDataProcessor();
+		editor.model.document.createRoot( '$root', 'main' );
+		editor.model.document.createRoot( '$root', 'secondRoot' );
+		editor.model.schema.extend( '$text', { allowIn: '$root' } );
+	} );
+
+	afterEach( () => {
+		editor.destroy();
+	} );
+
+	describe( 'setData()', () => {
+		it( 'should be added to editor interface', () => {
+			expect( editor ).have.property( 'setData' ).to.be.a( 'function' );
+		} );
+
+		it( 'should set data of the first root', () => {
+			editor.setData( 'foo' );
+
+			expect( getData( editor.model, { rootName: 'main', withoutSelection: true } ) ).to.equal( 'foo' );
+		} );
+	} );
+
+	describe( 'getData()', () => {
+		it( 'should be added to editor interface', () => {
+			expect( editor ).have.property( 'getData' ).to.be.a( 'function' );
+		} );
+
+		it( 'should get data of the first root', () => {
+			setData( editor.model, 'foo' );
+
+			expect( editor.getData() ).to.equal( 'foo' );
+		} );
+	} );
+} );

+ 47 - 0
packages/ckeditor5-core/tests/editor/utils/elementapimixin.js

@@ -0,0 +1,47 @@
+/**
+ * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* global document */
+
+import ElementApiMixin from '../../../src/editor/utils/elementapimixin';
+import Editor from '../../../src/editor/editor';
+import HtmlDataProcessor from '@ckeditor/ckeditor5-engine/src/dataprocessor/htmldataprocessor';
+import mix from '@ckeditor/ckeditor5-utils/src/mix';
+
+describe( 'ElementApiMixin', () => {
+	let editor;
+
+	beforeEach( () => {
+		class CustomEditor extends Editor {}
+		mix( CustomEditor, ElementApiMixin );
+
+		editor = new CustomEditor();
+		editor.data.processor = new HtmlDataProcessor();
+		editor.model.document.createRoot();
+		editor.model.schema.extend( '$text', { allowIn: '$root' } );
+	} );
+
+	afterEach( () => {
+		editor.destroy();
+	} );
+
+	describe( 'updateEditorElement()', () => {
+		it( 'should be added to editor interface', () => {
+			expect( editor ).have.property( 'updateElement' ).to.be.a( 'function' );
+		} );
+
+		it( 'sets data to editor element', () => {
+			const editorElement = document.createElement( 'div' );
+
+			editor.data.set( 'foo bar' );
+
+			editor.element = editorElement;
+
+			editor.updateElement();
+
+			expect( editorElement.innerHTML ).to.equal( 'foo bar' );
+		} );
+	} );
+} );

+ 1 - 1
packages/ckeditor5-core/tests/manual/article.html

@@ -1,7 +1,7 @@
 <div id="editor">
 	<h2>Heading 1</h2>
 	<p>Paragraph</p>
-	<p><strong>Bold</strong> <i>Italic</i> <a href="foo">Link</a></p>
+	<p><strong>Bold</strong> <i>Italic</i> <a href="https://ckeditor.com">Link</a></p>
 	<ul>
 		<li>UL List item 1</li>
 		<li>UL List item 2</li>

+ 3 - 3
packages/ckeditor5-core/tests/manual/article.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -12,9 +12,9 @@ import ArticlePluginSet from '../_utils/articlepluginset';
 ClassicEditor
 	.create( document.querySelector( '#editor' ), {
 		plugins: [ ArticlePluginSet ],
-		toolbar: [ 'headings', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ],
+		toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ],
 		image: {
-			toolbar: [ 'imageStyleFull', 'imageStyleSide', '|', 'imageTextAlternative' ]
+			toolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ]
 		}
 	} )
 	.then( editor => {

+ 1 - 1
packages/ckeditor5-core/tests/manual/formsubmit.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 6 - 6
packages/ckeditor5-core/tests/manual/readonly.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 
@@ -8,16 +8,16 @@
 import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor';
 
 import ArticlePluginSet from '../_utils/articlepluginset';
-import ContextualToolbar from '@ckeditor/ckeditor5-ui/src/toolbar/contextual/contextualtoolbar';
+import BalloonToolbar from '@ckeditor/ckeditor5-ui/src/toolbar/balloon/balloontoolbar';
 
 ClassicEditor
 	.create( document.querySelector( '#editor' ), {
-		plugins: [ ArticlePluginSet, ContextualToolbar ],
-		toolbar: [ 'headings', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ],
+		plugins: [ ArticlePluginSet, BalloonToolbar ],
+		toolbar: [ 'heading', '|', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ],
 		image: {
-			toolbar: [ 'imageStyleFull', 'imageStyleSide', '|', 'imageTextAlternative' ],
+			toolbar: [ 'imageStyle:full', 'imageStyle:side', '|', 'imageTextAlternative' ],
 		},
-		contextualToolbar: [ 'bold', 'italic', 'link' ]
+		balloonToolbar: [ 'bold', 'italic', 'link' ]
 	} )
 	.then( editor => {
 		window.editor = editor;

+ 1 - 1
packages/ckeditor5-core/tests/plugin.js

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

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

@@ -1,5 +1,5 @@
 /**
- * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
+ * @license Copyright (c) 2003-2018, CKSource - Frederico Knabben. All rights reserved.
  * For licensing, see LICENSE.md.
  */
 

+ 1 - 0
packages/ckeditor5-core/theme/icons/cancel.svg

@@ -0,0 +1 @@
+<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M11.06 10l4.597 4.596a.75.75 0 1 1-1.06 1.06L10 11.062l-4.596 4.596a.75.75 0 1 1-1.06-1.06L8.938 10 4.343 5.404a.75.75 0 1 1 1.06-1.06L10 8.938l4.596-4.596a.75.75 0 0 1 1.06 1.06L11.062 10z" fill="#000" fill-rule="evenodd"/></svg>

+ 1 - 0
packages/ckeditor5-core/theme/icons/check.svg

@@ -0,0 +1 @@
+<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M6.688 14.44l-4.196-4.195a.758.758 0 0 0-1.066-.006.742.742 0 0 0-.006 1.054l5.268 5.269L18.074 5.176a.742.742 0 0 0-.006-1.055.758.758 0 0 0-1.067.006L6.688 14.44z" fill="#000" fill-rule="nonzero"/></svg>

+ 1 - 1
packages/ckeditor5-core/theme/icons/image.svg

@@ -1 +1 @@
-<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 14.994C2 16.102 2.895 17 3.994 17h12.012A2 2 0 0 0 18 14.994V5.006A2.001 2.001 0 0 0 16.006 3H3.994A2 2 0 0 0 2 5.006v9.988zm1-9.992C3 4.45 3.45 4 4.007 4h11.986A1.01 1.01 0 0 1 17 5.002v9.996C17 15.55 16.55 16 15.993 16H4.007A1.01 1.01 0 0 1 3 14.998V5.002zm1.024 10H16v-3.096l-2.89-4.263-3.096 5.257-3.003-2.103L4 13.96l.024 1.043zM6.406 6A1.4 1.4 0 0 0 5 7.393a1.4 1.4 0 0 0 1.406 1.393 1.4 1.4 0 0 0 1.407-1.393A1.4 1.4 0 0 0 6.406 6z" fill="#454545" fill-rule="evenodd"/></svg>
+<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg"><path d="M6.91 10.54c.26-.23.64-.21.88.03l3.36 3.14 2.23-2.06a.64.64 0 0 1 .87 0l2.52 2.97V4.5H3.2v10.12l3.71-4.08zm10.27-7.51c.6 0 1.09.47 1.09 1.05v11.84c0 .59-.49 1.06-1.09 1.06H2.79c-.6 0-1.09-.47-1.09-1.06V4.08c0-.58.49-1.05 1.1-1.05h14.38zm-5.22 5.56a1.96 1.96 0 1 1 3.4-1.96 1.96 1.96 0 0 1-3.4 1.96z" fill="#000" fill-rule="nonzero"/></svg>

Разница между файлами не показана из-за своего большого размера
+ 0 - 0
packages/ckeditor5-core/theme/icons/input.svg


Разница между файлами не показана из-за своего большого размера
+ 0 - 0
packages/ckeditor5-core/theme/icons/low-vision.svg


+ 1 - 1
packages/ckeditor5-core/theme/icons/object-center.svg

@@ -1 +1 @@
-<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M2 15h16v1H2v-1zm13-2H5V6h10v7zm-1-6H6v5h8V7zM2 3h16v1H2V3z" fill-rule="nonzero"/></svg>
+<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg"><g fill="#000" fill-rule="nonzero"><path d="M2 4.5V3h16v1.5zM6.5 7.5V12h7V7.5h-7zM5.758 6h8.484c.419 0 .758.407.758.91v5.681c0 .502-.34.909-.758.909H5.758c-.419 0-.758-.407-.758-.91V6.91c0-.503.34-.91.758-.91zM2 16.5V15h16v1.5z"/></g></svg>

+ 1 - 1
packages/ckeditor5-core/theme/icons/object-full-width.svg

@@ -1 +1 @@
-<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 16h16v1H2v-1zm15-2H3V6h14v8zm-1-7H4v6h12V7zM2 3h16v1H2V3z"/></svg>
+<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg"><g fill="#000" fill-rule="nonzero"><path d="M2 4.5V3h16v1.5zM4.5 7.5V12h11V7.5h-11zM4.061 6H15.94c.586 0 1.061.407 1.061.91v5.68c0 .503-.475.91-1.061.91H4.06C3.475 13.5 3 13.093 3 12.59V6.91C3 6.406 3.475 6 4.061 6zM2 16.5V15h16v1.5z"/></g></svg>

+ 1 - 1
packages/ckeditor5-core/theme/icons/object-left.svg

@@ -1 +1 @@
-<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M2 15h16v1H2v-1zm11-3h5v1h-5v-1zm-2 1H2V6h9v7zm-1-6H3v5h7V7zm3 2h5v1h-5V9zm0-3h5v1h-5V6zM2 3h16v1H2V3z"/></svg>
+<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="1.414"><path d="M18 4.5V3H2v1.5h16zm0 3V6h-5.674v1.5H18zm0 3V9h-5.674v1.5H18zm0 3V12h-5.674v1.5H18zm-8.5-6V12h-6V7.5h6zm.818-1.5H2.682C2.305 6 2 6.407 2 6.91v5.68c0 .503.305.91.682.91h7.636c.377 0 .682-.407.682-.91V6.91c0-.503-.305-.91-.682-.91zM18 16.5V15H2v1.5h16z" fill-rule="nonzero"/></svg>

+ 1 - 1
packages/ckeditor5-core/theme/icons/object-right.svg

@@ -1 +1 @@
-<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M18 16H2v-1h16v1zM6.978 13H2v-1h4.978v1zM18 6v7H9V6h9zm-1 6V7h-7v5h7zM6.978 10H2V9h4.978v1zm0-3H2V6h4.978v1zM18 4H2V3h16v1z"/></svg>
+<svg width="20" height="20" xmlns="http://www.w3.org/2000/svg"><g fill="#000" fill-rule="nonzero"><path d="M2 4.5V3h16v1.5zM2 7.5V6h5.674v1.5zM2 10.5V9h5.674v1.5zM2 13.5V12h5.674v1.5zM10.5 7.5V12h6V7.5h-6zM9.682 6h7.636c.377 0 .682.407.682.91v5.68c0 .503-.305.91-.682.91H9.682c-.377 0-.682-.407-.682-.91V6.91c0-.503.305-.91.682-.91zM2 16.5V15h16v1.5z"/></g></svg>

+ 1 - 0
packages/ckeditor5-core/theme/icons/pencil.svg

@@ -0,0 +1 @@
+<svg viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M7.3 17.37l-.061.088a1.518 1.518 0 0 1-.934.535l-4.178.663-.806-4.153a1.495 1.495 0 0 1 .187-1.058l.056-.086L8.77 2.639c.958-1.351 2.803-1.076 4.296-.03 1.497 1.047 2.387 2.693 1.433 4.055L7.3 17.37zM9.14 4.728l-5.545 8.346 3.277 2.294 5.544-8.346L9.14 4.728zM6.07 16.512l-3.276-2.295.53 2.73 2.746-.435zM9.994 3.506L13.271 5.8c.316-.452-.16-1.333-1.065-1.966-.905-.634-1.895-.78-2.212-.328zM8 18.5L9.375 17H19v1.5H8z" fill="#000" fill-rule="nonzero"/></svg>

+ 0 - 1
packages/ckeditor5-core/theme/icons/picker.svg

@@ -1 +0,0 @@
-<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M9.635 7.529l-6.252 6.474A2 2 0 0 0 6.26 16.78l6.252-6.473-.72-.695-6.251 6.474a1 1 0 0 1-1.439-1.39l6.252-6.473-.72-.695zm5.125.746c.115-.096.238-.21.369-.346 1.332-1.379 1.76-3.127.955-3.903-.805-.777-2.537-.29-3.868 1.09a4.63 4.63 0 0 0-.332.38l2.876 2.779zm-4.755-3.27l4.774 4.61-.662.685-4.774-4.61.662-.685z" fill="#454545" fill-rule="evenodd"/></svg>

+ 1 - 1
packages/ckeditor5-core/theme/icons/quote.svg

@@ -1 +1 @@
-<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M12.061 15.51v-.882c1.395-.847 2.345-1.633 2.85-2.358.37-.533.554-1.162.554-1.887 0-.437-.082-.759-.246-.964-.15-.205-.328-.307-.533-.307-.137 0-.328.048-.574.143-.37.123-.67.185-.902.185-.547 0-1.033-.205-1.456-.615-.424-.41-.636-.923-.636-1.538 0-.698.212-1.238.636-1.62a3.002 3.002 0 0 1 2.05-.78c.93 0 1.757.39 2.482 1.17.724.778 1.087 1.742 1.087 2.89 0 1.614-.602 3.084-1.805 4.41-.807.875-1.976 1.593-3.507 2.153zm-8.386 0v-.882c1.394-.847 2.345-1.633 2.85-2.358.37-.533.554-1.162.554-1.887 0-.437-.082-.759-.246-.964-.15-.205-.328-.307-.533-.307-.137 0-.328.048-.574.143-.37.123-.67.185-.903.185-.547 0-1.032-.205-1.456-.615-.424-.41-.636-.923-.636-1.538 0-.698.212-1.238.636-1.62a3.002 3.002 0 0 1 2.051-.78c.93 0 1.757.39 2.481 1.17.725.778 1.087 1.742 1.087 2.89 0 1.614-.601 3.084-1.804 4.41-.807.875-1.976 1.593-3.507 2.153z" fill="#454545" fill-rule="evenodd"/></svg>
+<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><g fill="#000" fill-rule="evenodd"><path d="M3 10.423a6.5 6.5 0 0 1 6.056-6.408l.038.67C6.448 5.423 5.354 7.663 5.22 10H9c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.011-.563zM11 10.423a6.5 6.5 0 0 1 6.056-6.408l.038.67c-2.646.739-3.74 2.979-3.873 5.315H17c.552 0 .5.432.5.986v4.511c0 .554-.448.503-1 .503h-5c-.552 0-.5-.449-.5-1.003v-4.011-.563z"/></g></svg>

+ 0 - 1
packages/ckeditor5-core/theme/icons/source.svg

@@ -1 +0,0 @@
-<svg width="20" height="20" viewBox="0 0 20 20" xmlns="http://www.w3.org/2000/svg"><path d="M15.116 7.961l2.426 2.206-.01-.417-.01-.525-5.87 5.831.916.923 5.87-5.832.485-.482-.506-.46-2.419-2.198-.882.954zm-2.96-2.69l-.483-.44.874-.961.491.446-.882.955zm-7.041 7.612l-2.442-2.22-.507-.46.486-.483 5.87-5.83.915.922-5.87 5.83-.02-.941 2.45 2.227-.882.955zm2.96 2.69l.467.425.875-.962-.46-.417-.882.955zM4.518 17.43L17.475 3.422l-.954-.882L3.564 16.548l.954.882z" fill="#232323" fill-rule="evenodd"/></svg>

Некоторые файлы не были показаны из-за большого количества измененных файлов