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

Merge pull request #192 from ckeditor/t/185

Implemented a real editor.
Piotrek Koszuliński 9 лет назад
Родитель
Сommit
7ffe71c9f0
55 измененных файлов с 1005 добавлено и 2987 удалено
  1. 4 1
      bender.js
  2. 0 118
      ckeditor.js
  3. 9 6
      package.json
  4. 0 26
      src/creator/creator.js
  5. 0 173
      src/creator/standardcreator.js
  6. 0 112
      src/editable.js
  7. 0 60
      src/editablecollection.js
  8. 0 351
      src/editor.js
  9. 196 0
      src/editor/editor.js
  10. 120 0
      src/editor/standardeditor.js
  11. 95 0
      tests/_utils-tests/classictesteditor.js
  12. 85 0
      tests/_utils-tests/modeltesteditor.js
  13. 0 57
      tests/_utils-tests/utils.js
  14. 45 0
      tests/_utils-tests/virtualtesteditor.js
  15. 61 0
      tests/_utils/classictesteditor.js
  16. 61 0
      tests/_utils/modeltesteditor.js
  17. 0 35
      tests/_utils/ui/boxlesseditorui/boxlesseditorui.js
  18. 0 28
      tests/_utils/ui/editableui/framed/framededitableuiiframe.js
  19. 0 104
      tests/_utils/ui/editableui/framed/framededitableuiiframeview.js
  20. 0 16
      tests/_utils/ui/editableui/framed/framededitableuiview.js
  21. 0 16
      tests/_utils/ui/floatingtoolbar/floatingtoolbar.js
  22. 0 27
      tests/_utils/ui/floatingtoolbar/floatingtoolbarview.js
  23. 0 27
      tests/_utils/utils.js
  24. 47 0
      tests/_utils/virtualtesteditor.js
  25. 0 2
      tests/ckeditor.html
  26. 0 215
      tests/ckeditor.js
  27. 8 7
      tests/command/attributecommand.js
  28. 3 8
      tests/command/command.js
  29. 0 36
      tests/creator/creator.js
  30. 0 55
      tests/creator/manual/_assets/styles.css
  31. 0 90
      tests/creator/manual/_utils/creator/inlinecreator.js
  32. 0 76
      tests/creator/manual/_utils/creator/legacycreator.js
  33. 0 91
      tests/creator/manual/_utils/creator/multicreator.js
  34. 0 13
      tests/creator/manual/creator-inline.html
  35. 0 47
      tests/creator/manual/creator-inline.js
  36. 0 21
      tests/creator/manual/creator-inline.md
  37. 0 13
      tests/creator/manual/creator-legacy.html
  38. 0 51
      tests/creator/manual/creator-legacy.js
  39. 0 23
      tests/creator/manual/creator-legacy.md
  40. 0 20
      tests/creator/manual/creator-multi.html
  41. 0 60
      tests/creator/manual/creator-multi.js
  42. 0 22
      tests/creator/manual/creator-multi.md
  43. 0 3
      tests/creator/standardcreator.html
  44. 0 239
      tests/creator/standardcreator.js
  45. 0 128
      tests/editable.js
  46. 0 104
      tests/editablecollection.js
  47. 0 223
      tests/editor/baseeditor.js
  48. 0 176
      tests/editor/creator.js
  49. 78 0
      tests/editor/editor-base.js
  50. 33 82
      tests/editor/editor.js
  51. 136 0
      tests/editor/standardeditor.js
  52. 7 7
      tests/keystrokehandler.js
  53. 6 6
      tests/load.js
  54. 2 4
      tests/plugin.js
  55. 9 8
      tests/plugincollection.js

+ 4 - 1
bender.js

@@ -41,7 +41,10 @@ const config = {
 			'build/amd/tests/**/_*/*.js',
 			'build/amd/tests/**/_*/*.js',
 			'!build/amd/ckeditor5/*/lib/**'
 			'!build/amd/ckeditor5/*/lib/**'
 		]
 		]
-	}
+	},
+
+	// Due to https://github.com/ckeditor/ckeditor5/issues/190.
+	testTimeout: 5 * 1000 // 5s
 };
 };
 
 
 module.exports = config;
 module.exports = config;

+ 0 - 118
ckeditor.js

@@ -1,118 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import Editor from './ckeditor5/editor.js';
-import Collection from './ckeditor5/utils/collection.js';
-import CKEditorError from './ckeditor5/utils/ckeditorerror.js';
-import isArrayLike from './ckeditor5/utils/lib/lodash/isArrayLike.js';
-import clone from './ckeditor5/utils/lib/lodash/clone.js';
-import uid from './ckeditor5/utils/uid.js';
-
-/**
- * This is the API entry point. The entire CKEditor code runs under this object.
- *
- * @namespace CKEDITOR
- */
-const CKEDITOR = {
-	/**
-	 * A collection containing all editor instances created.
-	 *
-	 * @readonly
-	 * @member {utils.Collection} CKEDITOR.instances
-	 */
-	instances: new Collection(),
-
-	/**
-	 * Creates an editor instance for the provided DOM element.
-	 *
-	 * The creation of editor instances is an asynchronous operation, therefore a promise is returned by this
-	 * method.
-	 *
-	 *		CKEDITOR.create( '#content' );
-	 *
-	 *		CKEDITOR.create( '#content' ).then( ( editor ) => {
-	 *			// Manipulate "editor" here.
-	 *		} );
-	 *
-	 * @method CKEDITOR.create
-	 * @param {String|HTMLElement|HTMLCollection|NodeList|Array.<HTMLElement>|Object.<String, HTMLElement>} elements
-	 * One or more elements on which the editor will be initialized. Different creators can handle these
-	 * elements differently, but usually a creator loads the data from the element and either makes
-	 * it editable or hides it and inserts the editor UI next to it.
-	 * @returns {Promise} A promise, which will be fulfilled with the created editor.
-	 */
-	create( elements, config ) {
-		return new Promise( ( resolve ) => {
-			const editor = new Editor( normalizeElements( elements ), config );
-
-			this.instances.add( editor );
-
-			// Remove the editor from `instances` when destroyed.
-			editor.once( 'destroy', () => {
-				this.instances.remove( editor );
-			} );
-
-			resolve(
-				// Initializes the editor, which returns a promise.
-				editor.init()
-					.then( () => {
-						// After initialization, return the created editor.
-						return editor;
-					} )
-			);
-		} );
-	}
-};
-
-export default CKEDITOR;
-
-function normalizeElements( elements ) {
-	let elementsObject;
-
-	// If a query selector has been passed, transform it into a real element.
-	if ( typeof elements == 'string' ) {
-		elementsObject = toElementsObject( document.querySelectorAll( elements ) );
-	}
-	// Arrays and array-like objects.
-	else if ( isArrayLike( elements ) ) {
-		elementsObject = toElementsObject( elements );
-	}
-	// Single HTML element.
-	else if ( elements instanceof HTMLElement ) {
-		elementsObject = toElementsObject( [ elements ] );
-	}
-	// Object.
-	else {
-		elementsObject = clone( elements );
-	}
-
-	if ( !Object.keys( elementsObject ).length ) {
-		throw new CKEditorError( 'ckeditor5-create-no-elements: No elements have been passed to CKEDITOR.create()' );
-	}
-
-	return elementsObject;
-}
-
-function toElementsObject( elements ) {
-	return Array.from( elements ).reduce( ( ret, el ) => {
-		ret[ getEditorElementName( el ) ] = el;
-
-		return ret;
-	}, {} );
-}
-
-function getEditorElementName( element ) {
-	if ( element.id ) {
-		return element.id;
-	}
-
-	if ( element.dataset.editable ) {
-		return element.dataset.editable;
-	}
-
-	return 'editable' + uid();
-}

+ 9 - 6
package.json

@@ -8,14 +8,17 @@
     "WYSIWYG"
     "WYSIWYG"
   ],
   ],
   "dependencies": {
   "dependencies": {
-    "ckeditor5-creator-classic": "ckeditor/ckeditor5-creator-classic",
-    "ckeditor5-delete": "ckeditor/ckeditor5-delete",
-    "ckeditor5-engine": "ckeditor/ckeditor5-engine",
-    "ckeditor5-enter": "ckeditor/ckeditor5-enter",
+    "ckeditor5-basic-styles": "ckeditor/ckeditor5-basic-styles#t/1",
+    "ckeditor5-creator-classic": "ckeditor/ckeditor5-creator-classic#t/9",
+    "ckeditor5-delete": "ckeditor/ckeditor5-delete#t/6",
+    "ckeditor5-engine": "ckeditor/ckeditor5-engine#t/452",
+    "ckeditor5-enter": "ckeditor/ckeditor5-enter#t/12",
+    "ckeditor5-paragraph": "ckeditor/ckeditor5-paragraph#t/1",
     "ckeditor5-theme-lark": "ckeditor/ckeditor5-theme-lark",
     "ckeditor5-theme-lark": "ckeditor/ckeditor5-theme-lark",
-    "ckeditor5-ui": "ckeditor/ckeditor5-ui",
+    "ckeditor5-typing": "ckeditor/ckeditor5-typing#t/1",
+    "ckeditor5-ui": "ckeditor/ckeditor5-ui#t/37",
     "ckeditor5-ui-default": "ckeditor/ckeditor5-ui-default",
     "ckeditor5-ui-default": "ckeditor/ckeditor5-ui-default",
-    "ckeditor5-undo": "ckeditor/ckeditor5-undo",
+    "ckeditor5-undo": "ckeditor/ckeditor5-undo#t/5",
     "ckeditor5-utils": "ckeditor/ckeditor5-utils",
     "ckeditor5-utils": "ckeditor/ckeditor5-utils",
     "requirejs": "Reinmar/requirejs"
     "requirejs": "Reinmar/requirejs"
   },
   },

+ 0 - 26
src/creator/creator.js

@@ -1,26 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import Plugin from '../plugin.js';
-
-/**
- * Base creator class.
- *
- * @memberOf ckeditor5.creator
- * @extends ckeditor5.Plugin
- */
-export default class Creator extends Plugin {
-	/**
-	 * The creator's trigger. This method is called by the editor to finalize
-	 * the editor creation.
-	 *
-	 * @returns {Promise}
-	 */
-	create() {
-		return Promise.resolve();
-	}
-}

+ 0 - 173
src/creator/standardcreator.js

@@ -1,173 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import Creator from './creator.js';
-import Document from '../engine/model/document.js';
-import DataController from '../engine/datacontroller.js';
-import EditingController from '../engine/editingcontroller.js';
-import HtmlDataProcessor from '../engine/dataprocessor/htmldataprocessor.js';
-import KeystrokeHandler from '../keystrokehandler.js';
-
-/**
- * Standard creator for browser environment.
- *
- * @memberOf ckeditor5.creator
- * @extends ckeditor5.creator.Creator
- */
-export default class StandardCreator extends Creator {
-	/**
-	 * Creates an instance of the standard creator. Initializes the engine ({@link engine.model.Document document},
-	 * {@link engine.EditingController editing controller} and
-	 * {@link engine.DataController data controller}).
-	 *
-	 * @param {ckeditor5.Editor} editor The editor instance.
-	 * @param {engine.dataProcessor.DataProcessor} [dataProcessor=engine.dataProcessor.HtmlDataProcessor] The data
-	 * processor to use. If no data processor is provided {@link engine.dataProcessor.HtmlDataProcessor HtmlDataProcessor}
-	 * will be used.
-	 */
-	constructor( editor, dataProcessor = new HtmlDataProcessor() ) {
-		super( editor );
-
-		editor.document = new Document();
-		editor.editing = new EditingController( editor.document );
-		editor.data = new DataController( editor.document, dataProcessor );
-		editor.keystrokes = new KeystrokeHandler( editor );
-
-		/**
-		 * The elements replaced by {@link ckeditor5.creator.StandardCreator#_replaceElement} and their replacements.
-		 *
-		 * @private
-		 * @member {Array.<Object>} ckeditor5.creator.StandardCreator#_replacedElements
-		 */
-		this._replacedElements = [];
-	}
-
-	destroy() {
-		const editor = this.editor;
-
-		super.destroy();
-
-		editor.document.destroy();
-		editor.editing.destroy();
-		editor.data.destroy();
-
-		this._restoreElements();
-	}
-
-	/**
-	 * Updates the {@link ckeditor5.Editor#element editor element}'s content with the data.
-	 *
-	 * @param [elementName] If not specified, the first element will be used.
-	 */
-	updateEditorElement( elementName ) {
-		if ( !elementName ) {
-			elementName = this.editor.firstElementName;
-		}
-
-		StandardCreator.setDataInElement( this.editor.elements.get( elementName ), this.editor.getData( elementName ) );
-	}
-
-	/**
-	 * Updates all {@link ckeditor5.Editor#element editor elements} content with the data taken from
-	 * their corresponding editables.
-	 */
-	updateEditorElements() {
-		this.editor.elements.forEach( ( editorElement, elementName ) => {
-			this.updateEditorElement( elementName );
-		} );
-	}
-
-	/**
-	 * Loads the data from the given {@link ckeditor5.Editor#element editor element} to the editable.
-	 *
-	 * @param [elementName] If not specified, the first element will be used.
-	 */
-	loadDataFromEditorElement( elementName ) {
-		if ( !elementName ) {
-			elementName = this.editor.firstElementName;
-		}
-
-		this.editor.setData( StandardCreator.getDataFromElement( this.editor.elements.get( elementName ) ), elementName );
-	}
-
-	/**
-	 * Loads the data from all {@link ckeditor5.Editor#element editor elements} to their corresponding editables.
-	 */
-	loadDataFromEditorElements() {
-		this.editor.elements.forEach( ( editorElement, elementName ) => {
-			this.loadDataFromEditorElement( elementName );
-		} );
-	}
-
-	/**
-	 * Gets data from a given source element.
-	 *
-	 * @param {HTMLElement} el The element from which the data will be retrieved.
-	 * @returns {String} The data string.
-	 */
-	static getDataFromElement( el ) {
-		if ( el instanceof HTMLTextAreaElement ) {
-			return el.value;
-		}
-
-		return el.innerHTML;
-	}
-
-	/**
-	 * Sets data in a given element.
-	 *
-	 * @param {HTMLElement} el The element in which the data will be set.
-	 * @param {String} data The data string.
-	 */
-	static setDataInElement( el, data ) {
-		if ( el instanceof HTMLTextAreaElement ) {
-			el.value = data;
-		}
-
-		el.innerHTML = data;
-	}
-
-	/**
-	 * Hides one of the {@link ckeditor5.Editor#elements editor elements} and, if specified, inserts the the given element
-	 * (e.g. the editor's UI main element) next to it.
-	 *
-	 * The effect of this method will be automatically reverted by {@link ckeditor5.creator.StandardCreator#destroy destroy}.
-	 *
-	 * The second argument may not be passed and then the element will be replaced by nothing, so in other words it will
-	 * be hidden.
-	 *
-	 * @protected
-	 * @param {HTMLElement} element The element to replace.
-	 * @param {HTMLElement} [newElement] The replacement element. If not passed, then the `element` will just be hidden.
-	 */
-	_replaceElement( element, newElement ) {
-		this._replacedElements.push( { element, newElement } );
-
-		element.style.display = 'none';
-
-		if ( newElement ) {
-			element.parentNode.insertBefore( newElement, element.nextSibling );
-		}
-	}
-
-	/**
-	 * Restores what the {@link ckeditor5.creator.StandardCreator#_replaceElement _replaceElement} did.
-	 *
-	 * @protected
-	 */
-	_restoreElements() {
-		this._replacedElements.forEach( ( { element, newElement } ) => {
-			element.style.display = '';
-
-			if ( newElement ) {
-				newElement.remove();
-			}
-		} );
-
-		this._replacedElements = [];
-	}
-}

+ 0 - 112
src/editable.js

@@ -1,112 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import mix from './utils/mix.js';
-import ObservableMixin from './utils/observablemixin.js';
-import FocusObserver from './engine/view/observer/focusobserver.js';
-
-/**
- * Class representing a single editable element. It combines the {@link ckeditor5.Editable#viewElement editable view}
- * with the {@link ckeditor5.Editable#domElement editable DOM element} to which the view is rendering.
- *
- * @memberOf ckeditor5
- * @mixes utils.ObservaleMixin
- */
-export default class Editable {
-	/**
-	 * Creates a new instance of the Editable class.
-	 *
-	 * @param {ckeditor5.Editor} editor The editor instance.
-	 * @param {String} name The name of the editable.
-	 */
-	constructor( editor, name ) {
-		/**
-		 * The editor instance.
-		 *
-		 * @readonly
-		 * @member {ckeditor5.Editor} ckeditor5.Editable#editor
-		 */
-		this.editor = editor;
-
-		/**
-		 * The name of the editable.
-		 *
-		 * @readonly
-		 * @member {String} ckeditor5.Editable#name
-		 */
-		this.name = name;
-
-		/**
-		 * Whether the editable is in read-write or read-only mode.
-		 *
-		 * @observable
-		 * @member {Boolean} ckeditor5.Editable#isEditable
-		 */
-		this.set( 'isEditable', true );
-
-		/**
-		 * Whether the editable is focused.
-		 *
-		 * @readonly
-		 * @observable
-		 * @member {Boolean} ckeditor5.Editable#isFocused
-		 */
-		this.set( 'isFocused', false );
-
-		/**
-		 * The editable DOM element.
-		 *
-		 * @readonly
-		 * @member {HTMLElement} ckeditor5.Editable#domElement
-		 */
-
-		/**
-		 * The view element which holds this editable.
-		 *
-		 * @readonly
-		 * @member {engine.view.Element} ckeditor5.Editable#viewElement
-		 */
-	}
-
-	/**
-	 * Binds the {@link ckeditor5.Editable#viewElement editable's view} to a concrete DOM element.
-	 *
-	 * @param {HTMLElement} domElement The DOM element which holds the editable.
-	 */
-	bindTo( domElement ) {
-		const editingView = this.editor.editing.view;
-		const viewElement = editingView.createRoot( domElement, this.name );
-
-		this.domElement = domElement;
-		this.viewElement = viewElement;
-
-		// Move to EditingController constructor.
-		editingView.addObserver( FocusObserver );
-
-		this.listenTo( editingView, 'focus', ( evt, data ) => {
-			if ( data.target === this.viewElement ) {
-				this.isFocused = true;
-			}
-		} );
-
-		this.listenTo( editingView, 'blur', ( evt, data ) => {
-			if ( data.target === this.viewElement ) {
-				this.isFocused = false;
-			}
-		} );
-	}
-
-	/**
-	 * Destroys the editable.
-	 */
-	destroy() {
-		this.stopListening();
-		this.domElement = this.viewElement = null;
-	}
-}
-
-mix( Editable, ObservableMixin );

