|
@@ -10,16 +10,9 @@
|
|
|
import Selection from './selection';
|
|
import Selection from './selection';
|
|
|
import { injectQuirksHandling } from './filler';
|
|
import { injectQuirksHandling } from './filler';
|
|
|
import { injectUiElementHandling } from './uielement';
|
|
import { injectUiElementHandling } from './uielement';
|
|
|
-import log from '@ckeditor/ckeditor5-utils/src/log';
|
|
|
|
|
-import MutationObserver from './observer/mutationobserver';
|
|
|
|
|
-import SelectionObserver from './observer/selectionobserver';
|
|
|
|
|
-import FocusObserver from './observer/focusobserver';
|
|
|
|
|
-import KeyObserver from './observer/keyobserver';
|
|
|
|
|
-import FakeSelectionObserver from './observer/fakeselectionobserver';
|
|
|
|
|
import Collection from '@ckeditor/ckeditor5-utils/src/collection';
|
|
import Collection from '@ckeditor/ckeditor5-utils/src/collection';
|
|
|
import mix from '@ckeditor/ckeditor5-utils/src/mix';
|
|
import mix from '@ckeditor/ckeditor5-utils/src/mix';
|
|
|
import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
|
|
import ObservableMixin from '@ckeditor/ckeditor5-utils/src/observablemixin';
|
|
|
-import { scrollViewportToShowTarget } from '@ckeditor/ckeditor5-utils/src/dom/scroll';
|
|
|
|
|
|
|
|
|
|
// todo: check the docs
|
|
// todo: check the docs
|
|
|
/**
|
|
/**
|
|
@@ -46,14 +39,6 @@ export default class Document {
|
|
|
* Creates a Document instance.
|
|
* Creates a Document instance.
|
|
|
*/
|
|
*/
|
|
|
constructor() {
|
|
constructor() {
|
|
|
- /**
|
|
|
|
|
- * Roots of the DOM tree. Map on the `HTMLElement`s with roots names as keys.
|
|
|
|
|
- *
|
|
|
|
|
- * @readonly
|
|
|
|
|
- * @member {Map} module:engine/view/document~Document#domRoots
|
|
|
|
|
- */
|
|
|
|
|
- this.domRoots = new Map();
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* Selection done on this document.
|
|
* Selection done on this document.
|
|
|
*
|
|
*
|
|
@@ -97,99 +82,10 @@ export default class Document {
|
|
|
*/
|
|
*/
|
|
|
this.set( 'isFocused', false );
|
|
this.set( 'isFocused', false );
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * Map of registered {@link module:engine/view/observer/observer~Observer observers}.
|
|
|
|
|
- *
|
|
|
|
|
- * @private
|
|
|
|
|
- * @member {Map.<Function, module:engine/view/observer/observer~Observer>} module:engine/view/document~Document#_observers
|
|
|
|
|
- */
|
|
|
|
|
- this._observers = new Map();
|
|
|
|
|
-
|
|
|
|
|
- // Add default observers.
|
|
|
|
|
- this.addObserver( MutationObserver );
|
|
|
|
|
- this.addObserver( SelectionObserver );
|
|
|
|
|
- this.addObserver( FocusObserver );
|
|
|
|
|
- this.addObserver( KeyObserver );
|
|
|
|
|
- this.addObserver( FakeSelectionObserver );
|
|
|
|
|
-
|
|
|
|
|
injectQuirksHandling( this );
|
|
injectQuirksHandling( this );
|
|
|
injectUiElementHandling( this );
|
|
injectUiElementHandling( this );
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- /**
|
|
|
|
|
- * Creates observer of the given type if not yet created, {@link module:engine/view/observer/observer~Observer#enable enables} it
|
|
|
|
|
- * and {@link module:engine/view/observer/observer~Observer#observe attaches} to all existing and future
|
|
|
|
|
- * {@link module:engine/view/document~Document#domRoots DOM roots}.
|
|
|
|
|
- *
|
|
|
|
|
- * Note: Observers are recognized by their constructor (classes). A single observer will be instantiated and used only
|
|
|
|
|
- * when registered for the first time. This means that features and other components can register a single observer
|
|
|
|
|
- * multiple times without caring whether it has been already added or not.
|
|
|
|
|
- *
|
|
|
|
|
- * @param {Function} Observer The constructor of an observer to add.
|
|
|
|
|
- * Should create an instance inheriting from {@link module:engine/view/observer/observer~Observer}.
|
|
|
|
|
- * @returns {module:engine/view/observer/observer~Observer} Added observer instance.
|
|
|
|
|
- */
|
|
|
|
|
- addObserver( Observer ) {
|
|
|
|
|
- let observer = this._observers.get( Observer );
|
|
|
|
|
-
|
|
|
|
|
- if ( observer ) {
|
|
|
|
|
- return observer;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- observer = new Observer( this );
|
|
|
|
|
-
|
|
|
|
|
- this._observers.set( Observer, observer );
|
|
|
|
|
-
|
|
|
|
|
- for ( const [ name, domElement ] of this.domRoots ) {
|
|
|
|
|
- observer.observe( domElement, name );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- observer.enable();
|
|
|
|
|
-
|
|
|
|
|
- return observer;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * Returns observer of the given type or `undefined` if such observer has not been added yet.
|
|
|
|
|
- *
|
|
|
|
|
- * @param {Function} Observer The constructor of an observer to get.
|
|
|
|
|
- * @returns {module:engine/view/observer/observer~Observer|undefined} Observer instance or undefined.
|
|
|
|
|
- */
|
|
|
|
|
- getObserver( Observer ) {
|
|
|
|
|
- return this._observers.get( Observer );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * Attaches DOM root element to the view element and enable all observers on that element.
|
|
|
|
|
- * Also {@link module:engine/view/renderer~Renderer#markToSync mark element} to be synchronized with the view
|
|
|
|
|
- * what means that all child nodes will be removed and replaced with content of the view root.
|
|
|
|
|
- *
|
|
|
|
|
- * This method also will change view element name as the same as tag name of given dom root.
|
|
|
|
|
- * Name is always transformed to lower case.
|
|
|
|
|
- *
|
|
|
|
|
- * @param {Element} domRoot DOM root element.
|
|
|
|
|
- * @param {String} [name='main'] Name of the root.
|
|
|
|
|
- */
|
|
|
|
|
- attachDomRoot( domRoot, name = 'main' ) {
|
|
|
|
|
- const viewRoot = this.getRoot( name );
|
|
|
|
|
-
|
|
|
|
|
- // Set view root name the same as DOM root tag name.
|
|
|
|
|
- viewRoot._name = domRoot.tagName.toLowerCase();
|
|
|
|
|
-
|
|
|
|
|
- this.domRoots.set( name, domRoot );
|
|
|
|
|
- this.domConverter.bindElements( domRoot, viewRoot );
|
|
|
|
|
- this.renderer.markToSync( 'children', viewRoot );
|
|
|
|
|
- this.renderer.domDocuments.add( domRoot.ownerDocument );
|
|
|
|
|
-
|
|
|
|
|
- viewRoot.on( 'change:children', ( evt, node ) => this.renderer.markToSync( 'children', node ) );
|
|
|
|
|
- viewRoot.on( 'change:attributes', ( evt, node ) => this.renderer.markToSync( 'attributes', node ) );
|
|
|
|
|
- viewRoot.on( 'change:text', ( evt, node ) => this.renderer.markToSync( 'text', node ) );
|
|
|
|
|
-
|
|
|
|
|
- for ( const observer of this._observers.values() ) {
|
|
|
|
|
- observer.observe( domRoot, name );
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
/**
|
|
/**
|
|
|
* Gets a {@link module:engine/view/document~Document#roots view root element} with the specified name. If the name is not
|
|
* Gets a {@link module:engine/view/document~Document#roots view root element} with the specified name. If the name is not
|
|
|
* specific "main" root is returned.
|
|
* specific "main" root is returned.
|
|
@@ -201,82 +97,6 @@ export default class Document {
|
|
|
getRoot( name = 'main' ) {
|
|
getRoot( name = 'main' ) {
|
|
|
return this.roots.get( name );
|
|
return this.roots.get( name );
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * Gets DOM root element.
|
|
|
|
|
- *
|
|
|
|
|
- * @param {String} [name='main'] Name of the root.
|
|
|
|
|
- * @returns {Element} DOM root element instance.
|
|
|
|
|
- */
|
|
|
|
|
- getDomRoot( name = 'main' ) {
|
|
|
|
|
- return this.domRoots.get( name );
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * Focuses document. It will focus {@link module:engine/view/editableelement~EditableElement EditableElement} that is currently having
|
|
|
|
|
- * selection inside.
|
|
|
|
|
- */
|
|
|
|
|
- focus() {
|
|
|
|
|
- if ( !this.isFocused ) {
|
|
|
|
|
- const editable = this.selection.editableElement;
|
|
|
|
|
-
|
|
|
|
|
- if ( editable ) {
|
|
|
|
|
- this.domConverter.focus( editable );
|
|
|
|
|
- this.render();
|
|
|
|
|
- } else {
|
|
|
|
|
- /**
|
|
|
|
|
- * Before focusing view document, selection should be placed inside one of the view's editables.
|
|
|
|
|
- * Normally its selection will be converted from model document (which have default selection), but
|
|
|
|
|
- * when using view document on its own, we need to manually place selection before focusing it.
|
|
|
|
|
- *
|
|
|
|
|
- * @error view-focus-no-selection
|
|
|
|
|
- */
|
|
|
|
|
- log.warn( 'view-focus-no-selection: There is no selection in any editable to focus.' );
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * Scrolls the page viewport and {@link #domRoots} with their ancestors to reveal the
|
|
|
|
|
- * caret, if not already visible to the user.
|
|
|
|
|
- */
|
|
|
|
|
- scrollToTheSelection() {
|
|
|
|
|
- const range = this.selection.getFirstRange();
|
|
|
|
|
-
|
|
|
|
|
- if ( range ) {
|
|
|
|
|
- scrollViewportToShowTarget( {
|
|
|
|
|
- target: this.domConverter.viewRangeToDom( range ),
|
|
|
|
|
- viewportOffset: 20
|
|
|
|
|
- } );
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * Disables all added observers.
|
|
|
|
|
- */
|
|
|
|
|
- disableObservers() {
|
|
|
|
|
- for ( const observer of this._observers.values() ) {
|
|
|
|
|
- observer.disable();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * Enables all added observers.
|
|
|
|
|
- */
|
|
|
|
|
- enableObservers() {
|
|
|
|
|
- for ( const observer of this._observers.values() ) {
|
|
|
|
|
- observer.enable();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- /**
|
|
|
|
|
- * Destroys all observers created by view `Document`.
|
|
|
|
|
- */
|
|
|
|
|
- destroy() {
|
|
|
|
|
- for ( const observer of this._observers.values() ) {
|
|
|
|
|
- observer.destroy();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
mix( Document, ObservableMixin );
|
|
mix( Document, ObservableMixin );
|