The styles processor instance.
ReadonlydocumentInstance of the module:engine/view/document~ViewDocument associated with this view controller.
ReadonlydomInstance of the module:engine/view/domconverter~ViewDomConverter domConverter used by module:engine/view/view~EditingView#_renderer renderer and module:engine/view/observer/observer~Observer observers.
ReadonlydomRoots of the DOM tree. Map on the HTMLElements with roots names as keys.
ReadonlyhasInforms whether the DOM selection is inside any of the DOM roots managed by the view.
ReadonlyisUsed to prevent calling #forceRender and #change during rendering view to the DOM.
InternalDisables or enables rendering. If the flag is set to true then the rendering will be disabled.
If the flag is set to false and if there was some change in the meantime, then the rendering action will be performed.
A flag indicates whether the rendering should be disabled.
Creates observer of the given type if not yet created, module:engine/view/observer/observer~Observer#enable enables it and module:engine/view/observer/observer~Observer#observe attaches to all existing and future #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.
The constructor of an observer to add. Should create an instance inheriting from module:engine/view/observer/observer~Observer.
Added observer instance.
Attaches a DOM root element to the view element and enable all observers on that element. Also module:engine/view/renderer~ViewRenderer#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.
Note: Use #detachDomRoot detachDomRoot() to revert this action.
DOM root element.
Optionalname: stringName of the root.
Binds #set observable properties to other objects implementing the module:utils/observablemixin~Observable interface.
Read more in the {@glink framework/deep-dive/observables#property-bindings dedicated} guide covering the topic of property bindings with some additional examples.
Consider two objects: a button and an associated command (both Observable).
A simple property binding could be as follows:
button.bind( 'isEnabled' ).to( command, 'isEnabled' );
or even shorter:
button.bind( 'isEnabled' ).to( command );
which works in the following way:
button.isEnabled instantly equals command.isEnabled,command.isEnabled changes, button.isEnabled will immediately reflect its value.Note: To release the binding, use module:utils/observablemixin~Observable#unbind.
You can also "rename" the property in the binding by specifying the new name in the to() chain:
button.bind( 'isEnabled' ).to( command, 'isWorking' );
It is possible to bind more than one property at a time to shorten the code:
button.bind( 'isEnabled', 'value' ).to( command );
which corresponds to:
button.bind( 'isEnabled' ).to( command );
button.bind( 'value' ).to( command );
The binding can include more than one observable, combining multiple data sources in a custom callback:
button.bind( 'isEnabled' ).to( command, 'isEnabled', ui, 'isVisible',
( isCommandEnabled, isUIVisible ) => isCommandEnabled && isUIVisible );
Using a custom callback allows processing the value before passing it to the target property:
button.bind( 'isEnabled' ).to( command, 'value', value => value === 'heading1' );
It is also possible to bind to the same property in an array of observables.
To bind a button to multiple commands (also Observables) so that each and every one of them
must be enabled for the button to become enabled, use the following code:
button.bind( 'isEnabled' ).toMany( [ commandA, commandB, commandC ], 'isEnabled',
( isAEnabled, isBEnabled, isCEnabled ) => isAEnabled && isBEnabled && isCEnabled );
Observable property that will be bound to other observable(s).
The bind chain with the to() and toMany() methods.
Binds #set observable properties to other objects implementing the module:utils/observablemixin~Observable interface.
Read more in the {@glink framework/deep-dive/observables#property-bindings dedicated} guide covering the topic of property bindings with some additional examples.
Consider two objects: a button and an associated command (both Observable).
A simple property binding could be as follows:
button.bind( 'isEnabled' ).to( command, 'isEnabled' );
or even shorter:
button.bind( 'isEnabled' ).to( command );
which works in the following way:
button.isEnabled instantly equals command.isEnabled,command.isEnabled changes, button.isEnabled will immediately reflect its value.Note: To release the binding, use module:utils/observablemixin~Observable#unbind.
You can also "rename" the property in the binding by specifying the new name in the to() chain:
button.bind( 'isEnabled' ).to( command, 'isWorking' );
It is possible to bind more than one property at a time to shorten the code:
button.bind( 'isEnabled', 'value' ).to( command );
which corresponds to:
button.bind( 'isEnabled' ).to( command );
button.bind( 'value' ).to( command );
The binding can include more than one observable, combining multiple data sources in a custom callback:
button.bind( 'isEnabled' ).to( command, 'isEnabled', ui, 'isVisible',
( isCommandEnabled, isUIVisible ) => isCommandEnabled && isUIVisible );
Using a custom callback allows processing the value before passing it to the target property:
button.bind( 'isEnabled' ).to( command, 'value', value => value === 'heading1' );
It is also possible to bind to the same property in an array of observables.
To bind a button to multiple commands (also Observables) so that each and every one of them
must be enabled for the button to become enabled, use the following code:
button.bind( 'isEnabled' ).toMany( [ commandA, commandB, commandC ], 'isEnabled',
( isAEnabled, isBEnabled, isCEnabled ) => isAEnabled && isBEnabled && isCEnabled );
The bind chain with the to() and toMany() methods.
Binds #set observable properties to other objects implementing the module:utils/observablemixin~Observable interface.
Read more in the {@glink framework/deep-dive/observables#property-bindings dedicated} guide covering the topic of property bindings with some additional examples.
Consider two objects: a button and an associated command (both Observable).
A simple property binding could be as follows:
button.bind( 'isEnabled' ).to( command, 'isEnabled' );
or even shorter:
button.bind( 'isEnabled' ).to( command );
which works in the following way:
button.isEnabled instantly equals command.isEnabled,command.isEnabled changes, button.isEnabled will immediately reflect its value.Note: To release the binding, use module:utils/observablemixin~Observable#unbind.
You can also "rename" the property in the binding by specifying the new name in the to() chain:
button.bind( 'isEnabled' ).to( command, 'isWorking' );
It is possible to bind more than one property at a time to shorten the code:
button.bind( 'isEnabled', 'value' ).to( command );
which corresponds to:
button.bind( 'isEnabled' ).to( command );
button.bind( 'value' ).to( command );
The binding can include more than one observable, combining multiple data sources in a custom callback:
button.bind( 'isEnabled' ).to( command, 'isEnabled', ui, 'isVisible',
( isCommandEnabled, isUIVisible ) => isCommandEnabled && isUIVisible );
Using a custom callback allows processing the value before passing it to the target property:
button.bind( 'isEnabled' ).to( command, 'value', value => value === 'heading1' );
It is also possible to bind to the same property in an array of observables.
To bind a button to multiple commands (also Observables) so that each and every one of them
must be enabled for the button to become enabled, use the following code:
button.bind( 'isEnabled' ).toMany( [ commandA, commandB, commandC ], 'isEnabled',
( isAEnabled, isBEnabled, isCEnabled ) => isAEnabled && isBEnabled && isCEnabled );
Observable properties that will be bound to other observable(s).
The bind chain with the to() and toMany() methods.
The change() method is the primary way of changing the view. You should use it to modify any node in the view tree.
It makes sure that after all changes are made the view is rendered to the DOM (assuming that the view will be changed
inside the callback). It prevents situations when the DOM is updated when the view state is not yet correct. It allows
to nest calls one inside another and still performs a single rendering after all those changes are made.
It also returns the return value of its callback.
const text = view.change( writer => {
const newText = writer.createText( 'foo' );
writer.insert( position1, newText );
view.change( writer => {
writer.insert( position2, writer.createText( 'bar' ) );
} );
writer.remove( range );
return newText;
} );
When the outermost change block is done and rendering to the DOM is over the
module:engine/view/view~EditingView#event:render View#render event is fired.
This method throws a applying-view-changes-on-rendering error when
the change block is used after rendering to the DOM has started.
Callback function which may modify the view.
Value returned by the callback.
Creates a new position after given view item.
View item after which the position should be located.
Creates position at the given location. The location can be specified as:
0),'end' (sets position at the end of that element),'before' or 'after' (sets position before or after given view item).This method is a shortcut to other constructors such as:
Optionaloffset: ViewPositionOffsetOffset or one of the flags. Used only when first parameter is a module:engine/view/item~ViewItem view item.
Creates a new position before given view item.
View item before which the position should be located.
Creates a range spanning from start position to end position.
Note: This factory method creates it's own module:engine/view/position~ViewPosition instances basing on passed values.
Start position.
Optionalend: ViewPositionEnd position. If not set, range will be collapsed at start position.
Creates a range inside an module:engine/view/element~ViewElement element which starts before the first child of that element and ends after the last child of that element.
Element which is a parent for the range.
Creates new module:engine/view/selection~ViewSelection instance.
// Creates collapsed selection at the position of given item and offset.
const paragraph = view.createContainerElement( 'paragraph' );
const selection = view.createSelection( paragraph, offset );
// Creates a range inside an {@link module:engine/view/element~ViewElement element} which starts before the
// first child of that element and ends after the last child of that element.
const selection = view.createSelection( paragraph, 'in' );
// Creates a range on an {@link module:engine/view/item~ViewItem item} which starts before the item and ends
// just after the item.
const selection = view.createSelection( paragraph, 'on' );
Selection's factory method allow passing additional options (backward, fake and label) as the last argument.
// Creates backward selection.
const selection = view.createSelection( paragraph, 'in', { backward: true } );
Fake selection does not render as browser native selection over selected elements and is hidden to the user. This way, no native selection UI artifacts are displayed to the user and selection over elements can be represented in other way, for example by applying proper CSS class.
Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM (and be properly handled by screen readers).
// Creates fake selection with label.
const selection = view.createSelection( element, 'in', { fake: true, label: 'foo' } );
See also: #createSelection:SELECTABLE createSelection( selectable, options ).
Optionaloptions: ViewSelectionOptionsCreates new module:engine/view/selection~ViewSelection instance.
// Creates empty selection without ranges.
const selection = view.createSelection();
// Creates selection at the given range.
const range = view.createRange( start, end );
const selection = view.createSelection( range );
// Creates selection at the given ranges
const ranges = [ view.createRange( start1, end2 ), view.createRange( star2, end2 ) ];
const selection = view.createSelection( ranges );
// Creates selection from the other selection.
const otherSelection = view.createSelection();
const selection = view.createSelection( otherSelection );
// Creates selection from the document selection.
const selection = view.createSelection( editor.editing.view.document.selection );
// Creates selection at the given position.
const position = view.createPositionFromPath( root, path );
const selection = view.createSelection( position );
Selection's factory method allow passing additional options (backward, fake and label) as the last argument.
// Creates backward selection.
const selection = view.createSelection( range, { backward: true } );
Fake selection does not render as browser native selection over selected elements and is hidden to the user. This way, no native selection UI artifacts are displayed to the user and selection over elements can be represented in other way, for example by applying proper CSS class.
Additionally fake's selection label can be provided. It will be used to describe fake selection in DOM (and be properly handled by screen readers).
// Creates fake selection with label.
const selection = view.createSelection( range, { fake: true, label: 'foo' } );
See also: #createSelection:NODE_OFFSET createSelection( node, placeOrOffset, options ).
Optionalselectable: Optionaloptions: ViewSelectionOptionsTurns the given methods of this object into event-based ones. This means that the new method will fire an event (named after the method) and the original action will be plugged as a listener to that event.
Read more in the {@glink framework/deep-dive/observables#decorating-object-methods dedicated} guide covering the topic of decorating methods with some additional examples.
Decorating the method does not change its behavior (it only adds an event), but it allows to modify it later on by listening to the method's event.
For example, to cancel the method execution the event can be module:utils/eventinfo~EventInfo#stop stopped:
class Foo extends ObservableMixin() {
constructor() {
super();
this.decorate( 'method' );
}
method() {
console.log( 'called!' );
}
}
const foo = new Foo();
foo.on( 'method', ( evt ) => {
evt.stop();
}, { priority: 'high' } );
foo.method(); // Nothing is logged.
Note: The high module:utils/priorities~PriorityString priority listener has been used to execute this particular callback before the one which calls the original method (which uses the "normal" priority).
It is also possible to change the returned value:
foo.on( 'method', ( evt ) => {
evt.return = 'Foo!';
} );
foo.method(); // -> 'Foo'
Finally, it is possible to access and modify the arguments the method is called with:
method( a, b ) {
console.log( `${ a }, ${ b }` );
}
// ...
foo.on( 'method', ( evt, args ) => {
args[ 0 ] = 3;
console.log( args[ 1 ] ); // -> 2
}, { priority: 'high' } );
foo.method( 1, 2 ); // -> '3, 2'
Name of the method to decorate.
Delegates selected events to another module:utils/emittermixin~Emitter. For instance:
emitterA.delegate( 'eventX' ).to( emitterB );
emitterA.delegate( 'eventX', 'eventY' ).to( emitterC );
then eventX is delegated (fired by) emitterB and emitterC along with data:
emitterA.fire( 'eventX', data );
and eventY is delegated (fired by) emitterC along with data:
emitterA.fire( 'eventY', data );
Event names that will be delegated to another emitter.
Destroys this instance. Makes sure that all observers are destroyed and listeners removed.
Detaches a DOM root element from the view element and restores its attributes to the state before
#attachDomRoot attachDomRoot().
Name of the root to detach.
Disables all added observers.
Enables all added observers.
Fires an event, executing all callbacks registered for it.
The first parameter passed to callbacks is an module:utils/eventinfo~EventInfo object,
followed by the optional args provided in the fire() method call.
The type describing the event. See module:utils/emittermixin~BaseEvent.
The name of the event or EventInfo object if event is delegated.
Additional arguments to be passed to the callbacks.
By default the method returns undefined. However, the return value can be changed by listeners
through modification of the module:utils/eventinfo~EventInfo#return evt.return's property (the event info
is the first param of every callback).
It will focus DOM element representing module:engine/view/editableelement~ViewEditableElement ViewEditableElement that is currently having selection inside.
Forces rendering module:engine/view/document~ViewDocument view document to DOM. If any view changes are currently in progress, rendering will start after all #change change blocks are processed.
Note that this method is dedicated for special cases. All view changes should be wrapped in the #change block and the view will automatically check whether it needs to render DOM or not.
Throws module:utils/ckeditorerror~CKEditorError CKEditorError applying-view-changes-on-rendering when
trying to re-render when rendering to DOM has already started.
Gets DOM root element.
Optionalname: stringName of the root.
DOM root element instance.
Registers a callback function to be executed when an event is fired in a specific (emitter) object.
Events can be grouped in namespaces using :.
When namespaced event is fired, it additionally fires all callbacks for that namespace.
// myEmitter.on( ... ) is a shorthand for myEmitter.listenTo( myEmitter, ... ).
myEmitter.on( 'myGroup', genericCallback );
myEmitter.on( 'myGroup:myEvent', specificCallback );
// genericCallback is fired.
myEmitter.fire( 'myGroup' );
// both genericCallback and specificCallback are fired.
myEmitter.fire( 'myGroup:myEvent' );
// genericCallback is fired even though there are no callbacks for "foo".
myEmitter.fire( 'myGroup:foo' );
An event callback can module:utils/eventinfo~EventInfo#stop stop the event and set the module:utils/eventinfo~EventInfo#return return value of the #fire method.
The type describing the event. See module:utils/emittermixin~BaseEvent.
The object that fires the event.
The name of the event.
The function to be called on event.
Optionaloptions: GetCallbackOptions<TEvent>Additional options.
Stops executing the callback on the given event.
Shorthand for #stopListening this.stopListening( this, event, callback ).
The name of the event.
The function to stop being called.
Registers a callback function to be executed when an event is fired.
Shorthand for #listenTo this.listenTo( this, event, callback, options ) (it makes the emitter
listen on itself).
The type descibing the event. See module:utils/emittermixin~BaseEvent.
The name of the event.
The function to be called on event.
Optionaloptions: GetCallbackOptions<TEvent>Additional options.
Registers a callback function to be executed on the next time the event is fired only. This is similar to calling #on followed by #off in the callback.
The type descibing the event. See module:utils/emittermixin~BaseEvent.
The name of the event.
The function to be called on event.
Optionaloptions: GetCallbackOptions<TEvent>Additional options.
Scrolls the page viewport and #domRoots with their ancestors to reveal the caret, if not already visible to the user.
Note: Calling this method fires the module:engine/view/view~ViewScrollToTheSelectionEvent event that allows custom behaviors.
Optionaloptions: {Additional configuration of the scrolling behavior.
Optional ReadonlyalignToTop?: TWhen set true, the DOM selection will be aligned to the top of the viewport if not already visible
(see forceScroll to learn more).
Optional ReadonlyancestorOffset?: numberA distance between the DOM selection and scrollable DOM root ancestor(s) to be maintained
while scrolling to the selection (default is 20px). Setting this value to 0 will reveal the selection precisely at
the scrollable ancestor(s) boundary.
Optional ReadonlyforceScroll?: UWhen set true, the DOM selection will be aligned to the top of the viewport and scrollable ancestors
whether it is already visible or not. This option will only work when alignToTop is true.
Optional ReadonlyviewportOffset?: number | { bottom: number; left: number; right: number; top: number }A distance between the DOM selection and the viewport boundary to be maintained
while scrolling to the selection (default is 20px). Setting this value to 0 will reveal the selection precisely at
the viewport boundary.
Creates and sets the value of an observable property of this object. Such a property becomes a part of the state and is observable.
This method throws the observable-set-cannot-override error if the observable instance already
has a property with the given property name. This prevents from mistakenly overriding existing
properties and methods, but means that foo.set( 'bar', 1 ) may be slightly slower than foo.bar = 1.
In TypeScript, those properties should be declared in class using declare keyword. In example:
public declare myProp: number;
constructor() {
this.set( 'myProp', 2 );
}
The property's name.
The property's value.
Creates and sets the value of an observable properties of this object. Such a property becomes a part of the state and is observable.
It accepts a single object literal containing key/value pairs with properties to be set.
This method throws the observable-set-cannot-override error if the observable instance already
has a property with the given property name. This prevents from mistakenly overriding existing
properties and methods, but means that foo.set( 'bar', 1 ) may be slightly slower than foo.bar = 1.
In TypeScript, those properties should be declared in class using declare keyword. In example:
public declare myProp1: number;
public declare myProp2: string;
constructor() {
this.set( {
'myProp1: 2,
'myProp2: 'foo'
} );
}
An object with name=>value pairs.
Optional_disableRendering?: unknownOptionaladdObserver?: unknownOptionalattachDomRoot?: unknownOptionalbind?: unknownOptionalchange?: unknownOptionalcreatePositionAfter?: unknownOptionalcreatePositionAt?: unknownOptionalcreatePositionBefore?: unknownOptionalcreateRange?: unknownOptionalcreateRangeIn?: unknownOptionalcreateRangeOn?: unknownOptionalcreateSelection?: unknownOptionaldecorate?: unknownOptionaldelegate?: unknownOptionaldestroy?: unknownOptionaldetachDomRoot?: unknownOptionaldisableObservers?: unknownOptional Readonlydocument?: unknownInstance of the module:engine/view/document~ViewDocument associated with this view controller.
Optional ReadonlydomConverter?: unknownInstance of the module:engine/view/domconverter~ViewDomConverter domConverter used by module:engine/view/view~EditingView#_renderer renderer and module:engine/view/observer/observer~Observer observers.
Optional ReadonlydomRoots?: unknownRoots of the DOM tree. Map on the HTMLElements with roots names as keys.
OptionalenableObservers?: unknownOptionalfire?: unknownOptionalfocus?: unknownOptionalforceRender?: unknownOptionalgetDomRoot?: unknownOptionalgetObserver?: unknownOptional ReadonlyhasDomSelection?: unknownInforms whether the DOM selection is inside any of the DOM roots managed by the view.
Optional ReadonlyisRenderingInProgress?: unknownUsed to prevent calling #forceRender and #change during rendering view to the DOM.
OptionallistenTo?: unknownOptionaloff?: unknownOptionalon?: unknownOptionalonce?: unknownOptionalscrollToTheSelection?: unknownOptionalset?: unknownOptionalstopDelegating?: unknownOptionalstopListening?: unknownOptionalunbind?: unknownStops delegating events. It can be used at different levels:
Optionalevent: stringThe name of the event to stop delegating. If omitted, stops it all delegations.
Optionalemitter: Emitter(requires event) The object to stop delegating a particular event to.
If omitted, stops delegation of event to all emitters.
Stops listening for events. It can be used at different levels:
Optionalemitter: EmitterThe object to stop listening to. If omitted, stops it for all objects.
Optionalevent: string(Requires the emitter) The name of the event to stop listening to. If omitted, stops it
for all events from emitter.
Optionalcallback: Function(Requires the event) The function to be removed from the call list for the given
event.
Removes the binding created with #bind.
// Removes the binding for the 'a' property.
A.unbind( 'a' );
// Removes bindings for all properties.
A.unbind();
Observable properties to be unbound. All the bindings will be released if no properties are provided.
Editor's view controller class. Its main responsibility is DOM - View management for editing purposes, to provide abstraction over the DOM structure and events and hide all browsers quirks.
View controller renders view document to DOM whenever view structure changes. To determine when view can be rendered, all changes need to be done using the module:engine/view/view~EditingView#change method, using module:engine/view/downcastwriter~ViewDowncastWriter:
View controller also register module:engine/view/observer/observer~Observer observers which observes changes on DOM and fire events on the module:engine/view/document~ViewDocument Document. Note that the following observers are added by the class constructor and are always available:
This class also module:engine/view/view~EditingView#attachDomRoot binds the DOM and the view elements.
If you do not need full a DOM - view management, and only want to transform a tree of view elements to a tree of DOM elements you do not need this controller. You can use the module:engine/view/domconverter~ViewDomConverter ViewDomConverter instead.