+ 0 - 60
src/editablecollection.js

@@ -1,60 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import mix from './utils/mix.js';
-import Collection from './utils/collection.js';
-import ObservableMixin from './utils/observablemixin.js';
-
-/**
- * A collection of {@link ckeditor5.Editable editables}.
- *
- * @memberOf ckeditor5
- * @mixes utils.ObservaleMixin
- * @extends utils.Collection
- */
-export default class EditableCollection extends Collection {
-	/**
-	 * Creates a new instance of EditableCollection.
-	 */
-	constructor() {
-		super( { idProperty: 'name' } );
-
-		/**
-		 * The currently focused editable.
-		 *
-		 * @readonly
-		 * @observable
-		 * @member {ckeditor5.Editable} ckeditor5.EditableCollection#current
-		 */
-		this.set( 'current', null );
-
-		this.on( 'add', ( evt, editable ) => {
-			this.listenTo( editable, 'change:isFocused', ( evt, name, value ) => {
-				this.current = value ? editable : null;
-			} );
-		} );
-
-		this.on( 'remove', ( evt, editable ) => {
-			this.stopListening( editable );
-		} );
-	}
-
-	/**
-	 * Destroys the collection.
-	 */
-	destroy() {
-		this.stopListening();
-
-		for ( let editable of this ) {
-			editable.destroy();
-		}
-
-		this.clear();
-	}
-}
-
-mix( EditableCollection, ObservableMixin );

+ 0 - 351
src/editor.js

@@ -1,351 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import ObservableMixin from './utils/observablemixin.js';
-import Config from './utils/config.js';
-import PluginCollection from './plugincollection.js';
-import EditableCollection from './editablecollection.js';
-import CKEditorError from './utils/ckeditorerror.js';
-import Locale from './utils/locale.js';
-import isArray from './utils/lib/lodash/isArray.js';
-import nth from './utils/nth.js';
-import mix from './utils/mix.js';
-
-/**
- * Represents a single editor instance.
- *
- * @memberOf ckeditor5
- * @mixes utils.ObservaleMixin
- */
-export default class Editor {
-	/**
-	 * Creates a new instance of the Editor class.
-	 *
-	 * This constructor should be rarely used. When creating new editor instance use instead the
-	 * {@link CKEDITOR#create `CKEDITOR.create()` method}.
-	 *
-	 * @param {Object.<String, HTMLElement>|null} [elements] The DOM elements that will be the source
-	 * for the created editor.
-	 * @param {Object} config The editor config.
-	 */
-	constructor( elements, config ) {
-		/**
-		 * The original host page elements upon which the editor is created.
-		 *
-		 * @readonly
-		 * @member {Map.<String, HTMLElement>|null} ckeditor5.Editor#elements
-		 */
-		if ( elements ) {
-			this.elements = new Map();
-
-			for ( let name in elements ) {
-				this.elements.set( name, elements[ name ] );
-			}
-		} else {
-			this.elements = null;
-		}
-
-		/**
-		 * Holds all configurations specific to this editor instance.
-		 *
-		 * @readonly
-		 * @member {utils.Config} ckeditor5.Editor#config
-		 */
-		this.config = config = new Config( config );
-
-		/**
-		 * The plugins loaded and in use by this editor instance.
-		 *
-		 * @readonly
-		 * @member {ckeditor5.PluginCollection} ckeditor5.Editor#plugins
-		 */
-		this.plugins = new PluginCollection( this );
-
-		/**
-		 * The editables of the editor.
-		 *
-		 * @readonly
-		 * @member {ckeditor5.EditableCollection} ckeditor5.Editor#editables
-		 */
-		this.editables = new EditableCollection();
-
-		/**
-		 * Commands registered to the editor.
-		 *
-		 * @readonly
-		 * @member {Map.<ckeditor5.command.Command>} ckeditor5.Editor#commands
-		 */
-		this.commands = new Map();
-
-		/**
-		 * @readonly
-		 * @member {utils.Locale} ckeditor5.Editor#locale
-		 */
-		this.locale = new Locale( config.lang );
-
-		/**
-		 * Shorthand for {@link utils.Locale#t}.
-		 *
-		 * @see utils.Locale#t
-		 * @method ckeditor5.Editor#t
-		 */
-		this.t = this.locale.t;
-
-		/**
-		 * Tree Model document managed by this editor.
-		 *
-		 * This property is set by the {@link ckeditor5.creator.Creator}.
-		 *
-		 * @readonly
-		 * @member {engine.model.Document} ckeditor5.Editor#document
-		 */
-
-		/**
-		 * Instance of the {@link engine.EditingController editing controller}.
-		 *
-		 * This property is set by the {@link ckeditor5.creator.Creator}.
-		 *
-		 * @readonly
-		 * @member {engine.EditingController} ckeditor5.Editor#editing
-		 */
-
-		/**
-		 * Instance of the {@link engine.DataController data controller}.
-		 *
-		 * This property is set by the {@link ckeditor5.creator.Creator}.
-		 *
-		 * @readonly
-		 * @member {engine.DataController} ckeditor5.Editor#data
-		 */
-
-		/**
-		 * Instance of the {@link ckeditor5.KeystrokeHandler}.
-		 *
-		 * This property is set by the {@link ckeditor5.creator.Creator}.
-		 *
-		 * @readonly
-		 * @member {engine.treecontroller.DataController} ckeditor5.Editor#keystrokes
-		 */
-
-		/**
-		 * The chosen creator.
-		 *
-		 * @protected
-		 * @member {ckeditor5.creator.Creator} ckeditor5.Editor#_creator
-		 */
-	}
-
-	/**
-	 * First element from {@link ckeditor5.Editor#elements}.
-	 *
-	 * @readonly
-	 * @type {HTMLElement|null}
-	 */
-	get firstElement() {
-		if ( !this.elements ) {
-			return null;
-		}
-
-		return nth( 0, this.elements )[ 1 ];
-	}
-
-	/**
-	 * Name of the first element from {@link ckeditor5.Editor#elements}.
-	 *
-	 * @readonly
-	 * @type {String|null}
-	 */
-	get firstElementName() {
-		if ( !this.elements ) {
-			return null;
-		}
-
-		return nth( 0, this.elements )[ 0 ];
-	}
-
-	/**
-	 * Initializes the editor instance object after its creation.
-	 *
-	 * The initialization consists of the following procedures:
-	 *
-	 * * Loading and initializing the configured features and creator.
-	 * * Firing the editor creator.
-	 *
-	 * This method should be rarely used as {@link CKEDITOR#create} calls it one should never use the `Editor`
-	 * constructor directly.
-	 *
-	 * @returns {Promise} A promise which resolves once the initialization is completed.
-	 */
-	init() {
-		const that = this;
-		const config = this.config;
-		let creatorName = config.creator;
-
-		if ( !creatorName ) {
-			/**
-			 * The `config.creator` option was not defined.
-			 *
-			 * @error editor-undefined-creator
-			 */
-			return Promise.reject(
-				new CKEditorError( 'editor-undefined-creator: The config.creator option was not defined.' )
-			);
-		}
-
-		return loadPlugins()
-			.then( initPlugins )
-			.then( fireCreator );
-
-		function loadPlugins() {
-			let plugins = config.features || [];
-
-			// Handle features passed as a string.
-			if ( !isArray( plugins ) ) {
-				plugins = plugins.split( ',' );
-			}
-
-			plugins.push( creatorName );
-
-			return that.plugins.load( plugins );
-		}
-
-		function initPlugins( loadedPlugins ) {
-			return loadedPlugins.reduce( ( promise, plugin ) => {
-				return promise.then( plugin.init.bind( plugin ) );
-			}, Promise.resolve() );
-		}
-
-		function fireCreator() {
-			// We can always get the creator by its name because config.creator (which is requried) is passed
-			// to PluginCollection.load().
-			that._creator = that.plugins.get( creatorName );
-
-			// Finally fire the creator. It may be asynchronous, returning a promise.
-			return that._creator.create();
-		}
-	}
-
-	/**
-	 * Destroys the editor instance, releasing all resources used by it. If the editor replaced an element, the
-	 * element will be recovered.
-	 *
-	 * @fires ckeditor5.Editor#destroy
-	 * @returns {Promise} A promise that resolves once the editor instance is fully destroyed.
-	 */
-	destroy() {
-		this.fire( 'destroy' );
-		this.stopListening();
-
-		// Note: The destruction order should be the reverse of the initialization order.
-		return Promise.resolve()
-			.then( () => {
-				return this._creator && this._creator.destroy();
-			} )
-			.then( () => this.editables.destroy() );
-	}
-
-	/**
-	 * Sets the data in the specified editor's editable root.
-	 *
-	 * @param {*} data The data to load.
-	 * @param {String} [editableRootName] The name of the editable root to which the data should be loaded.
-	 * If not specified and if there's only one editable root added to the editor, then the data will be loaded
-	 * to that editable.
-	 */
-	setData( data, editableRootName ) {
-		if ( !this.data ) {
-			/**
-			 * Data controller has not been defined yet, so methds like {@link ckeditor5.Editor#setData} and
-			 * {@link ckeditor5.Editor#getData} cannot be used.
-			 *
-			 * @error editor-no-datacontroller
-			 */
-			throw new CKEditorError( 'editor-no-datacontroller: Data controller has not been defined yet.' );
-		}
-
-		this.data.set( data, editableRootName || this._getDefaultRootName() );
-	}
-
-	/**
-	 * Gets the data from the specified editor's editable root.
-	 *
-	 * @param {String} [editableRootName] The name of the editable root to get the data from.
-	 * If not specified and if there's only one editable root added to the editor, then the data will be retrieved
-	 * from it.
-	 */
-	getData( editableRootName ) {
-		if ( !this.data ) {
-			throw new CKEditorError( 'editor-no-datacontroller: Data controller has not been defined yet.' );
-		}
-
-		return this.data.get( editableRootName || this._getDefaultRootName() );
-	}
-
-	/**
-	 * Executes specified command with given parameter.
-	 *
-	 * @param {String} commandName Name of command to execute.
-	 * @param {*} [commandParam] If set, command will be executed with this parameter.
-	 */
-	execute( commandName, commandParam ) {
-		let command = this.commands.get( commandName );
-
-		if ( !command ) {
-			/**
-			 * Specified command has not been added to the editor.
-			 *
-			 * @error editor-command-not-found
-			 */
-			throw new CKEditorError( 'editor-command-not-found: Specified command has not been added to the editor.' );
-		}
-
-		command._execute( commandParam );
-	}
-
-	/**
-	 * Returns name of the editable root if there is only one. If there are multiple or no editable roots, throws an error.
-	 *
-	 * Note: The error message makes sense only for methods like {@link ckeditor5.Editor#setData} and
-	 * {@link ckeditor5.Editor#getData}.
-	 *
-	 * @private
-	 * @returns {String}
-	 */
-	_getDefaultRootName() {
-		const rootNames = Array.from( this.document.rootNames );
-
-		if ( rootNames.length > 1 ) {
-			/**
-			 * The name of the editable root must be specified. There are multiple editable roots added to the editor,
-			 * so the name of the editable must be specified.
-			 *
-			 * @error editor-editable-root-name-missing
-			 */
-			throw new CKEditorError( 'editor-editable-root-name-missing: The name of the editable root must be specified.' );
-		}
-
-		if ( rootNames.length === 0 ) {
-			/**
-			 * The editor does not contain any editable roots, so the data cannot be set or read from it.
-			 *
-			 * @error editor-no-editable-roots
-			 */
-			throw new CKEditorError( 'editor-no-editable-roots: There are no editable roots defined.' );
-		}
-
-		return rootNames[ 0 ];
-	}
-}
-
-mix( Editor, ObservableMixin );
-
-/**
- * Fired when this editor instance is destroyed. The editor at this point is not usable and this event should be used to
- * perform the clean-up in any plugin.
- *
- * @event ckeditor5.Editor#destroy
- */

+ 196 - 0
src/editor/editor.js

@@ -0,0 +1,196 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import EmitterMixin from '../utils/emittermixin.js';
+import Config from '../utils/config.js';
+import PluginCollection from '../plugincollection.js';
+import Locale from '../utils/locale.js';
+import DataController from '../engine/datacontroller.js';
+import Document from '../engine/model/document.js';
+
+import CKEditorError from '../utils/ckeditorerror.js';
+import isArray from '../utils/lib/lodash/isArray.js';
+import mix from '../utils/mix.js';
+
+/**
+ * Class representing a basic editor. It contains a base architecture, without much additional logic.
+ *
+ * See also {@link ckeditor5.editor.StandardEditor}.
+ *
+ * @memberOf ckeditor5.editor
+ * @mixes utils.EmitterMixin
+ */
+export default class Editor {
+	/**
+	 * Creates a new instance of the Editor class.
+	 *
+	 * @param {Object} config The editor config.
+	 */
+	constructor( config ) {
+		/**
+		 * Holds all configurations specific to this editor instance.
+		 *
+		 * @readonly
+		 * @member {utils.Config} ckeditor5.Editor#config
+		 */
+		this.config = new Config( config );
+
+		/**
+		 * The plugins loaded and in use by this editor instance.
+		 *
+		 * @readonly
+		 * @member {ckeditor5.PluginCollection} ckeditor5.Editor#plugins
+		 */
+		this.plugins = new PluginCollection( this );
+
+		/**
+		 * Commands registered to the editor.
+		 *
+		 * @readonly
+		 * @member {Map.<ckeditor5.command.Command>} ckeditor5.Editor#commands
+		 */
+		this.commands = new Map();
+
+		/**
+		 * @readonly
+		 * @member {utils.Locale} ckeditor5.Editor#locale
+		 */
+		this.locale = new Locale( this.config.get( 'lang' ) );
+
+		/**
+		 * Shorthand for {@link utils.Locale#t}.
+		 *
+		 * @see utils.Locale#t
+		 * @method ckeditor5.Editor#t
+		 */
+		this.t = this.locale.t;
+
+		/**
+		 * Tree Model document managed by this editor.
+		 *
+		 * @readonly
+		 * @member {engine.model.Document} ckeditor5.Editor#document
+		 */
+		this.document = new Document();
+
+		/**
+		 * Instance of the {@link engine.DataController data controller}.
+		 *
+		 * @readonly
+		 * @member {engine.DataController} ckeditor5.Editor#data
+		 */
+		this.data = new DataController( this.document );
+
+		/**
+		 * Instance of the {@link engine.EditingController editing controller}.
+		 *
+		 * This property is set by more specialized editor classes (such as {@link ckeditor5.editor.StandardEditor}),
+		 * however, it's required for features to work as their engine-related parts will try to connect converters.
+		 *
+		 * 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 {engine.EditingController} ckeditor5.editor.Editor#editing
+		 */
+	}
+
+	/**
+	 * Loads and initilizes plugins specified in `config.features`.
+	 *
+	 * @returns {Promise} A promise which resolves once the initialization is completed.
+	 */
+	initPlugins() {
+		const that = this;
+		const config = this.config;
+
+		return loadPlugins()
+			.then( initPlugins );
+
+		function loadPlugins() {
+			let plugins = config.features || [];
+
+			// Handle features passed as a string.
+			if ( !isArray( plugins ) ) {
+				plugins = plugins.split( ',' );
+			}
+
+			return that.plugins.load( plugins );
+		}
+
+		function initPlugins( loadedPlugins ) {
+			return loadedPlugins.reduce( ( promise, plugin ) => {
+				return promise.then( plugin.init.bind( plugin ) );
+			}, Promise.resolve() );
+		}
+	}
+
+	/**
+	 * Destroys the editor instance, releasing all resources used by it.
+	 *
+	 * @fires ckeditor5.editor.Editor#destroy
+	 * @returns {Promise} A promise that resolves once the editor instance is fully destroyed.
+	 */
+	destroy() {
+		this.fire( 'destroy' );
+		this.stopListening();
+
+		return Promise.resolve()
+			.then( () => {
+				this.document.destroy();
+				this.data.destroy();
+			} );
+	}
+
+	/**
+	 * Executes specified command with given parameter.
+	 *
+	 * @param {String} commandName Name of command to execute.
+	 * @param {*} [commandParam] If set, command will be executed with this parameter.
+	 */
+	execute( commandName, commandParam ) {
+		let command = this.commands.get( commandName );
+
+		if ( !command ) {
+			/**
+			 * Specified command has not been added to the editor.
+			 *
+			 * @error editor-command-not-found
+			 */
+			throw new CKEditorError( 'editor-command-not-found: Specified command has not been added to the editor.' );
+		}
+
+		command._execute( commandParam );
+	}
+
+	/**
+	 * Creates a basic editor instance.
+	 *
+	 * @param {Object} config See {@link ckeditor5.editor.StandardEditor}'s param.
+	 * @returns {Promise} Promise resolved once editor is ready.
+	 * @returns {ckeditor5.editor.StandardEditor} return.editor The editor instance.
+	 */
+	static create( config ) {
+		return new Promise( ( resolve ) => {
+			const editor = new this( config );
+
+			resolve(
+				editor.initPlugins()
+					.then( () => editor )
+			);
+		} );
+	}
+}
+
+mix( Editor, EmitterMixin );
+
+/**
+ * Fired when this editor instance is destroyed. The editor at this point is not usable and this event should be used to
+ * perform the clean-up in any plugin.
+ *
+ * @event ckeditor5.editor.Editor#destroy
+ */

+ 120 - 0
src/editor/standardeditor.js

@@ -0,0 +1,120 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Editor from './editor.js';
+import KeystrokeHandler from '../keystrokehandler.js';
+import EditingController from '../engine/editingcontroller.js';
+
+import getDataFromElement from '../utils/dom/getdatafromelement.js';
+import setDataInElement from '../utils/dom/setdatainelement.js';
+
+/**
+ * Class representing a typical browser-based editor. It handles a single source element and
+ * uses {@link engine.EditingController}.
+ *
+ * @memberOf ckeditor5.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} ckeditor5.editor.StandardEditor#element
+		 */
+		this.element = element;
+
+		// Documented in Editor.
+		this.editing = new EditingController( this.document );
+
+		/**
+		 * Instance of the {@link ckeditor5.KeystrokeHandler}.
+		 *
+		 * @readonly
+		 * @member {engine.treecontroller.DataController} ckeditor5.editor.StandardEditor#keystrokes
+		 */
+		this.keystrokes = new KeystrokeHandler( this );
+
+		/**
+		 * Editor UI instance.
+		 *
+		 * This property is set by more specialized editor constructors. However, it's required
+		 * for features to work (their UI-related part will try to interact with editor UI),
+		 * so every editor class which is meant to work with default features should set this property.
+		 *
+		 * @readonly
+		 * @member {ui.editorUI.EditorUI} ckeditor5.editor.StandardEditor#ui
+		 */
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	destroy() {
+		return Promise.resolve()
+			.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 ckeditor5.editor.StandardEditor#element editor element}'s content with the data.
+	 */
+	updateEditorElement() {
+		setDataInElement( this.element, this.getData() );
+	}
+
+	/**
+	 * Loads the data from the {@link ckeditor5.editor.StandardEditor#element editor element} to the main root.
+	 */
+	loadDataFromEditorElement() {
+		this.setData( getDataFromElement( this.element ) );
+	}
+
+	/**
+	 * Creates a standard editor instance.
+	 *
+	 * @param {HTMLElement} element See {@link ckeditor5.editor.StandardEditor}'s param.
+	 * @param {Object} config See {@link ckeditor5.editor.StandardEditor}'s param.
+	 * @returns {Promise} Promise resolved once editor is ready.
+	 * @returns {ckeditor5.editor.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 )
+			);
+		} );
+	}
+}

+ 95 - 0
tests/_utils-tests/classictesteditor.js

@@ -0,0 +1,95 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import StandardEditor from '/ckeditor5/editor/standardeditor.js';
+import ClassicTestEditor from '/tests/ckeditor5/_utils/classictesteditor.js';
+import HtmlDataProcessor from '/ckeditor5/engine/dataprocessor/htmldataprocessor.js';
+import BoxedEditorUI from '/ckeditor5/ui/editorui/boxed/boxededitorui.js';
+import Feature from '/ckeditor5/feature.js';
+
+import { getData } from '/tests/engine/_utils/model.js';
+import testUtils from '/tests/ckeditor5/_utils/utils.js';
+
+testUtils.createSinonSandbox();
+
+describe( 'ClassicTestEditor', () => {
+	let editorElement;
+
+	beforeEach( () => {
+		editorElement = document.createElement( 'div' );
+		document.body.appendChild( editorElement );
+	} );
+
+	describe( 'constructor', () => {
+		it( 'creates an instance of editor', () => {
+			const editor = new ClassicTestEditor( editorElement, { foo: 1 } );
+
+			expect( editor ).to.be.instanceof( StandardEditor );
+
+			expect( editor.config.get( 'foo' ) ).to.equal( 1 );
+			expect( editor ).to.have.property( 'element', editorElement );
+		} );
+
+		it( 'creates model and view roots', () => {
+			const editor = new ClassicTestEditor( { foo: 1 } );
+
+			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 );
+		} );
+	} );
+
+	describe( 'create', () => {
+		it( 'creates an instance of editor', () => {
+			return ClassicTestEditor.create( editorElement, { foo: 1 } )
+				.then( editor => {
+					expect( editor ).to.be.instanceof( ClassicTestEditor );
+
+					expect( editor.config.get( 'foo' ) ).to.equal( 1 );
+					expect( editor ).to.have.property( 'element', editorElement );
+				} );
+		} );
+
+		it( 'creates and initilizes the UI', () => {
+			return ClassicTestEditor.create( editorElement, { foo: 1 } )
+				.then( editor => {
+					expect( editor.ui ).to.be.instanceof( BoxedEditorUI );
+				} );
+		} );
+
+		it( 'loads data from the editor element', () => {
+			editorElement.innerHTML = 'foo';
+
+			class FeatureTextInRoot extends Feature {
+				init() {
+					this.editor.document.schema.allow( { name: '$text', inside: '$root' } );
+				}
+			}
+
+			return ClassicTestEditor.create( editorElement, { features: [ FeatureTextInRoot ] } )
+				.then( editor => {
+					expect( getData( editor.document, { withoutSelection: true } ) ).to.equal( 'foo' );
+				} );
+		} );
+	} );
+
+	describe( 'destroy', () => {
+		it( 'destroys UI and calls super.destroy()', () => {
+			return ClassicTestEditor.create( editorElement, { foo: 1 } )
+				.then( editor => {
+					const superSpy = testUtils.sinon.spy( StandardEditor.prototype, 'destroy' );
+					const uiSpy = sinon.spy( editor.ui, 'destroy' );
+
+					return editor.destroy()
+						.then( () => {
+							expect( superSpy.calledOnce ).to.be.true;
+							expect( uiSpy.calledOnce ).to.be.true;
+						} );
+				} );
+		} );
+	} );
+} );

+ 85 - 0
tests/_utils-tests/modeltesteditor.js

@@ -0,0 +1,85 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Editor from '/ckeditor5/editor/editor.js';
+import ModelTestEditor from '/tests/ckeditor5/_utils/modeltesteditor.js';
+import HtmlDataProcessor from '/ckeditor5/engine/dataprocessor/htmldataprocessor.js';
+import { getData, setData } from '/tests/engine/_utils/model.js';
+
+import testUtils from '/tests/ckeditor5/_utils/utils.js';
+
+testUtils.createSinonSandbox();
+
+describe( 'ModelTestEditor', () => {
+	describe( 'constructor', () => {
+		it( 'creates an instance of editor', () => {
+			const editor = new ModelTestEditor( { foo: 1 } );
+
+			expect( editor ).to.be.instanceof( Editor );
+
+			expect( editor.config.get( 'foo' ) ).to.equal( 1 );
+		} );
+
+		it( 'creates model and view roots', () => {
+			const editor = new ModelTestEditor( { foo: 1 } );
+
+			expect( editor.document.getRoot() ).to.have.property( 'name', '$root' );
+			expect( editor.data.processor ).to.be.instanceof( HtmlDataProcessor );
+		} );
+	} );
+
+	describe( 'create', () => {
+		it( 'creates an instance of editor', () => {
+			return ModelTestEditor.create( { foo: 1 } )
+				.then( editor => {
+					expect( editor ).to.be.instanceof( ModelTestEditor );
+
+					expect( editor.config.get( 'foo' ) ).to.equal( 1 );
+				} );
+		} );
+	} );
+
+	describe( 'setData', () => {
+		let editor;
+
+		beforeEach( () => {
+			return ModelTestEditor.create()
+				.then( newEditor => {
+					editor = newEditor;
+
+					editor.document.schema.allow( { name: '$text', inside: '$root' } );
+				} );
+		} );
+
+		it( 'should set data of the first root', () => {
+			editor.document.createRoot( 'secondRoot' );
+
+			editor.setData( 'foo' );
+
+			expect( getData( editor.document, { rootName: 'main', withoutSelection: true } ) ).to.equal( 'foo' );
+		} );
+	} );
+
+	describe( 'getData', () => {
+		let editor;
+
+		beforeEach( () => {
+			return ModelTestEditor.create()
+				.then( newEditor => {
+					editor = newEditor;
+
+					editor.document.schema.allow( { name: '$text', inside: '$root' } );
+				} );
+		} );
+
+		it( 'should set data of the first root', () => {
+			setData( editor.document, 'foo' );
+
+			expect( editor.getData() ).to.equal( 'foo' );
+		} );
+	} );
+} );

+ 0 - 57
tests/_utils-tests/utils.js

@@ -1,57 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import testUtils from '/tests/ckeditor5/_utils/utils.js';
-import moduleTestUtils from '/tests/ckeditor5/_utils/module.js';
-import Creator from '/ckeditor5/creator/creator.js';
-
-let createFn3 = () => {};
-let destroyFn3 = () => {};
-
-testUtils.createSinonSandbox();
-
-testUtils.defineEditorCreatorMock( 'test1' );
-testUtils.defineEditorCreatorMock( 'test2', {
-	foo: 1,
-	bar: 2
-} );
-testUtils.defineEditorCreatorMock( 'test3', {
-	create: createFn3,
-	destroy: destroyFn3
-} );
-
-const modules = moduleTestUtils.require( {
-	testCreator1: 'creator-test1/creator-test1',
-	testCreator2: 'creator-test2/creator-test2',
-	testCreator3: 'creator-test3/creator-test3'
-} );
-
-///////////////////
-
-let TestCreator1, TestCreator2, TestCreator3;
-
-before( () => {
-	TestCreator1 = modules.testCreator1;
-	TestCreator2 = modules.testCreator2;
-	TestCreator3 = modules.testCreator3;
-} );
-
-describe( 'testUtils.defineEditorCreatorMock()', () => {
-	it( 'should register all creators', () => {
-		expect( TestCreator1.prototype ).to.be.instanceof( Creator );
-		expect( TestCreator2.prototype ).to.be.instanceof( Creator );
-		expect( TestCreator3.prototype ).to.be.instanceof( Creator );
-	} );
-
-	it( 'should copy properties from the second argument', () => {
-		expect( TestCreator2.prototype ).to.have.property( 'foo', 1 );
-		expect( TestCreator2.prototype ).to.have.property( 'bar', 2 );
-
-		expect( TestCreator3.prototype ).to.have.property( 'create', createFn3 );
-		expect( TestCreator3.prototype ).to.have.property( 'destroy', destroyFn3 );
-	} );
-} );

+ 45 - 0
tests/_utils-tests/virtualtesteditor.js

@@ -0,0 +1,45 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import StandardEditor from '/ckeditor5/editor/standardeditor.js';
+import VirtualTestEditor from '/tests/ckeditor5/_utils/virtualtesteditor.js';
+import HtmlDataProcessor from '/ckeditor5/engine/dataprocessor/htmldataprocessor.js';
+
+import testUtils from '/tests/ckeditor5/_utils/utils.js';
+
+testUtils.createSinonSandbox();
+
+describe( 'VirtualTestEditor', () => {
+	describe( 'constructor', () => {
+		it( 'creates an instance of editor', () => {
+			const editor = new VirtualTestEditor( { foo: 1 } );
+
+			expect( editor ).to.be.instanceof( StandardEditor );
+
+			expect( editor.config.get( 'foo' ) ).to.equal( 1 );
+		} );
+
+		it( 'creates model and view roots', () => {
+			const editor = new VirtualTestEditor( { foo: 1 } );
+
+			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 );
+		} );
+	} );
+
+	describe( 'create', () => {
+		it( 'creates an instance of editor', () => {
+			return VirtualTestEditor.create( { foo: 1 } )
+				.then( editor => {
+					expect( editor ).to.be.instanceof( VirtualTestEditor );
+
+					expect( editor.config.get( 'foo' ) ).to.equal( 1 );
+				} );
+		} );
+	} );
+} );

+ 61 - 0
tests/_utils/classictesteditor.js

@@ -0,0 +1,61 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import StandardEditor from '/ckeditor5/editor/standardeditor.js';
+
+import HtmlDataProcessor from '/ckeditor5/engine/dataprocessor/htmldataprocessor.js';
+
+import BoxedEditorUI from '/ckeditor5/ui/editorui/boxed/boxededitorui.js';
+import BoxedEditorUIView from '/ckeditor5/ui/editorui/boxed/boxededitoruiview.js';
+
+/**
+ * A simplified classic editor. Useful for testing features.
+ *
+ * @memberOf tests.ckeditor5._utils
+ * @extends ckeditor5.editor.StandardEditor
+ */
+export default class ClassicTestEditor extends StandardEditor {
+	/**
+	 * @inheritDoc
+	 */
+	constructor( element, config ) {
+		super( element, config );
+
+		this.document.createRoot();
+
+		this.editing.createRoot( 'div' );
+
+		this.data.processor = new HtmlDataProcessor();
+
+		this.ui = new BoxedEditorUI( this );
+		this.ui.view = new BoxedEditorUIView( this.ui.viewModel, this.locale );
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	destroy() {
+		return this.ui.destroy()
+			.then( () => super.destroy() );
+	}
+
+	/**
+	 * @inheritDoc
+	 */
+	static create( element, config ) {
+		return new Promise( ( resolve ) => {
+			const editor = new this( element, config );
+
+			resolve(
+				editor.initPlugins()
+					.then( () => editor.ui.init() )
+					.then( () => editor.loadDataFromEditorElement() )
+					.then( () => editor )
+			);
+		} );
+	}
+}

+ 61 - 0
tests/_utils/modeltesteditor.js

@@ -0,0 +1,61 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import Editor from '/ckeditor5/editor/editor.js';
+import HtmlDataProcessor from '/ckeditor5/engine/dataprocessor/htmldataprocessor.js';
+
+/**
+ * A simple editor implementation with a functional model part of the engine (the document).
+ * It contains a full data pipeline but no editing pipeline.
+ *
+ * Should work in Node.js. If not now, then in the future :).
+ *
+ * @memberOf tests.ckeditor5._utils
+ */
+export default class ModelTestEditor extends Editor {
+	constructor( config ) {
+		super( config );
+
+		this.document.createRoot();
+
+		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 );
+	}
+
+	/**
+	 * Gets the data from the editor's main root.
+	 */
+	getData() {
+		return this.data.get();
+	}
+
+	/**
+	 * Creates a virtual, element-less editor instance.
+	 *
+	 * @param {Object} config See {@link ckeditor5.editor.StandardEditor}'s param.
+	 * @returns {Promise} Promise resolved once editor is ready.
+	 * @returns {ckeditor5.editor.VirtualTestEditor} return.editor The editor instance.
+	 */
+	static create( config ) {
+		return new Promise( ( resolve ) => {
+			const editor = new this( config );
+
+			resolve(
+				editor.initPlugins()
+					.then( () => editor )
+			);
+		} );
+	}
+}

+ 0 - 35
tests/_utils/ui/boxlesseditorui/boxlesseditorui.js

@@ -1,35 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import EditorUI from '/ckeditor5/ui/editorui/editorui.js';
-import ControllerCollection from '/ckeditor5/ui/controllercollection.js';
-
-export default class BoxlessEditorUI extends EditorUI {
-	constructor( editor ) {
-		super( editor );
-
-		this.collections.add( new ControllerCollection( 'editable' ) );
-
-		/**
-		 * @private
-		 * @type {ui.View}
-		 * @property _view
-		 */
-	}
-
-	get view() {
-		return this._view;
-	}
-
-	set view( view ) {
-		if ( view ) {
-			this._view = view;
-
-			view.register( 'editable', true );
-		}
-	}
-}

+ 0 - 28
tests/_utils/ui/editableui/framed/framededitableuiiframe.js

@@ -1,28 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import EditableUI from '/ckeditor5/ui/editableui/editableui.js';
-
-/**
- * The basic implementation of an iframe-based {@link ui.editableUI.EditableUI}.
- *
- * @memberOf ui.editableUI.iframe
- * @extends ui.editableUI.EditableUI
- */
-export default class FramedEditableUIIframe extends EditableUI {
-	/**
-	 * Creates a new instance of the iframe–based {@link ui.editableUI.EditableUI EditableUI}.
-	 *
-	 * @param {ckeditor5.Editor} editor The editor instance.
-	 * @param {utils.Observable} editableModel The model for the editable.
-	 */
-	constructor( editor, editableModel ) {
-		super( editor, editableModel );
-
-		this.viewModel.bind( 'width', 'height' ).to( editor.ui );
-	}
-}

+ 0 - 104
tests/_utils/ui/editableui/framed/framededitableuiiframeview.js

@@ -1,104 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import IframeView from '/ckeditor5/ui/iframe/iframeview.js';
-import FramedEditableUIView from './framededitableuiview.js';
-
-/**
- * The basic implementation of an {@link ui.iframe.IframeView IframeView}-based
- * {@link ui.editableUI.EditableUIView}.
- *
- * @memberOf ui.editableUI.iframe
- * @extends ui.iframe.IframeView
- */
-export default class FramedEditableUIIframeView extends IframeView {
-	/**
-	 * Creates a new instance of the {@link ui.iframe.IframeView IframeView}–based
-	 * {@link ui.editableUI.EditableUIView EditableUIView}.
-	 *
-	 * @param {utils.Observable} [model] (View)Model of this View.
-	 * @param {utils.Locale} [locale] The {@link ckeditor5.Editor#locale editor's locale} instance.
-	 */
-	constructor( model, locale ) {
-		super( model, locale );
-
-		const bind = this.attributeBinder;
-
-		this.template.attributes.class.push( 'ck-editor__editable-iframe' );
-		this.template.attributes.style = [
-			'width:',
-			bind.to( 'width', ( w ) => `${w}px` ),
-			';',
-			'height:',
-			bind.to( 'height', ( h ) => `${h}px`  )
-		];
-
-		this.on( 'loaded', this._iframeLoaded, this );
-
-		/**
-		 * A view which represents the editable `<body>` element within the iframe.
-		 *
-		 * @private
-		 * @member {FramedEditableUIView} ui.editableUI.iframe#_innerView
-		 */
-	}
-
-	/**
-	 * This getter exposes the {@link ui.editable.EditableUIView#editableElement}. It points to the
-	 * `<body>` inside the `<iframe>` document, which is provided by `FramedEditableUIView`.
-	 */
-	get editableElement() {
-		return this._innerView.editableElement;
-	}
-
-	/**
-	 * Destroys the View instance and child {@link _innerView}.
-	 */
-	destroy() {
-		super.destroy();
-
-		return this._innerView.destroy();
-	}
-
-	/**
-	 * When the iframe is loaded, it creates a child view out of <body> element
-	 * and initializes it. Element of this view is exposed through {@link editableElement}.
-	 *
-	 * @protected
-	 */
-	_iframeLoaded() {
-		this._innerView = new FramedEditableUIView(
-			this.model,
-			this.locale,
-			this.element.contentDocument.body
-		);
-
-		this._innerView.init();
-
-		this._iframeDeferred.resolve();
-	}
-}
-
-/**
- * The view model interface for FramedEditableUIView.
- *
- * @memberOf ui.editableUI.iframe
- * @interface FramedEditableUIViewModel
- * @mixes utils.ObservableMixin
- */
-
-/**
- * The width of the iframe.
- *
- * @member {Number} ui.editableUI.iframe.FramedEditableUIViewModel#width
- */
-
-/**
- * The height of the iframe.
- *
- * @member {Number} ui.editableUI.iframe.FramedEditableUIViewModel#height
- */

+ 0 - 16
tests/_utils/ui/editableui/framed/framededitableuiview.js

@@ -1,16 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import EditableUIView from '/ckeditor5/ui/editableui/editableuiview.js';
-
-export default class FramedEditableUIView extends EditableUIView {
-	constructor( model, locale, editableElement ) {
-		super( model, locale, editableElement );
-
-		this.template.attributes.class.push( 'ck-editor__editable_framed' );
-	}
-}

+ 0 - 16
tests/_utils/ui/floatingtoolbar/floatingtoolbar.js

@@ -1,16 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import Toolbar from '/ckeditor5/ui/bindings/toolbar.js';
-
-export default class FloatingToolbar extends Toolbar {
-	constructor( model, view, editor ) {
-		super( model, view, editor );
-
-		model.bind( 'isVisible' ).to( editor.editables.get( model.editableName ), 'isFocused' );
-	}
-}

+ 0 - 27
tests/_utils/ui/floatingtoolbar/floatingtoolbarview.js

@@ -1,27 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import ToolbarView from '/ckeditor5/ui/toolbar/toolbarview.js';
-
-export default class FloatingToolbarView extends ToolbarView {
-	constructor( model, locale ) {
-		super( model, locale );
-
-		const bind = this.attributeBinder;
-
-		this.template.attributes.class.push(
-			bind.to( 'isVisible', value => value ? 'ck-visible' : 'ck-hidden' )
-		);
-
-		// This has a high risk of breaking if someone defines "on" in the parent template.
-		// See https://github.com/ckeditor/ckeditor5-engine/issues/219
-		this.template.on = {
-			// Added just for fun, but needed to keep the focus in the editable.
-			mousedown: ( evt ) => evt.preventDefault()
-		};
-	}
-}

+ 0 - 27
tests/_utils/utils.js

@@ -5,8 +5,6 @@
 
 
 'use strict';
 'use strict';
 
 
-import moduleUtils from '/tests/ckeditor5/_utils/module.js';
-
 /**
 /**
  * General test utils for CKEditor.
  * General test utils for CKEditor.
  */
  */
@@ -35,31 +33,6 @@ const utils = {
 		afterEach( () => {
 		afterEach( () => {
 			utils.sinon.restore();
 			utils.sinon.restore();
 		} );
 		} );
-	},
-
-	/**
-	 * Defines CKEditor plugin which is a mock of an editor creator.
-	 *
-	 * The mocked creator is available under:
-	 *
-	 *		editor.plugins.get( 'creator-thename' );
-	 *
-	 * @param {String} creatorName Name of the creator.
-	 * @param {Object} [proto] Prototype of the creator. Properties from the proto param will
-	 * be copied to the prototype of the creator.
-	 */
-	defineEditorCreatorMock( creatorName, proto ) {
-		moduleUtils.define( `creator-${ creatorName }/creator-${ creatorName }`, [ 'creator/creator' ], ( Creator ) => {
-			class TestCreator extends Creator {}
-
-			if ( proto ) {
-				for ( let propName in proto ) {
-					TestCreator.prototype[ propName ] = proto[ propName ];
-				}
-			}
-
-			return TestCreator;
-		} );
 	}
 	}
 };
 };
 
 

+ 47 - 0
tests/_utils/virtualtesteditor.js

@@ -0,0 +1,47 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+'use strict';
+
+import StandardEditor from '/ckeditor5/editor/standardeditor.js';
+import HtmlDataProcessor from '/ckeditor5/engine/dataprocessor/htmldataprocessor.js';
+
+/**
+ * A simple editor implementation useful for testing the engine part of the features.
+ * It contains full data pipepilne and the engine pipeline but without rendering to DOM.
+ *
+ * Should work in Node.js. If not now, then in the future :).
+ *
+ * @memberOf tests.ckeditor5._utils
+ */
+export default class VirtualTestEditor extends StandardEditor {
+	constructor( config ) {
+		super( null, config );
+
+		this.document.createRoot();
+
+		this.editing.createRoot( 'div' );
+
+		this.data.processor = new HtmlDataProcessor();
+	}
+
+	/**
+	 * Creates a virtual, element-less editor instance.
+	 *
+	 * @param {Object} config See {@link ckeditor5.editor.StandardEditor}'s param.
+	 * @returns {Promise} Promise resolved once editor is ready.
+	 * @returns {ckeditor5.editor.VirtualTestEditor} return.editor The editor instance.
+	 */
+	static create( config ) {
+		return new Promise( ( resolve ) => {
+			const editor = new this( config );
+
+			resolve(
+				editor.initPlugins()
+					.then( () => editor )
+			);
+		} );
+	}
+}

+ 0 - 2
tests/ckeditor.html

@@ -1,2 +0,0 @@
-<div id="content"></div>
-<div class="editor"></div>

+ 0 - 215
tests/ckeditor.js

@@ -1,215 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* bender-tags: browser-only */
-
-'use strict';
-
-import testUtils from '/tests/ckeditor5/_utils/utils.js';
-
-import CKEDITOR from '/ckeditor.js';
-import Editor from '/ckeditor5/editor.js';
-import CKEditorError from '/ckeditor5/utils/ckeditorerror.js';
-
-const content = document.getElementById( 'content' );
-const editorConfig = { creator: 'creator-test' };
-
-testUtils.createSinonSandbox();
-testUtils.defineEditorCreatorMock( 'test' );
-
-beforeEach( () => {
-	// Destroy all editor instances.
-	while ( CKEDITOR.instances.length ) {
-		CKEDITOR.instances.get( 0 ).destroy();
-	}
-} );
-
-describe( 'create', () => {
-	it( 'should return a promise', () => {
-		expect( CKEDITOR.create( content, editorConfig ) ).to.be.instanceof( Promise );
-	} );
-
-	it( 'should create a new editor instance', () => {
-		return CKEDITOR.create( content, editorConfig ).then( ( editor ) => {
-			expect( editor ).to.be.instanceof( Editor );
-		} );
-	} );
-
-	it( 'should set configurations on the new editor', () => {
-		return CKEDITOR.create( content, { test: 1, creator: 'creator-test' } ).then( ( editor ) => {
-			expect( editor.config.test ).to.equal( 1 );
-		} );
-	} );
-
-	it( 'should add the editor to the `instances` collection', () => {
-		return CKEDITOR.create( content, editorConfig ).then( ( editor ) => {
-			expect( CKEDITOR.instances ).to.have.length( 1 );
-			expect( CKEDITOR.instances.get( 0 ) ).to.equal( editor );
-		} );
-	} );
-
-	it( 'should remove the editor from the `instances` collection on `destroy` event', () => {
-		let editor1, editor2;
-
-		// Create the first editor.
-		return CKEDITOR.create( content, editorConfig ).then( ( editor ) => {
-			editor1 = editor;
-
-			// Create the second editor.
-			return CKEDITOR.create( '.editor', editorConfig ).then( ( editor ) => {
-				editor2 = editor;
-
-				// It should have 2 editors.
-				expect( CKEDITOR.instances ).to.have.length( 2 );
-
-				// Destroy one of them.
-				editor1.destroy();
-
-				// It should have 1 editor now.
-				expect( CKEDITOR.instances ).to.have.length( 1 );
-
-				// Ensure that the remaining is the right one.
-				expect( CKEDITOR.instances.get( 0 ) ).to.equal( editor2 );
-			} );
-		} );
-	} );
-
-	describe( 'elements param', () => {
-		const container = document.createElement( 'div' );
-		let el1, el2;
-
-		document.body.appendChild( container );
-
-		beforeEach( () => {
-			container.innerHTML = '';
-
-			el1 = document.createElement( 'div' );
-			el2 = document.createElement( 'div' );
-
-			container.appendChild( el1 );
-			container.appendChild( el2 );
-		} );
-
-		it( 'should work with a string', () => {
-			return CKEDITOR.create( 'div', editorConfig ).then( ( editor ) => {
-				assertElements( editor, document.querySelectorAll( 'div' ).length );
-			} );
-		} );
-
-		it( 'should work with an HTMLElement', () => {
-			return CKEDITOR.create( el1, editorConfig ).then( ( editor ) => {
-				assertElements( editor, 1 );
-			} );
-		} );
-
-		it( 'should work with a NodeList', () => {
-			const elements = container.querySelectorAll( 'div' );
-
-			return CKEDITOR.create( elements, editorConfig ).then( ( editor ) => {
-				assertElements( editor, 2 );
-			} );
-		} );
-
-		it( 'should work with an HTMLCollection', () => {
-			const elements = container.getElementsByTagName( 'div' );
-
-			return CKEDITOR.create( elements, editorConfig ).then( ( editor ) => {
-				assertElements( editor, 2 );
-			} );
-		} );
-
-		it( 'should work with an array', () => {
-			const elements = Array.from( container.getElementsByTagName( 'div' ) );
-
-			return CKEDITOR.create( elements, editorConfig ).then( ( editor ) => {
-				assertElements( editor, 2 );
-			} );
-		} );
-
-		it( 'should work with an object', () => {
-			const elements = {
-				editableA: el1,
-				editableB: el2
-			};
-
-			return CKEDITOR.create( elements, editorConfig ).then( ( editor ) => {
-				assertElements( editor, 2 );
-			} );
-		} );
-
-		it( 'should be rejected on element not found (when string passed)', () => {
-			let addSpy = testUtils.sinon.spy( CKEDITOR.instances, 'add' );
-
-			return CKEDITOR.create( '.undefined' )
-				.then( () => {
-					throw new Error( 'It should not enter this function.' );
-				} )
-				.catch( ( error ) => {
-					expect( error ).to.be.instanceof( CKEditorError );
-					expect( error.message ).to.match( /^ckeditor5-create-no-elements:/ );
-
-					// We need to make sure that create()'s execution is stopped.
-					// Assertion based on a real mistake we made that reject() wasn't followed by a return.
-					sinon.assert.notCalled( addSpy );
-				} );
-		} );
-
-		it( 'should be rejected on an empty elements array-like obj', () => {
-			return CKEDITOR.create( [] )
-				.then( () => {
-					throw new Error( 'It should not enter this function.' );
-				} )
-				.catch( ( error ) => {
-					expect( error ).to.be.instanceof( CKEditorError );
-					expect( error.message ).to.match( /^ckeditor5-create-no-elements:/ );
-				} );
-		} );
-
-		it( 'should be rejected on an empty object', () => {
-			return CKEDITOR.create( {} )
-				.then( () => {
-					throw new Error( 'It should not enter this function.' );
-				} )
-				.catch( ( error ) => {
-					expect( error ).to.be.instanceof( CKEditorError );
-					expect( error.message ).to.match( /^ckeditor5-create-no-elements:/ );
-				} );
-		} );
-
-		it( 'should take names from the ids or data-editable attributes', () => {
-			el1.id = 'foo';
-			el2.dataset.editable = 'bar';
-
-			return CKEDITOR.create( [ el1, el2 ], editorConfig )
-				.then( ( editor ) => {
-					expect( editor.elements.get( 'foo' ) ).to.equal( el1 );
-					expect( editor.elements.get( 'bar' ) ).to.equal( el2 );
-				} );
-		} );
-
-		it( 'should take names from the object keys', () => {
-			el1.id = 'foo';
-			el2.dataset.editable = 'bar';
-
-			return CKEDITOR.create( { a: el1, b: el2 }, editorConfig )
-				.then( ( editor ) => {
-					expect( editor.elements.get( 'a' ) ).to.equal( el1 );
-					expect( editor.elements.get( 'b' ) ).to.equal( el2 );
-				} );
-		} );
-
-		it( 'should generate editableN names', () => {
-			return CKEDITOR.create( [ el1, el2 ], editorConfig )
-				.then( ( editor ) => {
-					expect( Array.from( editor.elements.keys() ).join( ',' ) ).to.match( /^editable\d+,editable\d+$/ );
-				} );
-		} );
-
-		function assertElements( editor, expectedSize ) {
-			expect( editor.elements ).to.be.instanceof( Map );
-			expect( editor.elements ).to.have.property( 'size', expectedSize );
-		}
-	} );
-} );

+ 8 - 7
tests/command/attributecommand.js

@@ -5,7 +5,7 @@
 
 
 'use strict';
 'use strict';
 
 
-import Editor from '/ckeditor5/editor.js';
+import Editor from '/ckeditor5/editor/editor.js';
 import Document from '/ckeditor5/engine/model/document.js';
 import Document from '/ckeditor5/engine/model/document.js';
 import AttributeCommand from '/ckeditor5/command/attributecommand.js';
 import AttributeCommand from '/ckeditor5/command/attributecommand.js';
 import Text from '/ckeditor5/engine/model/text.js';
 import Text from '/ckeditor5/engine/model/text.js';
@@ -20,24 +20,25 @@ const attrKey = 'bold';
 beforeEach( () => {
 beforeEach( () => {
 	editor = new Editor();
 	editor = new Editor();
 	editor.document = new Document();
 	editor.document = new Document();
+
 	modelDoc = editor.document;
 	modelDoc = editor.document;
-	root = modelDoc.createRoot( 'root', 'div' );
+	root = modelDoc.createRoot();
 
 
 	command = new AttributeCommand( editor, attrKey );
 	command = new AttributeCommand( editor, attrKey );
 
 
-	modelDoc.schema.registerItem( 'div', '$block' );
 	modelDoc.schema.registerItem( 'p', '$block' );
 	modelDoc.schema.registerItem( 'p', '$block' );
+	modelDoc.schema.registerItem( 'h1', '$block' );
 	modelDoc.schema.registerItem( 'img', '$inline' );
 	modelDoc.schema.registerItem( 'img', '$inline' );
 
 
 	// Allow block in "root" (DIV)
 	// Allow block in "root" (DIV)
-	modelDoc.schema.allow( { name: '$block', inside: 'div' } );
+	modelDoc.schema.allow( { name: '$block', inside: '$root' } );
 
 
 	// Bold text is allowed only in P.
 	// Bold text is allowed only in P.
 	modelDoc.schema.allow( { name: '$text', attributes: 'bold', inside: 'p' } );
 	modelDoc.schema.allow( { name: '$text', attributes: 'bold', inside: 'p' } );
-	modelDoc.schema.allow( { name: 'p', attributes: 'bold', inside: 'div' } );
+	modelDoc.schema.allow( { name: 'p', attributes: 'bold', inside: '$root' } );
 
 
 	// Disallow bold on image.
 	// Disallow bold on image.
-	modelDoc.schema.disallow( { name: 'img', attributes: 'bold', inside: 'div' } );
+	modelDoc.schema.disallow( { name: 'img', attributes: 'bold', inside: '$root' } );
 } );
 } );
 
 
 afterEach( () => {
 afterEach( () => {
@@ -198,7 +199,7 @@ describe( '_checkEnabled', () => {
 				new Element( 'img' ),
 				new Element( 'img' ),
 				'bar'
 				'bar'
 			] ),
 			] ),
-			new Element( 'div' ),
+			new Element( 'h1' ),
 			new Element( 'p' )
 			new Element( 'p' )
 		] );
 		] );
 	} );
 	} );

+ 3 - 8
tests/command/command.js

@@ -3,14 +3,12 @@
  * For licensing, see LICENSE.md.
  * For licensing, see LICENSE.md.
  */
  */
 
 
-/* bender-tags: browser-only */
-
 'use strict';
 'use strict';
 
 
-import Editor from '/ckeditor5/editor.js';
+import Editor from '/ckeditor5/editor/editor.js';
 import Command from '/ckeditor5/command/command.js';
 import Command from '/ckeditor5/command/command.js';
 
 
-let element, editor, command;
+let editor, command;
 
 
 class CommandWithSchema extends Command {
 class CommandWithSchema extends Command {
 	constructor( editor, schemaValid ) {
 	constructor( editor, schemaValid ) {
@@ -25,10 +23,7 @@ class CommandWithSchema extends Command {
 }
 }
 
 
 beforeEach( () => {
 beforeEach( () => {
-	element = document.createElement( 'div' );
-	document.body.appendChild( element );
-
-	editor = new Editor( element );
+	editor = new Editor();
 	command = new Command( editor );
 	command = new Command( editor );
 } );
 } );
 
 

+ 0 - 36
tests/creator/creator.js

@@ -1,36 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* bender-tags: creator */
-
-'use strict';
-
-import testUtils from '/tests/ckeditor5/_utils/utils.js';
-import Creator from '/ckeditor5/creator/creator.js';
-import Plugin from '/ckeditor5/plugin.js';
-import Editor from '/ckeditor5/editor.js';
-
-testUtils.createSinonSandbox();
-
-describe( 'Creator', () => {
-	let creator, editor;
-
-	beforeEach( () => {
-		editor = new Editor();
-		creator = new Creator( editor );
-	} );
-
-	describe( 'constructor', () => {
-		it( 'inherits from the Plugin', () => {
-			expect( creator ).to.be.instanceof( Plugin );
-		} );
-	} );
-
-	describe( 'create', () => {
-		it( 'returns a promise', () => {
-			expect( creator.create() ).to.be.instanceof( Promise );
-		} );
-	} );
-} );

+ 0 - 55
tests/creator/manual/_assets/styles.css

@@ -1,55 +0,0 @@
-.ck-body {
-	margin: 10px 0;
-	border: solid 3px red;
-}
-.ck-body::before {
-	content: '[[ ck-body region ]]';
-}
-
-.ck-box {
-	margin: 10px 0;
-}
-
-.ck-main {
-	border: solid 1px rgb( 200, 200, 200 );
-	padding: 5px
-}
-
-.ck-toolbar {
-	border: solid 1px rgb( 200, 200, 200 );
-	background: rgb( 240, 240, 240 );
-	padding: 5px;
-}
-
-.ck-toolbar.ck-hidden {
-	opacity: 0.3;
-}
-
-.ck-button {
-	border: solid 1px transparent;
-	background: transparent;
-	display: inline-block;
-	padding: 5px 10px;
-	border-radius: 1px;
-	margin-right: 5px;
-
-	font-size: 16px;
-	color: rgb( 69, 69, 69 );
-
-	cursor: pointer;
-}
-
-.ck-button:hover:not(.ck-disabled) {
-	border: solid 1px rgb( 180, 180, 180 );
-	box-shadow: 0 0 2px rgba( 0, 0, 0, 0.1 );
-}
-
-.ck-button.ck-on {
-	border: solid 1px rgb( 200, 200, 200 );
-	box-shadow: inset 0 0 3px rgba( 0, 0, 0, 0.1 );
-	background: rgba( 0, 0, 0, 0.05 );
-}
-
-.ck-button.ck-disabled {
-	color: rgb( 180, 180, 180 );
-}

+ 0 - 90
tests/creator/manual/_utils/creator/inlinecreator.js

@@ -1,90 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import StandardCreator from '/ckeditor5/creator/standardcreator.js';
-
-import HtmlDataProcessor from '/ckeditor5/engine/dataprocessor/htmldataprocessor.js';
-import Editable from '/ckeditor5/editable.js';
-
-import { createEditableUI, createEditorUI } from '/ckeditor5/ui/creator-utils.js';
-
-import EditorUIView from '/ckeditor5/ui/editorui/editoruiview.js';
-import BoxlessEditorUI from '/tests/ckeditor5/_utils/ui/boxlesseditorui/boxlesseditorui.js';
-import EditableUI from '/ckeditor5/ui/editableui/editableui.js';
-import InlineEditableUIView from '/ckeditor5/ui/editableui/inline/inlineeditableuiview.js';
-import Model from '/ckeditor5/ui/model.js';
-import FloatingToolbar from '/tests/ckeditor5/_utils/ui/floatingtoolbar/floatingtoolbar.js';
-import FloatingToolbarView from '/tests/ckeditor5/_utils/ui/floatingtoolbar/floatingtoolbarview.js';
-
-import { imitateFeatures, imitateDestroyFeatures } from '/ckeditor5/creator-classic/utils/imitatefeatures.js';
-
-export default class InlineCreator extends StandardCreator {
-	constructor( editor ) {
-		super( editor, new HtmlDataProcessor() );
-
-		this._createEditable();
-
-		createEditorUI( editor, BoxlessEditorUI, EditorUIView );
-	}
-
-	create() {
-		const editor = this.editor;
-		const editable = editor.editables.get( 0 );
-
-		// Features mock.
-		imitateFeatures( editor );
-
-		// UI.
-		this._createToolbars();
-		editor.ui.add( 'editable', createEditableUI( editor, editable, EditableUI, InlineEditableUIView ) );
-
-		// Init.
-		return super.create()
-			.then( () => editor.ui.init() )
-			// We'll be able to do that much earlier once the loading will be done to the document model,
-			// rather than straight to the editable.
-			.then( () => this.loadDataFromEditorElement() );
-	}
-
-	destroy() {
-		imitateDestroyFeatures();
-
-		this.updateEditorElement();
-
-		super.destroy();
-
-		return this.editor.ui.destroy();
-	}
-
-	_createEditable() {
-		const editor = this.editor;
-		const editorElement = editor.firstElement;
-		const editableName = editor.firstElementName;
-		const editable = new Editable( editor, editableName );
-
-		editor.editables.add( editable );
-		editable.bindTo( editorElement );
-		editor.document.createRoot( editableName, '$root' );
-	}
-
-	_createToolbars() {
-		const editableName = this.editor.firstElementName;
-		const locale = this.editor.locale;
-
-		const toolbar1Model = new Model( null, { editableName } );
-		const toolbar2Model = new Model( null, { editableName } );
-
-		const toolbar1 = new FloatingToolbar( toolbar1Model, new FloatingToolbarView( toolbar1Model, locale ), this.editor );
-		const toolbar2 = new FloatingToolbar( toolbar2Model, new FloatingToolbarView( toolbar2Model, locale ), this.editor );
-
-		toolbar1.addButtons( this.editor.config.toolbar );
-		toolbar2.addButtons( this.editor.config.toolbar.reverse() );
-
-		this.editor.ui.add( 'body', toolbar1 );
-		this.editor.ui.add( 'body', toolbar2 );
-	}
-}

+ 0 - 76
tests/creator/manual/_utils/creator/legacycreator.js

@@ -1,76 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import StandardCreator from '/ckeditor5/creator/standardcreator.js';
-
-import HtmlDataProcessor from '/ckeditor5/engine/dataprocessor/htmldataprocessor.js';
-import Editable from '/ckeditor5/editable.js';
-
-import { createEditableUI, createEditorUI } from '/ckeditor5/ui/creator-utils.js';
-
-import BoxedEditorUI from '/ckeditor5/ui/editorui/boxed/boxededitorui.js';
-import BoxedEditorUIView from '/ckeditor5/ui/editorui/boxed/boxededitoruiview.js';
-import FramedEditableUIIframe from '/tests/ckeditor5/_utils/ui/editableui/framed/framededitableuiiframe.js';
-import FramedEditableUIIframeView from '/tests/ckeditor5/_utils/ui/editableui/framed/framededitableuiiframeview.js';
-import Model from '/ckeditor5/ui/model.js';
-import Toolbar from '/ckeditor5/ui/bindings/toolbar.js';
-import ToolbarView from '/ckeditor5/ui/toolbar/toolbarview.js';
-
-import { imitateFeatures, imitateDestroyFeatures } from '/ckeditor5/creator-classic/utils/imitatefeatures.js';
-
-export default class LegacyCreator extends StandardCreator {
-	constructor( editor ) {
-		super( editor, new HtmlDataProcessor() );
-
-		const editableName = editor.firstElementName;
-		editor.editables.add( new Editable( editor, editableName ) );
-		editor.document.createRoot( editableName, '$root' );
-
-		// UI.
-		createEditorUI( editor, BoxedEditorUI, BoxedEditorUIView );
-	}
-
-	create() {
-		const editor = this.editor;
-		const editable = editor.editables.get( 0 );
-
-		// Features mock.
-		imitateFeatures( editor );
-
-		// UI.
-		this._replaceElement( editor.firstElement, editor.ui.view.element );
-		this._createToolbar();
-		editor.ui.add( 'main', createEditableUI( editor, editable, FramedEditableUIIframe, FramedEditableUIIframeView ) );
-
-		// Init.
-		return super.create()
-			.then( () => editor.ui.init() )
-			// We'll be able to do that much earlier once the loading will be done to the document model,
-			// rather than straight to the editable.
-			.then( () => this.loadDataFromEditorElement() );
-	}
-
-	destroy() {
-		imitateDestroyFeatures();
-
-		this.updateEditorElement();
-
-		super.destroy();
-
-		return this.editor.ui.destroy();
-	}
-
-	_createToolbar() {
-		const editor = this.editor;
-		const toolbarModel = new Model();
-		const toolbar = new Toolbar( toolbarModel, new ToolbarView( toolbarModel, editor.locale ), editor );
-
-		toolbar.addButtons( editor.config.toolbar );
-
-		this.editor.ui.add( 'top', toolbar );
-	}
-}

+ 0 - 91
tests/creator/manual/_utils/creator/multicreator.js

@@ -1,91 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import StandardCreator from '/ckeditor5/creator/standardcreator.js';
-
-import HtmlDataProcessor from '/ckeditor5/engine/dataprocessor/htmldataprocessor.js';
-import Editable from '/ckeditor5/editable.js';
-
-import { createEditableUI, createEditorUI } from '/ckeditor5/ui/creator-utils.js';
-
-import BoxedEditorUI from '/ckeditor5/ui/editorui/boxed/boxededitorui.js';
-import BoxedEditorUIView from '/ckeditor5/ui/editorui/boxed/boxededitoruiview.js';
-import EditableUI from '/ckeditor5/ui/editableui/editableui.js';
-import InlineEditableUIView from '/ckeditor5/ui/editableui/inline/inlineeditableuiview.js';
-import Model from '/ckeditor5/ui/model.js';
-import Toolbar from '/ckeditor5/ui/bindings/toolbar.js';
-import ToolbarView from '/ckeditor5/ui/toolbar/toolbarview.js';
-
-import { imitateFeatures, imitateDestroyFeatures } from '/ckeditor5/creator-classic/utils/imitatefeatures.js';
-
-export default class MultiCreator extends StandardCreator {
-	constructor( editor ) {
-		super( editor, new HtmlDataProcessor() );
-
-		// Engine.
-		this._createEditables();
-
-		// UI.
-		createEditorUI( editor, BoxedEditorUI, BoxedEditorUIView );
-	}
-
-	create() {
-		const editor = this.editor;
-
-		// Features mock.
-		imitateFeatures( editor );
-
-		// UI.
-		this._createToolbar();
-
-		for ( let editable of editor.editables ) {
-			editor.ui.add( 'main', createEditableUI( editor, editable, EditableUI, InlineEditableUIView ) );
-		}
-
-		editor.elements.forEach( ( element ) => {
-			this._replaceElement( element, null );
-		} );
-
-		// Init.
-		return super.create()
-			.then( () => editor.ui.init() )
-			// We'll be able to do that much earlier once the loading will be done to the document model,
-			// rather than straight to the editable.
-			.then( () => this.loadDataFromEditorElements() );
-	}
-
-	destroy() {
-		imitateDestroyFeatures();
-
-		this.updateEditorElements();
-
-		super.destroy();
-
-		this.editor.ui.destroy();
-	}
-
-	_createEditables() {
-		const editor = this.editor;
-
-		editor.elements.forEach( ( editorElement, editableName ) => {
-			const editable = new Editable( editor, editableName );
-
-			editor.editables.add( editable );
-			editor.document.createRoot( editableName, '$root' );
-		} );
-	}
-
-	_createToolbar() {
-		const editor = this.editor;
-		const toolbarModel = new Model();
-		const toolbar = new Toolbar( toolbarModel, new ToolbarView( toolbarModel, editor.locale ), editor );
-
-		toolbar.addButtons( editor.config.toolbar );
-
-		this.editor.ui.add( 'top', toolbar );
-	}
-}

+ 0 - 13
tests/creator/manual/creator-inline.html

@@ -1,13 +0,0 @@
-<head>
-	<link rel="stylesheet" href="%APPS_DIR%ckeditor/build/amd/theme/ckeditor.css">
-</head>
-
-<p>
-	<button id="destroyEditor">Destroy editor</button>
-	<button id="initEditor">Init editor</button>
-</p>
-
-<div id="editor">
-	<h1>Hello world!</h1>
-	<p>This is an editor instance.</p>
-</div>

+ 0 - 47
tests/creator/manual/creator-inline.js

@@ -1,47 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* global console:false */
-
-'use strict';
-
-import CKEDITOR from '/ckeditor.js';
-import InlineCreator from '/tests/ckeditor5/creator/manual/_utils/creator/inlinecreator.js';
-import testUtils from '/tests/utils/_utils/utils.js';
-
-let editor, editable, observer;
-
-function initEditor() {
-	CKEDITOR.create( '#editor', {
-		creator: InlineCreator,
-		toolbar: [ 'bold', 'italic' ]
-	} )
-	.then( ( newEditor ) => {
-		console.log( 'Editor was initialized', newEditor );
-		console.log( 'You can now play with it using global `editor` and `editable` variable.' );
-
-		window.editor = editor = newEditor;
-		window.editable = editable = editor.editables.get( 0 );
-
-		observer = testUtils.createObserver();
-		observer.observe( 'Editable', editable );
-	} );
-}
-
-function destroyEditor() {
-	editor.destroy()
-		.then( () => {
-			window.editor = editor = null;
-			window.editable = editable = null;
-
-			observer.stopListening();
-			observer = null;
-
-			console.log( 'Editor was destroyed' );
-		} );
-}
-
-document.getElementById( 'initEditor' ).addEventListener( 'click', initEditor );
-document.getElementById( 'destroyEditor' ).addEventListener( 'click', destroyEditor );

+ 0 - 21
tests/creator/manual/creator-inline.md

@@ -1,21 +0,0 @@
-@bender-ui: collapsed
-
-1. Click "Init editor".
-2. Expected:
-  * Inline editor should be created.
-  * There should be **two** toolbars:
-    * one with "Bold" and "Italic" buttons,
-    * second with "Italic" and "Bold" buttons.
-3. Click "Destroy editor".
-4. Expected:
-  * Editor should be destroyed (the element should not be editable).
-  * The element should contain its data (updated).
-  * The 'ck-body region' should be removed.
-
-## Notes:
-
-* You can play with:
-  * `editable.isEditable`,
-  * `boldModel.isEnabled` and `italicModel.isEnabled`.
-* Changes to `editable.isFocused/isEditable` should be logged to the console.
-* Buttons' states should be synchronised between toolbars (they share models).

+ 0 - 13
tests/creator/manual/creator-legacy.html

@@ -1,13 +0,0 @@
-<head>
-	<link rel="stylesheet" href="%APPS_DIR%ckeditor/build/amd/theme/ckeditor.css">
-</head>
-
-<p>
-	<button id="destroyEditor">Destroy editor</button>
-	<button id="initEditor">Init editor</button>
-</p>
-
-<div id="editor">
-	<h1>Hello world!</h1>
-	<p>This is an editor instance.</p>
-</div>

+ 0 - 51
tests/creator/manual/creator-legacy.js

@@ -1,51 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* global console:false */
-
-'use strict';
-
-import CKEDITOR from '/ckeditor.js';
-import LegacyCreator from '/tests/ckeditor5/creator/manual/_utils/creator/legacycreator.js';
-import testUtils from '/tests/utils/_utils/utils.js';
-
-let editor, editable, observer;
-
-function initEditor() {
-	CKEDITOR.create( '#editor', {
-		creator: LegacyCreator,
-		ui: {
-			width: 400,
-			height: 400
-		},
-		toolbar: [ 'bold', 'italic' ]
-	} )
-	.then( ( newEditor ) => {
-		console.log( 'Editor was initialized', newEditor );
-		console.log( 'You can now play with it using global `editor` and `editable` variables.' );
-
-		window.editor = editor = newEditor;
-		window.editable = editable = editor.editables.get( 0 );
-
-		observer = testUtils.createObserver();
-		observer.observe( 'Editable', editable );
-	} );
-}
-
-function destroyEditor() {
-	editor.destroy()
-		.then( () => {
-			window.editor = editor = null;
-			window.editable = editable = null;
-
-			observer.stopListening();
-			observer = null;
-
-			console.log( 'Editor was destroyed' );
-		} );
-}
-
-document.getElementById( 'initEditor' ).addEventListener( 'click', initEditor );
-document.getElementById( 'destroyEditor' ).addEventListener( 'click', destroyEditor );

+ 0 - 23
tests/creator/manual/creator-legacy.md

@@ -1,23 +0,0 @@
-@bender-ui: collapsed
-
-1. Click "Init editor".
-2. Expected:
-  * Framed editor should be created.
-  * It should be rectangular (400x400).
-  * Original element should disappear.
-  * There should be a toolbar with "Bold" and "Italic" buttons.
-3. Click "Destroy editor".
-4. Expected:
-  * Editor should be destroyed.
-  * Original element should be visible.
-  * The element should contain its data (updated).
-  * The 'ck-body region' should be removed.
-
-## Notes:
-
-* You can play with:
-  * `editable.isEditable`,
-  * `editor.ui.width/height`.
-  * `boldModel.isEnabled` and `italicModel.isEnabled`.
-* Changes to `editable.isFocused/isEditable` should be logged to the console.
-* Clicks on the buttons should be logged to the console.

+ 0 - 20
tests/creator/manual/creator-multi.html

@@ -1,20 +0,0 @@
-<head>
-	<link rel="stylesheet" href="%APPS_DIR%ckeditor/build/amd/theme/ckeditor.css">
-</head>
-
-<p>
-	<button id="destroyEditor">Destroy editor</button>
-	<button id="initEditor">Init editor</button>
-</p>
-
-<div id="editorContainer"></div>
-
-<div id="editable1" class="editor">
-	<h1>Hello world!</h1>
-	<p>This is an editor instance.</p>
-</div>
-
-<div id="editable2" class="editor">
-	<h1>Hello again!</h1>
-	<p>This is the same editor instance.</p>
-</div>

+ 0 - 60
tests/creator/manual/creator-multi.js

@@ -1,60 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* global console:false */
-
-'use strict';
-
-import CKEDITOR from '/ckeditor.js';
-import MultiCreator from '/tests/ckeditor5/creator/manual/_utils/creator/multicreator.js';
-import testUtils from '/tests/utils/_utils/utils.js';
-
-let editor, editables, observer;
-
-function initEditor() {
-	CKEDITOR.create( '.editor', {
-		creator: MultiCreator,
-		toolbar: [ 'bold', 'italic' ]
-	} )
-	.then( ( newEditor ) => {
-		console.log( 'Editor was initialized', newEditor );
-		console.log( 'You can now play with it using global `editor` and `editables` variables.' );
-
-		window.editor = editor = newEditor;
-		window.editables = editables = editor.editables;
-
-		const editable1 = editables.get( 'editable1' );
-		const editable2 = editables.get( 'editable2' );
-
-		editable1.toString = editable2.toString = function() {
-			return `Editable(${ this.name })`;
-		};
-
-		observer = testUtils.createObserver();
-		observer.observe( 'Editable 1', editable1 );
-		observer.observe( 'Editable 2', editable2 );
-		observer.observe( 'EditableCollection', editables );
-
-		document.getElementById( 'editorContainer' ).appendChild( editor.ui.view.element );
-	} );
-}
-
-function destroyEditor() {
-	editor.destroy()
-		.then( () => {
-			window.editor = editor = null;
-			window.editables = editables = null;
-
-			observer.stopListening();
-			observer = null;
-
-			document.getElementById( 'editorContainer' ).innerHTML = '';
-
-			console.log( 'Editor was destroyed' );
-		} );
-}
-
-document.getElementById( 'initEditor' ).addEventListener( 'click', initEditor );
-document.getElementById( 'destroyEditor' ).addEventListener( 'click', destroyEditor );

+ 0 - 22
tests/creator/manual/creator-multi.md

@@ -1,22 +0,0 @@
-@bender-ui: collapsed
-
-1. Click "Init editor".
-2. Expected:
-  * Boxed editor with two editables should be created.
-  * Original elements should disappear.
-  * There should be a toolbar with "Bold" and "Italic" buttons.
-3. Click "Destroy editor".
-4. Expected:
-  * Editor should be destroyed.
-  * Original elements should be visible.
-  * The elements should contain their data (updated).
-  * The 'ck-body region' should be removed.
-
-## Notes:
-
-* You can play with:
-  * `editables.get( 'editable1/2' ).isEditable`,
-  * `boldModel.isEnabled` and `italicModel.isEnabled`.
-* Changes to `editable.isFocused/isEditable` should be logged to the console.
-* Changes to `editables.current` should be logged to the console.
-* Clicks on the buttons should be logged to the console.

+ 0 - 3
tests/creator/standardcreator.html

@@ -1,3 +0,0 @@
-<textarea id="getData-textarea">&lt;b&gt;foo&lt;/b&gt;</textarea>
-<div id="getData-div"><b>foo</b></div>
-<template id="getData-template"><b>foo</b></template>

+ 0 - 239
tests/creator/standardcreator.js

@@ -1,239 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* bender-tags: creator, browser-only */
-
-'use strict';
-
-import testUtils from '/tests/ckeditor5/_utils/utils.js';
-import Creator from '/ckeditor5/creator/creator.js';
-import StandardCreator from '/ckeditor5/creator/standardcreator.js';
-import Editor from '/ckeditor5/editor.js';
-import HtmlDataProcessor from '/ckeditor5/engine/dataprocessor/htmldataprocessor.js';
-import Document from '/ckeditor5/engine/model/document.js';
-import EditingController from '/ckeditor5/engine/editingcontroller.js';
-import DataController from '/ckeditor5/engine/datacontroller.js';
-import KeystrokeHandler from '/ckeditor5/keystrokehandler.js';
-
-testUtils.createSinonSandbox();
-
-describe( 'Creator', () => {
-	let creator, editor;
-
-	beforeEach( () => {
-		const firstElement = document.createElement( 'div' );
-		document.body.appendChild( firstElement );
-
-		const secondElement = document.createElement( 'div' );
-		document.body.appendChild( secondElement );
-
-		editor = new Editor( { first: firstElement, second: secondElement } );
-		creator = new StandardCreator( editor, new HtmlDataProcessor() );
-	} );
-
-	describe( 'constructor', () => {
-		it( 'inherits from the Creator', () => {
-			expect( creator ).to.be.instanceof( Creator );
-		} );
-
-		it( 'creates the engine', () => {
-			expect( editor.document ).to.be.instanceof( Document );
-			expect( editor.editing ).to.be.instanceof( EditingController );
-			expect( editor.data ).to.be.instanceof( DataController );
-			expect( editor.data.processor ).to.be.instanceof( HtmlDataProcessor );
-		} );
-
-		it( 'creates the keystroke handler', () => {
-			expect( editor.keystrokes ).to.be.instanceof( KeystrokeHandler );
-		} );
-
-		it( 'uses HtmlDataProcessor if no processor is provided in constructor', () => {
-			creator = new StandardCreator( editor );
-
-			expect( editor.data.processor ).to.be.instanceof( HtmlDataProcessor );
-		} );
-	} );
-
-	describe( 'create', () => {
-		it( 'returns a promise', () => {
-			expect( creator.create() ).to.be.instanceof( Promise );
-		} );
-	} );
-
-	describe( 'destroy', () => {
-		it( 'calls super.destroy', () => {
-			const creatorSpy = testUtils.sinon.spy( Creator.prototype, 'destroy' );
-
-			creator.destroy();
-
-			expect( creatorSpy.called ).to.be.true;
-		} );
-
-		it( 'should destroy the engine', () => {
-			const spy = editor.document.destroy = editor.data.destroy = editor.editing.destroy = sinon.spy();
-
-			creator.destroy();
-
-			expect( spy.callCount ).to.equal( 3 );
-		} );
-
-		it( 'should restore the replaced element', () => {
-			const spy = testUtils.sinon.stub( creator, '_restoreElements' );
-
-			creator.destroy();
-
-			expect( spy.calledOnce ).to.be.true;
-		} );
-	} );
-
-	describe( 'updateEditorElement', () => {
-		it( 'should pass data to the first element when element name not specified', () => {
-			editor.getData = ( rootName ) => {
-				expect( rootName ).to.equal( 'first' );
-
-				return 'foo';
-			};
-
-			creator.updateEditorElement();
-
-			expect( editor.firstElement.innerHTML ).to.equal( 'foo' );
-		} );
-
-		it( 'should pass data to the given element', () => {
-			editor.elements.set( 'second', document.createElement( 'div' ) );
-
-			editor.getData = ( rootName ) => {
-				expect( rootName ).to.equal( 'second' );
-
-				return 'foo';
-			};
-
-			creator.updateEditorElement( 'second' );
-
-			expect( editor.elements.get( 'second' ).innerHTML ).to.equal( 'foo' );
-		} );
-	} );
-
-	describe( 'updateEditorElements', () => {
-		it( 'updates all editor elements', () => {
-			const spy = sinon.stub( creator, 'updateEditorElement' );
-
-			creator.updateEditorElements();
-
-			expect( spy.calledTwice ).to.be.true;
-			expect( spy.calledWith( 'first' ) ).to.be.true;
-			expect( spy.calledWith( 'second' ) ).to.be.true;
-		} );
-	} );
-
-	describe( 'loadDataFromEditorElement', () => {
-		it( 'should pass data to the first element', () => {
-			editor.setData = sinon.spy();
-
-			editor.elements.get( 'first' ).innerHTML = 'foo';
-			creator.loadDataFromEditorElement();
-
-			expect( editor.setData.calledWithExactly( 'foo', 'first' ) ).to.be.true;
-		} );
-
-		it( 'should pass data to the given element', () => {
-			const element = document.createElement( 'div' );
-			element.innerHTML = 'foo';
-
-			editor.elements.set( 'second', element );
-
-			editor.setData = sinon.spy();
-
-			creator.loadDataFromEditorElement( 'second' );
-
-			expect( editor.setData.calledWithExactly( 'foo', 'second' ) ).to.be.true;
-		} );
-	} );
-
-	describe( 'loadDataFromEditorElements', () => {
-		it( 'updates all editor elements', () => {
-			const spy = sinon.stub( creator, 'loadDataFromEditorElement' );
-
-			creator.loadDataFromEditorElements();
-
-			expect( spy.calledTwice ).to.be.true;
-			expect( spy.calledWith( 'first' ) ).to.be.true;
-			expect( spy.calledWith( 'second' ) ).to.be.true;
-		} );
-	} );
-
-	describe( 'getDataFromElement', () => {
-		[ 'textarea', 'template', 'div' ].forEach( ( elementName ) => {
-			it( 'should return the content of a ' + elementName, function() {
-				const data = StandardCreator.getDataFromElement( document.getElementById( 'getData-' + elementName ) );
-				expect( data ).to.equal( '<b>foo</b>' );
-			} );
-		} );
-	} );
-
-	describe( 'setDataInElement', () => {
-		[ 'textarea', 'template', 'div' ].forEach( ( elementName ) => {
-			it( 'should set the content of a ' + elementName, () => {
-				const el = document.createElement( elementName );
-				const expectedData = '<b>foo</b>';
-
-				StandardCreator.setDataInElement( el, expectedData );
-
-				const actualData = StandardCreator.getDataFromElement( el );
-				expect( actualData ).to.equal( actualData );
-			} );
-		} );
-	} );
-
-	describe( '_replaceElement', () => {
-		it( 'should hide the element', () => {
-			const el = editor.elements.get( 'first' );
-
-			creator._replaceElement( el );
-
-			expect( el.style.display ).to.equal( 'none' );
-		} );
-
-		it( 'should inserts the replacement next to the element being hidden', () => {
-			const el = editor.elements.get( 'first' );
-			const replacement = document.createElement( 'div' );
-
-			creator._replaceElement( el, replacement );
-
-			expect( el.nextSibling ).to.equal( replacement );
-		} );
-	} );
-
-	describe( '_restoreElements', () => {
-		it( 'should restore all elements', () => {
-			const el1 = editor.elements.get( 'first' );
-			const replacement1 = document.createElement( 'div' );
-			const el2 = editor.elements.get( 'second' );
-			const replacement2 = document.createElement( 'div' );
-
-			creator._replaceElement( el1, replacement1 );
-			creator._replaceElement( el2, replacement2 );
-
-			creator._restoreElements();
-
-			expect( replacement1.parentNode ).to.be.null;
-			expect( replacement2.parentNode ).to.be.null;
-			expect( el2.style.display ).to.not.equal( 'none' );
-		} );
-
-		it( 'should not try to remove replacement elements', () => {
-			const el1 = editor.elements.get( 'first' );
-			const el2 = editor.elements.get( 'second' );
-
-			creator._replaceElement( el1 );
-			creator._replaceElement( el2 );
-
-			creator._restoreElements();
-
-			expect( el1.style.display ).to.not.equal( 'none' );
-			expect( el2.style.display ).to.not.equal( 'none' );
-		} );
-	} );
-} );

+ 0 - 128
tests/editable.js

@@ -1,128 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* bender-tags: browser-only */
-
-'use strict';
-
-import Editor from '/ckeditor5/editor.js';
-import Editable from '/ckeditor5/editable.js';
-import EditingController from '/ckeditor5/engine/editingcontroller.js';
-import ViewElement from '/ckeditor5/engine/view/element.js';
-
-describe( 'Editable', () => {
-	const ELEMENT_NAME = 'h1';
-	const EDITABLE_NAME = 'editableNaNaNaNa';
-
-	let editable, editor;
-
-	beforeEach( () => {
-		editor = new Editor();
-		editable = new Editable( editor, EDITABLE_NAME );
-	} );
-
-	describe( 'constructor', () => {
-		it( 'sets the properties', () => {
-			expect( editable ).to.have.property( 'editor', editor );
-			expect( editable ).to.have.property( 'name', EDITABLE_NAME );
-			expect( editable ).to.have.property( 'isEditable', true );
-			expect( editable ).to.have.property( 'isFocused', false );
-		} );
-	} );
-
-	describe( 'isEditable', () => {
-		it( 'is observable', () => {
-			const spy = sinon.spy();
-
-			editable.on( 'change:isEditable', spy );
-
-			editable.isEditable = false;
-
-			expect( spy.calledOnce ).to.be.true;
-		} );
-	} );
-
-	describe( 'isFocused', () => {
-		it( 'is observable', () => {
-			const spy = sinon.spy();
-
-			editable.on( 'change:isFocused', spy );
-
-			editable.isFocused = true;
-
-			expect( spy.calledOnce ).to.be.true;
-		} );
-	} );
-
-	describe( 'bindTo', () => {
-		let domElement, editingView;
-
-		beforeEach( () => {
-			domElement = document.createElement( ELEMENT_NAME );
-
-			editor.editing = new EditingController();
-			editingView = editor.editing.view;
-
-			editable.bindTo( domElement );
-		} );
-
-		it( 'creates view root element', () => {
-			expect( editable.viewElement ).to.be.instanceof( ViewElement );
-			expect( editable.viewElement ).to.have.property( 'name', ELEMENT_NAME );
-
-			expect( editingView.viewRoots.get( EDITABLE_NAME ) ).to.equal( editable.viewElement );
-		} );
-
-		describe( 'isFocused binding', () => {
-			it( 'reacts on editingView#focus', () => {
-				editingView.fire( 'focus', {
-					target: editable.viewElement
-				} );
-
-				expect( editable ).to.have.property( 'isFocused', true );
-			} );
-
-			it( 'reacts on editingView#blur', () => {
-				editable.isFocused = true;
-
-				editingView.fire( 'blur', {
-					target: editable.viewElement
-				} );
-
-				expect( editable ).to.have.property( 'isFocused', false );
-			} );
-
-			it( 'reacts on editingView#focus only if target matches', () => {
-				editingView.fire( 'focus', {
-					target: new ViewElement( 'foo' )
-				} );
-
-				expect( editable ).to.have.property( 'isFocused', false );
-			} );
-
-			it( 'reacts on editingView#blur only if target matches', () => {
-				editable.isFocused = true;
-
-				editingView.fire( 'blur', {
-					target: new ViewElement( 'foo' )
-				} );
-
-				expect( editable ).to.have.property( 'isFocused', true );
-			} );
-		} );
-	} );
-
-	describe( 'destroy', () => {
-		it( 'offs everything', () => {
-			const spy = sinon.spy( editable, 'stopListening' );
-
-			editable.destroy();
-
-			expect( spy.calledOnce ).to.be.true;
-			expect( editable.viewElement ).to.be.null;
-			expect( editable.domElement ).to.be.null;
-		} );
-	} );
-} );

+ 0 - 104
tests/editablecollection.js

@@ -1,104 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-'use strict';
-
-import Editor from '/ckeditor5/editor.js';
-import Editable from '/ckeditor5/editable.js';
-import EditableCollection from '/ckeditor5/editablecollection.js';
-
-describe( 'EditableCollection', () => {
-	let collection, editor;
-
-	beforeEach( () => {
-		collection = new EditableCollection();
-		editor = new Editor();
-	} );
-
-	describe( 'constructor', () => {
-		it( 'configures collection to use idProperty=name', () => {
-			collection.add( new Editable( editor, 'foo' ) );
-
-			expect( collection.get( 'foo' ).name ).to.equal( 'foo' );
-		} );
-
-		it( 'sets observable property current', () => {
-			expect( collection ).to.have.property( 'current', null );
-
-			const spy = sinon.spy();
-			collection.on( 'change:current', spy );
-
-			collection.current = 1;
-
-			expect( spy.calledOnce ).to.be.true;
-		} );
-	} );
-
-	describe( 'add', () => {
-		it( 'binds collection.current to editable.isFocused changes', () => {
-			const editable = new Editable( editor, 'foo' );
-
-			collection.add( editable );
-
-			editable.isFocused = true;
-			expect( collection ).to.have.property( 'current', editable );
-
-			editable.isFocused = false;
-			expect( collection ).to.have.property( 'current', null );
-		} );
-	} );
-
-	describe( 'remove', () => {
-		it( 'stops watching editable.isFocused', () => {
-			const editable = new Editable( editor, 'foo' );
-
-			collection.add( editable );
-
-			editable.isFocused = true;
-
-			collection.remove( editable );
-
-			editable.isFocused = false;
-
-			expect( collection ).to.have.property( 'current', editable );
-		} );
-	} );
-
-	describe( 'destroy', () => {
-		let editables;
-
-		beforeEach( () => {
-			editables = [ new Editable( editor, 'foo' ), new Editable( editor, 'bar' ) ];
-
-			collection.add( editables[ 0 ] );
-			collection.add( editables[ 1 ] );
-		} );
-
-		it( 'stops watching all editables', () => {
-			collection.destroy();
-
-			editables[ 0 ].isFocused = true;
-			editables[ 1 ].isFocused = true;
-
-			expect( collection ).to.have.property( 'current', null );
-		} );
-
-		it( 'destroys all children', () => {
-			editables.forEach( editable => {
-				editable.destroy = sinon.spy();
-			} );
-
-			collection.destroy();
-
-			expect( editables.map( editable => editable.destroy.calledOnce ) ).to.deep.equal( [ true, true ] );
-		} );
-
-		it( 'removes all children', () => {
-			collection.destroy();
-
-			expect( collection ).to.have.lengthOf( 0 );
-		} );
-	} );
-} );

+ 0 - 223
tests/editor/baseeditor.js

@@ -1,223 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* bender-tags: editor */
-
-'use strict';
-
-import Editor from '/ckeditor5/editor.js';
-import Command from '/ckeditor5/command/command.js';
-import Locale from '/ckeditor5/utils/locale.js';
-import CKEditorError from '/ckeditor5/utils/ckeditorerror.js';
-import Document from '/ckeditor5/engine/model/document.js';
-import DataController from '/ckeditor5/engine/datacontroller.js';
-import HtmlDataProcessor from '/ckeditor5/engine/dataprocessor/htmldataprocessor.js';
-import { getData, setData } from '/tests/engine/_utils/model.js';
-
-describe( 'Editor', () => {
-	describe( 'locale', () => {
-		it( 'is instantiated and t() is exposed', () => {
-			const editor = new Editor();
-
-			expect( editor.locale ).to.be.instanceof( Locale );
-			expect( editor.t ).to.equal( editor.locale.t );
-		} );
-
-		it( 'is configured with the config.lang', () => {
-			const editor = new Editor( null, { lang: 'pl' } );
-
-			expect( editor.locale.lang ).to.equal( 'pl' );
-		} );
-	} );
-
-	describe( 'destroy', () => {
-		it( 'should fire "destroy"', () => {
-			const editor = new Editor();
-			let spy = sinon.spy();
-
-			editor.on( 'destroy', spy );
-
-			return editor.destroy().then( () => {
-				expect( spy.calledOnce ).to.be.true;
-			} );
-		} );
-
-		// Note: Tests for destroying creators are in creator/creator.js.
-		// When destroying creator will be generalized to destroying plugins,
-		// move that code here.
-	} );
-
-	describe( 'execute', () => {
-		it( 'should execute specified command', () => {
-			const editor = new Editor();
-
-			let command = new Command( editor );
-			sinon.spy( command, '_execute' );
-
-			editor.commands.set( 'commandName', command );
-			editor.execute( 'commandName' );
-
-			expect( command._execute.calledOnce ).to.be.true;
-		} );
-
-		it( 'should throw an error if specified command has not been added', () => {
-			const editor = new Editor();
-
-			expect( () => {
-				editor.execute( 'command' );
-			} ).to.throw( CKEditorError, /^editor-command-not-found:/ );
-		} );
-	} );
-
-	describe( 'setData', () => {
-		let editor;
-
-		beforeEach( () => {
-			editor = new Editor();
-
-			editor.document = new Document();
-			editor.data = {
-				set: sinon.spy()
-			};
-		} );
-
-		it( 'should set data of the first root', () => {
-			editor.document.createRoot( 'firstRoot', 'div' );
-
-			editor.setData( 'foo' );
-
-			expect( editor.data.set.calledOnce ).to.be.true;
-			expect( editor.data.set.calledWithExactly( 'foo', 'firstRoot' ) ).to.be.true;
-		} );
-
-		it( 'should set data of the specified root', () => {
-			editor.setData( 'foo', 'someRoot' );
-
-			expect( editor.data.set.calledOnce ).to.be.true;
-			expect( editor.data.set.calledWithExactly( 'foo', 'someRoot' ) ).to.be.true;
-		} );
-
-		it( 'should throw when no roots', () => {
-			expect( () => {
-				editor.setData( 'foo' );
-			} ).to.throw( CKEditorError, /^editor-no-editable-roots:/ );
-		} );
-
-		it( 'should throw when more than one root and no root name given', () => {
-			editor.document.createRoot( 'firstRoot', 'div' );
-			editor.document.createRoot( 'secondRoot', 'div' );
-
-			expect( () => {
-				editor.setData( 'foo' );
-			} ).to.throw( CKEditorError, /^editor-editable-root-name-missing:/ );
-		} );
-
-		it( 'should throw when no data controller', () => {
-			expect( () => {
-				editor.data = null;
-
-				editor.setData( 'foo' );
-			} ).to.throw( CKEditorError, /^editor-no-datacontroller:/ );
-		} );
-
-		describe( 'integrational tests', () => {
-			beforeEach( () => {
-				editor.data = new DataController( editor.document, new HtmlDataProcessor() );
-
-				editor.document.schema.allow( { name: '$text', inside: '$root' } );
-			} );
-
-			it( 'should set data of the first root', () => {
-				editor.document.createRoot( 'firstRoot', 'div' );
-
-				editor.setData( 'foo' );
-
-				expect( getData( editor.document, { rootName: 'firstRoot', withoutSelection: true } ) ).to.equal( 'foo' );
-			} );
-
-			it( 'should set data of the specified root', () => {
-				editor.document.createRoot( 'firstRoot', 'div' );
-				editor.document.createRoot( 'secondRoot', 'div' );
-
-				editor.setData( 'foo', 'secondRoot' );
-
-				expect( getData( editor.document, { rootName: 'secondRoot', withoutSelection: true } ) ).to.equal( 'foo' );
-			} );
-		} );
-	} );
-
-	describe( 'getData', () => {
-		let editor;
-
-		beforeEach( () => {
-			editor = new Editor();
-
-			editor.document = new Document();
-			editor.data = {
-				get( rootName ) {
-					return `data for ${ rootName }`;
-				}
-			};
-		} );
-
-		it( 'should get data from the first root', () => {
-			editor.document.createRoot( 'firstRoot', 'div' );
-
-			expect( editor.getData() ).to.equal( 'data for firstRoot' );
-		} );
-
-		it( 'should get data from the specified root', () => {
-			expect( editor.getData( 'someRoot' ) ).to.equal( 'data for someRoot' );
-		} );
-
-		it( 'should throw when no roots', () => {
-			expect( () => {
-				editor.getData();
-			} ).to.throw( CKEditorError, /^editor-no-editable-roots:/ );
-		} );
-
-		it( 'should throw when more than one root and no root name given', () => {
-			editor.document.createRoot( 'firstRoot', 'div' );
-			editor.document.createRoot( 'secondRoot', 'div' );
-
-			expect( () => {
-				editor.getData();
-			} ).to.throw( CKEditorError, /^editor-editable-root-name-missing:/ );
-		} );
-
-		it( 'should throw when no data controller', () => {
-			expect( () => {
-				editor.data = null;
-
-				editor.getData();
-			} ).to.throw( CKEditorError, /^editor-no-datacontroller:/ );
-		} );
-
-		describe( 'integrational tests', () => {
-			beforeEach( () => {
-				editor.data = new DataController( editor.document, new HtmlDataProcessor() );
-
-				editor.document.schema.allow( { name: '$text', inside: '$root' } );
-			} );
-
-			it( 'should set data of the first root', () => {
-				editor.document.createRoot( 'firstRoot', 'div' );
-
-				setData( editor.document, 'foo', { rootName: 'firstRoot' } );
-
-				expect( editor.getData() ).to.equal( 'foo' );
-			} );
-
-			it( 'should set data of the specified root', () => {
-				editor.document.createRoot( 'firstRoot', 'div' );
-				editor.document.createRoot( 'secondRoot', 'div' );
-
-				setData( editor.document, 'foo', { rootName: 'secondRoot' } );
-
-				expect( editor.getData( 'secondRoot' ) ).to.equal( 'foo' );
-			} );
-		} );
-	} );
-} );

+ 0 - 176
tests/editor/creator.js

@@ -1,176 +0,0 @@
-/**
- * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
- * For licensing, see LICENSE.md.
- */
-
-/* bender-tags: editor, creator, browser-only */
-
-'use strict';
-
-import moduleUtils from '/tests/ckeditor5/_utils/module.js';
-import testUtils from '/tests/ckeditor5/_utils/utils.js';
-import Editor from '/ckeditor5/editor.js';
-import Creator from '/ckeditor5/creator/creator.js';
-import CKEditorError from '/ckeditor5/utils/ckeditorerror.js';
-
-let editor;
-
-function initEditor( config ) {
-	editor = new Editor( null, config );
-
-	return editor.init();
-}
-
-testUtils.createSinonSandbox();
-
-testUtils.defineEditorCreatorMock( 'test1', {
-	create: sinon.spy(),
-	destroy: sinon.spy()
-} );
-
-testUtils.defineEditorCreatorMock( 'test-config1', {
-	create: sinon.spy()
-} );
-testUtils.defineEditorCreatorMock( 'test-config2', {
-	create: sinon.spy()
-} );
-
-moduleUtils.define( 'test3/test3', [ 'plugin' ], ( Plugin ) => {
-	return class extends Plugin {};
-} );
-
-moduleUtils.define( 'test/creator-async-create', [ 'creator/creator' ], ( Creator ) => {
-	return class extends Creator {
-		create() {
-			return new Promise( ( resolve, reject ) => {
-				reject( new Error( 'Catch me - create.' ) );
-			} );
-		}
-
-		destroy() {}
-	};
-} );
-
-moduleUtils.define( 'test/creator-async-destroy', [ 'creator/creator' ], ( Creator ) => {
-	return class extends Creator {
-		create() {}
-
-		destroy() {
-			return new Promise( ( resolve, reject ) => {
-				reject( new Error( 'Catch me - destroy.' ) );
-			} );
-		}
-	};
-} );
-
-afterEach( () => {
-	editor = null; // To make sure we're using the freshly inited editor.
-} );
-
-///////////////////
-
-describe( 'Editor creator', () => {
-	describe( 'init', () => {
-		it( 'should instantiate the creator and call create()', () => {
-			return initEditor( {
-					creator: 'creator-test1'
-				} )
-				.then( () => {
-					let creator = editor.plugins.get( 'creator-test1' );
-
-					expect( creator ).to.be.instanceof( Creator );
-
-					// The create method has been called.
-					sinon.assert.calledOnce( creator.create );
-				} );
-		} );
-
-		it( 'should throw if creator is not defined', () => {
-			return initEditor( {} )
-				.then( () => {
-					throw new Error( 'This should not be executed.' );
-				} )
-				.catch( ( err ) => {
-					expect( err ).to.be.instanceof( CKEditorError );
-					expect( err.message ).to.match( /^editor-undefined-creator:/ );
-				} );
-		} );
-
-		it( 'should use the creator specified in config.creator', () => {
-			return initEditor( {
-					creator: 'creator-test-config2',
-					features: [ 'creator-test-config1', 'creator-test-config2' ],
-				} )
-				.then( () => {
-					let creator1 = editor.plugins.get( 'creator-test-config1' );
-					let creator2 = editor.plugins.get( 'creator-test-config2' );
-
-					sinon.assert.calledOnce( creator2.create );
-					sinon.assert.notCalled( creator1.create );
-				} );
-		} );
-
-		it( 'should throw an error if the creator doesn\'t exist', () => {
-			return initEditor( {
-					creator: 'bad'
-				} )
-				.then( () => {
-					throw new Error( 'This should not be executed.' );
-				} )
-				.catch( ( err ) => {
-					// It's the Require.JS error.
-					expect( err ).to.be.an.instanceof( Error );
-					expect( err.message ).to.match( /^Script error for/ );
-				} );
-		} );
-
-		it( 'should chain the promise from the creator (enables async creators)', () => {
-			return initEditor( {
-					creator: 'test/creator-async-create'
-				} )
-				.then( () => {
-					throw new Error( 'This should not be executed.' );
-				} )
-				.catch( ( err ) => {
-					// Unfortunately fake timers don't work with promises, so throwing in the creator's create()
-					// seems to be the only way to test that the promise chain isn't broken.
-					expect( err ).to.have.property( 'message', 'Catch me - create.' );
-				} );
-		} );
-	} );
-
-	describe( 'destroy', () => {
-		it( 'should call "destroy" on the creator', () => {
-			let creator1;
-
-			return initEditor( {
-					creator: 'creator-test1'
-				} )
-				.then( () => {
-					creator1 = editor.plugins.get( 'creator-test1' );
-
-					return editor.destroy();
-				} )
-				.then( () => {
-					sinon.assert.calledOnce( creator1.destroy );
-				} );
-		} );
-
-		it( 'should chain the promise from the creator (enables async creators)', () => {
-			return initEditor( {
-					creator: 'test/creator-async-destroy'
-				} )
-				.then( () => {
-					return editor.destroy();
-				} )
-				.then( () => {
-					throw new Error( 'This should not be executed.' );
-				} )
-				.catch( ( err ) => {
-					// Unfortunately fake timers don't work with promises, so throwing in the creator's destroy()
-					// seems to be the only way to test that the promise chain isn't broken.
-					expect( err ).to.have.property( 'message', 'Catch me - destroy.' );
-				} );
-		} );
-	} );
-} );

+ 78 - 0
tests/editor/editor-base.js

@@ -0,0 +1,78 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* bender-tags: editor */
+
+'use strict';
+
+import Editor from '/ckeditor5/editor/editor.js';
+import Command from '/ckeditor5/command/command.js';
+import Locale from '/ckeditor5/utils/locale.js';
+import CKEditorError from '/ckeditor5/utils/ckeditorerror.js';
+
+describe( 'Editor', () => {
+	describe( 'locale', () => {
+		it( 'is instantiated and t() is exposed', () => {
+			const editor = new Editor();
+
+			expect( editor.locale ).to.be.instanceof( Locale );
+			expect( editor.t ).to.equal( editor.locale.t );
+		} );
+
+		it( 'is configured with the config.lang', () => {
+			const editor = new Editor( { lang: 'pl' } );
+
+			expect( editor.locale.lang ).to.equal( 'pl' );
+		} );
+	} );
+
+	describe( 'destroy', () => {
+		it( 'should fire "destroy"', () => {
+			const editor = new Editor();
+			let spy = sinon.spy();
+
+			editor.on( 'destroy', spy );
+
+			return editor.destroy().then( () => {
+				expect( spy.calledOnce ).to.be.true;
+			} );
+		} );
+
+		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' );
+
+			return editor.destroy()
+				.then( () => {
+					expect( spy1.calledOnce ).to.be.true;
+					expect( spy2.calledOnce ).to.be.true;
+				} );
+		} );
+	} );
+
+	describe( 'execute', () => {
+		it( 'should execute specified command', () => {
+			const editor = new Editor();
+
+			let command = new Command( editor );
+			sinon.spy( command, '_execute' );
+
+			editor.commands.set( 'commandName', command );
+			editor.execute( 'commandName' );
+
+			expect( command._execute.calledOnce ).to.be.true;
+		} );
+
+		it( 'should throw an error if specified command has not been added', () => {
+			const editor = new Editor();
+
+			expect( () => {
+				editor.execute( 'command' );
+			} ).to.throw( CKEditorError, /^editor-command-not-found:/ );
+		} );
+	} );
+} );

+ 33 - 82
tests/editor/editor.js

@@ -8,37 +8,26 @@
 'use strict';
 'use strict';
 
 
 import moduleUtils from '/tests/ckeditor5/_utils/module.js';
 import moduleUtils from '/tests/ckeditor5/_utils/module.js';
-import testUtils from '/tests/ckeditor5/_utils/utils.js';
-import Editor from '/ckeditor5/editor.js';
+import Editor from '/ckeditor5/editor/editor.js';
 import Plugin from '/ckeditor5/plugin.js';
 import Plugin from '/ckeditor5/plugin.js';
 import Config from '/ckeditor5/utils/config.js';
 import Config from '/ckeditor5/utils/config.js';
 import PluginCollection from '/ckeditor5/plugincollection.js';
 import PluginCollection from '/ckeditor5/plugincollection.js';
-import EditableCollection from '/ckeditor5/editablecollection.js';
 
 
 const pluginClasses = {};
 const pluginClasses = {};
 
 
 before( () => {
 before( () => {
-	// Define fake plugins to be used in tests.
-	testUtils.defineEditorCreatorMock( 'test', {
-		init: sinon.spy().named( 'creator-test' )
-	} );
-
 	pluginDefinition( 'A/A' );
 	pluginDefinition( 'A/A' );
 	pluginDefinition( 'B/B' );
 	pluginDefinition( 'B/B' );
 	pluginDefinition( 'C/C', [ 'B/B' ] );
 	pluginDefinition( 'C/C', [ 'B/B' ] );
 	pluginDefinition( 'D/D', [ 'C/C' ] );
 	pluginDefinition( 'D/D', [ 'C/C' ] );
 } );
 } );
 
 
-///////////////////
-
 describe( 'Editor', () => {
 describe( 'Editor', () => {
 	describe( 'constructor', () => {
 	describe( 'constructor', () => {
 		it( 'should create a new editor instance', () => {
 		it( 'should create a new editor instance', () => {
 			const editor = new Editor();
 			const editor = new Editor();
 
 
-			expect( editor ).to.have.property( 'elements', null );
 			expect( editor.config ).to.be.an.instanceof( Config );
 			expect( editor.config ).to.be.an.instanceof( Config );
-			expect( editor.editables ).to.be.an.instanceof( EditableCollection );
 			expect( editor.commands ).to.be.an.instanceof( Map );
 			expect( editor.commands ).to.be.an.instanceof( Map );
 
 
 			expect( editor.plugins ).to.be.an.instanceof( PluginCollection );
 			expect( editor.plugins ).to.be.an.instanceof( PluginCollection );
@@ -54,74 +43,52 @@ describe( 'Editor', () => {
 		} );
 		} );
 	} );
 	} );
 
 
-	describe( 'firstElement', () => {
-		it( 'should be set to first element', () => {
-			const editor = new Editor( { foo: 'a', bar: 'b' } );
-
-			expect( editor.firstElement ).to.equal( 'a' );
-		} );
-
-		it( 'should be set to null if there are no elements', () => {
-			const editor = new Editor();
-
-			expect( editor.firstElement ).to.be.null;
-		} );
-	} );
+	describe( 'create', () => {
+		it( 'should return a promise that resolves properly', () => {
+			let promise = Editor.create();
 
 
-	describe( 'firstElementName', () => {
-		it( 'should be set to first element name', () => {
-			const editor = new Editor( { foo: 'a', bar: 'b' } );
+			expect( promise ).to.be.an.instanceof( Promise );
 
 
-			expect( editor.firstElementName ).to.equal( 'foo' );
+			return promise;
 		} );
 		} );
 
 
-		it( 'should be set to null if there are no elements', () => {
-			const editor = new Editor();
+		it( 'loads plugins', () => {
+			return Editor.create( {
+					features: [ 'A' ]
+				} )
+				.then( editor => {
+					expect( getPlugins( editor ).length ).to.equal( 1 );
 
 
-			expect( editor.firstElementName ).to.be.null;
+					expect( editor.plugins.get( 'A' ) ).to.be.an.instanceof( Plugin );
+				} );
 		} );
 		} );
 	} );
 	} );
 
 
-	describe( 'init', () => {
-		it( 'should return a promise that resolves properly', () => {
-			const editor = new Editor( null, {
-				creator: 'creator-test'
-			} );
-
-			let promise = editor.init();
-
-			expect( promise ).to.be.an.instanceof( Promise );
-
-			return promise;
-		} );
-
-		it( 'should load features and creator', () => {
-			const editor = new Editor( null, {
-				features: [ 'A', 'B' ],
-				creator: 'creator-test'
+	describe( 'initPlugins', () => {
+		it( 'should load features', () => {
+			const editor = new Editor( {
+				features: [ 'A', 'B' ]
 			} );
 			} );
 
 
 			expect( getPlugins( editor ) ).to.be.empty;
 			expect( getPlugins( editor ) ).to.be.empty;
 
 
-			return editor.init().then( () => {
-				expect( getPlugins( editor ).length ).to.equal( 3 );
+			return editor.initPlugins().then( () => {
+				expect( getPlugins( editor ).length ).to.equal( 2 );
 
 
 				expect( editor.plugins.get( 'A' ) ).to.be.an.instanceof( Plugin );
 				expect( editor.plugins.get( 'A' ) ).to.be.an.instanceof( Plugin );
 				expect( editor.plugins.get( 'B' ) ).to.be.an.instanceof( Plugin );
 				expect( editor.plugins.get( 'B' ) ).to.be.an.instanceof( Plugin );
-				expect( editor.plugins.get( 'creator-test' ) ).to.be.an.instanceof( Plugin );
 			} );
 			} );
 		} );
 		} );
 
 
 		it( 'should load features passed as a string', () => {
 		it( 'should load features passed as a string', () => {
-			const editor = new Editor( null, {
-				features: 'A,B',
-				creator: 'creator-test'
+			const editor = new Editor( {
+				features: 'A,B'
 			} );
 			} );
 
 
 			expect( getPlugins( editor ) ).to.be.empty;
 			expect( getPlugins( editor ) ).to.be.empty;
 
 
-			return editor.init().then( () => {
-				expect( getPlugins( editor ).length ).to.equal( 3 );
+			return editor.initPlugins().then( () => {
+				expect( getPlugins( editor ).length ).to.equal( 2 );
 
 
 				expect( editor.plugins.get( 'A' ) ).to.be.an.instanceof( Plugin );
 				expect( editor.plugins.get( 'A' ) ).to.be.an.instanceof( Plugin );
 				expect( editor.plugins.get( 'B' ) ).to.be.an.instanceof( Plugin );
 				expect( editor.plugins.get( 'B' ) ).to.be.an.instanceof( Plugin );
@@ -129,14 +96,12 @@ describe( 'Editor', () => {
 		} );
 		} );
 
 
 		it( 'should initialize plugins in the right order', () => {
 		it( 'should initialize plugins in the right order', () => {
-			const editor = new Editor( null, {
-				features: [ 'A', 'D' ],
-				creator: 'creator-test'
+			const editor = new Editor( {
+				features: [ 'A', 'D' ]
 			} );
 			} );
 
 
-			return editor.init().then( () => {
+			return editor.initPlugins().then( () => {
 				sinon.assert.callOrder(
 				sinon.assert.callOrder(
-					editor.plugins.get( 'creator-test' ).init,
 					editor.plugins.get( pluginClasses[ 'A/A' ] ).init,
 					editor.plugins.get( pluginClasses[ 'A/A' ] ).init,
 					editor.plugins.get( pluginClasses[ 'B/B' ] ).init,
 					editor.plugins.get( pluginClasses[ 'B/B' ] ).init,
 					editor.plugins.get( pluginClasses[ 'C/C' ] ).init,
 					editor.plugins.get( pluginClasses[ 'C/C' ] ).init,
@@ -165,14 +130,12 @@ describe( 'Editor', () => {
 				return PluginAsync;
 				return PluginAsync;
 			} );
 			} );
 
 
-			const editor = new Editor( null, {
-				features: [ 'A', 'sync' ],
-				creator: 'creator-test'
+			const editor = new Editor( {
+				features: [ 'A', 'sync' ]
 			} );
 			} );
 
 
-			return editor.init().then( () => {
+			return editor.initPlugins().then( () => {
 				sinon.assert.callOrder(
 				sinon.assert.callOrder(
-					editor.plugins.get( 'creator-test' ).init,
 					editor.plugins.get( pluginClasses[ 'A/A' ] ).init,
 					editor.plugins.get( pluginClasses[ 'A/A' ] ).init,
 					editor.plugins.get( PluginAsync ).init,
 					editor.plugins.get( PluginAsync ).init,
 					// This one is called with delay by the async init.
 					// This one is called with delay by the async init.
@@ -182,20 +145,10 @@ describe( 'Editor', () => {
 			} );
 			} );
 		} );
 		} );
 	} );
 	} );
-
-	describe( 'plugins', () => {
-		it( 'should be empty on new editor', () => {
-			const editor = new Editor();
-
-			expect( getPlugins( editor ) ).to.be.empty;
-		} );
-	} );
 } );
 } );
 
 
-/**
- * @param {String} name Name of the plugin.
- * @param {String[]} deps Dependencies of the plugin (only other plugins).
- */
+// @param {String} name Name of the plugin.
+// @param {String[]} deps Dependencies of the plugin (only other plugins).
 function pluginDefinition( name, deps ) {
 function pluginDefinition( name, deps ) {
 	moduleUtils.define( name, deps || [], function() {
 	moduleUtils.define( name, deps || [], function() {
 		class NewPlugin extends Plugin {}
 		class NewPlugin extends Plugin {}
@@ -209,9 +162,7 @@ function pluginDefinition( name, deps ) {
 	} );
 	} );
 }
 }
 
 
-/**
- * Returns an array of loaded plugins.
- */
+// Returns an array of loaded plugins.
 function getPlugins( editor ) {
 function getPlugins( editor ) {
 	const plugins = [];
 	const plugins = [];
 
 

+ 136 - 0
tests/editor/standardeditor.js

@@ -0,0 +1,136 @@
+/**
+ * @license Copyright (c) 2003-2016, CKSource - Frederico Knabben. All rights reserved.
+ * For licensing, see LICENSE.md.
+ */
+
+/* bender-tags: editor, browser-only */
+
+'use strict';
+
+import StandardEditor from '/ckeditor5/editor/standardeditor.js';
+import HtmlDataProcessor from '/ckeditor5/engine/dataprocessor/htmldataprocessor.js';
+import { getData, setData } from '/tests/engine/_utils/model.js';
+
+import EditingController from '/ckeditor5/engine/editingcontroller.js';
+import KeystrokeHandler from '/ckeditor5/keystrokehandler.js';
+import Feature from '/ckeditor5/feature.js';
+
+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( KeystrokeHandler );
+		} );
+
+		it( 'sets config', () => {
+			const editor = new StandardEditor( editorElement, { foo: 1 } );
+
+			expect( editor.config.get( 'foo' ) ).to.equal( 1 );
+		} );
+	} );
+
+	describe( 'create', () => {
+		it( 'initializes editor with plugins and config', () => {
+			class FeatureFoo extends Feature {}
+
+			return StandardEditor.create( editorElement, {
+					foo: 1,
+					features: [ FeatureFoo ]
+				} )
+				.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( FeatureFoo ) ).to.be.instanceof( FeatureFoo );
+				} );
+		} );
+	} );
+
+	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( '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 set data of the first root', () => {
+			editor.document.createRoot();
+			editor.document.createRoot( '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;
+		} );
+	} );
+} );

+ 7 - 7
tests/keystrokehandler.js

@@ -7,19 +7,19 @@
 
 
 'use strict';
 'use strict';
 
 
-import Editor from '/ckeditor5/editor.js';
-import StandardCreator from '/ckeditor5/creator/standardcreator.js';
+import VirtualTestEditor from '/tests/ckeditor5/_utils/virtualtesteditor.js';
+import KeystrokeHandler from '/ckeditor5/keystrokehandler.js';
 import { keyCodes } from '/ckeditor5/utils/keyboard.js';
 import { keyCodes } from '/ckeditor5/utils/keyboard.js';
 
 
 describe( 'KeystrokeHandler', () => {
 describe( 'KeystrokeHandler', () => {
 	let editor;
 	let editor;
 
 
 	beforeEach( () => {
 	beforeEach( () => {
-		editor = new Editor( null, {
-			creator: StandardCreator
-		} );
-
-		return editor.init();
+		return VirtualTestEditor.create()
+			.then( newEditor => {
+				editor = newEditor;
+				editor.keystrokes = new KeystrokeHandler( editor );
+			} );
 	} );
 	} );
 
 
 	describe( 'constructor', () => {
 	describe( 'constructor', () => {

+ 6 - 6
tests/load.js

@@ -8,15 +8,15 @@
 import load from '/ckeditor5/load.js';
 import load from '/ckeditor5/load.js';
 
 
 describe( 'load()', () => {
 describe( 'load()', () => {
-	it( 'loads ckeditor.js', () => {
-		return load( 'ckeditor.js' )
-			.then( ( CKEDITORModule ) => {
-				expect( CKEDITORModule.default ).to.have.property( 'create' );
+	it( 'loads plugin.js', () => {
+		return load( 'ckeditor5/plugin.js' )
+			.then( ( PluginModule ) => {
+				expect( PluginModule.default ).to.be.a( 'function' );
 			} );
 			} );
 	} );
 	} );
 
 
-	it( 'loads ckeditor5/editor', () => {
-		return load( 'ckeditor5/editor.js' )
+	it( 'loads ckeditor5/editor/editor.js', () => {
+		return load( 'ckeditor5/editor/editor.js' )
 			.then( ( EditorModule ) => {
 			.then( ( EditorModule ) => {
 				expect( EditorModule.default ).to.be.a( 'function' );
 				expect( EditorModule.default ).to.be.a( 'function' );
 			} );
 			} );

+ 2 - 4
tests/plugin.js

@@ -3,17 +3,15 @@
  * For licensing, see LICENSE.md.
  * For licensing, see LICENSE.md.
  */
  */
 
 
-/* bender-tags: browser-only */
-
 'use strict';
 'use strict';
 
 
 import Plugin from '/ckeditor5/plugin.js';
 import Plugin from '/ckeditor5/plugin.js';
-import Editor from '/ckeditor5/editor.js';
+import Editor from '/ckeditor5/editor/editor.js';
 
 
 let editor;
 let editor;
 
 
 before( () => {
 before( () => {
-	editor = new Editor( document.body.appendChild( document.createElement( 'div' ) ) );
+	editor = new Editor();
 } );
 } );
 
 
 describe( 'constructor', () => {
 describe( 'constructor', () => {

+ 9 - 8
tests/plugincollection.js

@@ -9,16 +9,17 @@
 
 
 import moduleUtils from '/tests/ckeditor5/_utils/module.js';
 import moduleUtils from '/tests/ckeditor5/_utils/module.js';
 import testUtils from '/tests/ckeditor5/_utils/utils.js';
 import testUtils from '/tests/ckeditor5/_utils/utils.js';
-import Editor from '/ckeditor5/editor.js';
+import Editor from '/ckeditor5/editor/editor.js';
 import PluginCollection from '/ckeditor5/plugincollection.js';
 import PluginCollection from '/ckeditor5/plugincollection.js';
 import Plugin from '/ckeditor5/plugin.js';
 import Plugin from '/ckeditor5/plugin.js';
-import Creator from '/ckeditor5/creator/creator.js';
+import Feature from '/ckeditor5/feature.js';
 import CKEditorError from '/ckeditor5/utils/ckeditorerror.js';
 import CKEditorError from '/ckeditor5/utils/ckeditorerror.js';
 import log from '/ckeditor5/utils/log.js';
 import log from '/ckeditor5/utils/log.js';
 
 
 let editor;
 let editor;
 let PluginA, PluginB, PluginC, PluginD, PluginE, PluginF, PluginG, PluginH, PluginI;
 let PluginA, PluginB, PluginC, PluginD, PluginE, PluginF, PluginG, PluginH, PluginI;
 class TestError extends Error {}
 class TestError extends Error {}
+class GrandPlugin extends Feature {}
 
 
 testUtils.createSinonSandbox();
 testUtils.createSinonSandbox();
 
 
@@ -29,7 +30,7 @@ before( () => {
 	PluginD = createPlugin( 'D' );
 	PluginD = createPlugin( 'D' );
 	PluginE = createPlugin( 'E' );
 	PluginE = createPlugin( 'E' );
 	PluginF = createPlugin( 'F' );
 	PluginF = createPlugin( 'F' );
-	PluginG = createPlugin( 'G', Creator );
+	PluginG = createPlugin( 'G', GrandPlugin );
 	PluginH = createPlugin( 'H' );
 	PluginH = createPlugin( 'H' );
 	PluginI = createPlugin( 'I' );
 	PluginI = createPlugin( 'I' );
 
 
@@ -39,7 +40,7 @@ before( () => {
 	PluginE.requires = [ PluginF ];
 	PluginE.requires = [ PluginF ];
 	PluginH.requires = [ PluginI ];
 	PluginH.requires = [ PluginI ];
 
 
-	editor = new Editor( document.body.appendChild( document.createElement( 'div' ) ) );
+	editor = new Editor();
 } );
 } );
 
 
 // Create fake plugins that will be used on tests.
 // Create fake plugins that will be used on tests.
@@ -52,19 +53,19 @@ moduleUtils.define( 'B/B', () => {
 	return PluginB;
 	return PluginB;
 } );
 } );
 
 
-moduleUtils.define( 'C/C', [ 'editor', 'B/B' ], () => {
+moduleUtils.define( 'C/C', [ 'editor/editor', 'B/B' ], () => {
 	return PluginC;
 	return PluginC;
 } );
 } );
 
 
-moduleUtils.define( 'D/D', [ 'editor', 'A/A', 'C/C' ], () => {
+moduleUtils.define( 'D/D', [ 'editor/editor', 'A/A', 'C/C' ], () => {
 	return PluginD;
 	return PluginD;
 } );
 } );
 
 
-moduleUtils.define( 'E/E', [ 'editor', 'F/F' ], () => {
+moduleUtils.define( 'E/E', [ 'editor/editor', 'F/F' ], () => {
 	return PluginE;
 	return PluginE;
 } );
 } );
 
 
-moduleUtils.define( 'F/F', [ 'editor', 'E/E' ], () => {
+moduleUtils.define( 'F/F', [ 'editor/editor', 'E/E' ], () => {
 	return PluginF;
 	return PluginF;
 } );
 } );