Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added full page editing mode #12978

Merged
merged 4 commits into from
Dec 12, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 34 additions & 0 deletions packages/ckeditor5-engine/src/controller/datacontroller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,8 @@ export default class DataController extends EmitterMixin() {
ObservableMixin().prototype.decorate.call( this, 'init' as any );
ObservableMixin().prototype.decorate.call( this, 'set' as any );
ObservableMixin().prototype.decorate.call( this, 'get' as any );
ObservableMixin().prototype.decorate.call( this, 'toView' as any );
ObservableMixin().prototype.decorate.call( this, 'toModel' as any );

// Fire the `ready` event when the initialization has completed. Such low-level listener offers the possibility
// to plug into the initialization pipeline without interrupting the initialization flow.
Expand Down Expand Up @@ -259,6 +261,7 @@ export default class DataController extends EmitterMixin() {
* converters attached to {@link #downcastDispatcher} into a
* {@link module:engine/view/documentfragment~DocumentFragment view document fragment}.
*
* @fires toView
* @param {module:engine/model/element~Element|module:engine/model/documentfragment~DocumentFragment} modelElementOrFragment
* Element or document fragment whose content will be converted.
* @param {Object} [options={}] Additional configuration that will be available through the
Expand Down Expand Up @@ -456,6 +459,7 @@ export default class DataController extends EmitterMixin() {
* When marker elements were converted during the conversion process, it will be set as a document fragment's
* {@link module:engine/model/documentfragment~DocumentFragment#markers static markers map}.
*
* @fires toModel
* @param {module:engine/view/element~Element|module:engine/view/documentfragment~DocumentFragment} viewElementOrFragment
* The element or document fragment whose content will be converted.
* @param {module:engine/model/schema~SchemaContextDefinition} [context='$root'] Base context in which the view will
Expand Down Expand Up @@ -565,6 +569,24 @@ export default class DataController extends EmitterMixin() {
*
* @event get
*/

/**
* Event fired after the {@link #toView toView() method} has been run.
*
* The `toView` event is fired by the decorated {@link #toView} method.
* See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.
*
* @event toView
*/

/**
* Event fired after the {@link #toModel toModel() method} has been run.
*
* The `toModel` event is fired by the decorated {@link #toModel} method.
* See {@link module:utils/observablemixin~ObservableMixin#decorate} for more information and samples.
*
* @event toModel
*/
}

// Helper function for downcast conversion.
Expand Down Expand Up @@ -659,3 +681,15 @@ export type DataControllerGetEvent = {
args: [ Parameters<DataController[ 'get' ]> ];
return: ReturnType<DataController[ 'get' ]>;
};

export type DataControllerToModelEvent = {
name: 'toModel';
args: [ Parameters<DataController[ 'toModel' ]> ];
return: ReturnType<DataController[ 'toModel' ]>;
};

export type DataControllerToViewEvent = {
name: 'toView';
args: [ Parameters<DataController[ 'toView' ]> ];
return: ReturnType<DataController[ 'toView' ]>;
};
Original file line number Diff line number Diff line change
Expand Up @@ -120,11 +120,10 @@ export default class HtmlDataProcessor implements DataProcessor {
* Converts an HTML string to its DOM representation. Returns a document fragment containing nodes parsed from
* the provided data.
*
* @private
* @param {String} data
* @returns {DocumentFragment}
*/
private _toDom( data: string ): DocumentFragment {
protected _toDom( data: string ): DocumentFragment {
// Wrap data with a <body> tag so leading non-layout nodes (like <script>, <style>, HTML comment)
// will be preserved in the body collection.
// Do it only for data that is not a full HTML document.
Expand Down
54 changes: 54 additions & 0 deletions packages/ckeditor5-engine/src/view/documentfragment.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import type Node from './node';
export default class DocumentFragment extends EmitterMixin( TypeCheckable ) {
public readonly document: Document;
private readonly _children: Array<Node>;
private readonly _customProperties: Map<string | symbol, unknown>;

/**
* Creates new DocumentFragment instance.
Expand Down Expand Up @@ -59,6 +60,15 @@ export default class DocumentFragment extends EmitterMixin( TypeCheckable ) {
if ( children ) {
this._insertChild( 0, children );
}

/**
* Map of custom properties.
* Custom properties can be added to document fragment instance.
*
* @protected
* @member {Map}
*/
this._customProperties = new Map();
}

/**
Expand Down Expand Up @@ -112,6 +122,26 @@ export default class DocumentFragment extends EmitterMixin( TypeCheckable ) {
return null;
}

/**
* Returns the custom property value for the given key.
*
* @param {String|Symbol} key
* @returns {*}
*/
public getCustomProperty( key: string | symbol ): unknown {
return this._customProperties.get( key );
}

/**
* Returns an iterator which iterates over this document fragment's custom properties.
* Iterator provides `[ key, value ]` pairs for each stored property.
*
* @returns {Iterable.<*>}
*/
public* getCustomProperties(): Iterable<[ string | symbol, unknown ]> {
yield* this._customProperties.entries();
}

/**
* {@link module:engine/view/documentfragment~DocumentFragment#_insertChild Insert} a child node or a list of child nodes at the end
* and sets the parent of these nodes to this fragment.
Expand Down Expand Up @@ -212,6 +242,30 @@ export default class DocumentFragment extends EmitterMixin( TypeCheckable ) {
this.fire( 'change:' + type, node );
}

/**
* Sets a custom property. They can be used to add special data to elements.
*
* @see module:engine/view/downcastwriter~DowncastWriter#setCustomProperty
* @protected
* @param {String|Symbol} key
* @param {*} value
*/
public _setCustomProperty( key: string | symbol, value: unknown ): void {
this._customProperties.set( key, value );
}

/**
* Removes the custom property stored under the given key.
*
* @see module:engine/view/downcastwriter~DowncastWriter#removeCustomProperty
* @protected
* @param {String|Symbol} key
* @returns {Boolean} Returns true if property was removed.
*/
public _removeCustomProperty( key: string | symbol ): boolean {
return this._customProperties.delete( key );
}

// @if CK_DEBUG_ENGINE // printTree() {
// @if CK_DEBUG_ENGINE // let string = 'ViewDocumentFragment: [';

Expand Down
4 changes: 2 additions & 2 deletions packages/ckeditor5-engine/src/view/downcastwriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ export default class DowncastWriter {
* @param {*} value
* @param {module:engine/view/element~Element} element
*/
public setCustomProperty( key: string | symbol, value: unknown, element: Element ): void {
public setCustomProperty( key: string | symbol, value: unknown, element: Element | DocumentFragment ): void {
element._setCustomProperty( key, value );
}

Expand All @@ -567,7 +567,7 @@ export default class DowncastWriter {
* @param {module:engine/view/element~Element} element
* @returns {Boolean} Returns true if property was removed.
*/
public removeCustomProperty( key: string | symbol, element: Element ): boolean {
public removeCustomProperty( key: string | symbol, element: Element | DocumentFragment ): boolean {
return element._removeCustomProperty( key );
}

Expand Down
4 changes: 2 additions & 2 deletions packages/ckeditor5-engine/src/view/upcastwriter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ export default class UpcastWriter {
* @param {*} value Custom property value to be stored.
* @param {module:engine/view/element~Element} element Element for which custom property will be set.
*/
public setCustomProperty( key: string | symbol, value: unknown, element: Element ): void {
public setCustomProperty( key: string | symbol, value: unknown, element: Element | DocumentFragment ): void {
element._setCustomProperty( key, value );
}

Expand All @@ -351,7 +351,7 @@ export default class UpcastWriter {
* @param {module:engine/view/element~Element} element Element from which the custom property will be removed.
* @returns {Boolean} Returns true if property was removed.
*/
public removeCustomProperty( key: string | symbol, element: Element ): boolean {
public removeCustomProperty( key: string | symbol, element: Element | DocumentFragment ): boolean {
return element._removeCustomProperty( key );
}

Expand Down
20 changes: 20 additions & 0 deletions packages/ckeditor5-engine/tests/controller/datacontroller.js
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,16 @@ describe( 'DataController', () => {
upcastHelpers.elementToElement( { view: 'p', model: 'paragraph' } );
} );

it( 'should be decorated', () => {
const viewElement = parseView( '<p>foo</p>' );
const spy = sinon.spy();

data.on( 'toModel', spy );
data.toModel( viewElement );

sinon.assert.calledWithExactly( spy, sinon.match.any, [ viewElement ] );
} );

it( 'should convert content of an element #1', () => {
const viewElement = parseView( '<p>foo</p>' );
const output = data.toModel( viewElement );
Expand Down Expand Up @@ -622,6 +632,16 @@ describe( 'DataController', () => {
downcastHelpers.elementToElement( { model: 'div', view: 'div' } );
} );

it( 'should be decorated', () => {
const modelElement = parseModel( '<div><paragraph>foo</paragraph></div>', schema );
const spy = sinon.spy();

data.on( 'toView', spy );
data.toView( modelElement );

sinon.assert.calledWithExactly( spy, sinon.match.any, [ modelElement ] );
} );

it( 'should use #viewDocument as a parent for returned document fragments', () => {
const modelElement = parseModel( '<div><paragraph>foo</paragraph></div>', schema );
const viewDocumentFragment = data.toView( modelElement );
Expand Down
53 changes: 53 additions & 0 deletions packages/ckeditor5-engine/tests/view/documentfragment.js
Original file line number Diff line number Diff line change
Expand Up @@ -318,4 +318,57 @@ describe( 'DocumentFragment', () => {
expect( fragment.getChild( 0 ) ).to.equal( node2 );
} );
} );

describe( 'custom properties', () => {
it( 'should allow to set and get custom properties', () => {
const fragment = new DocumentFragment( document );

fragment._setCustomProperty( 'foo', 'bar' );

expect( fragment.getCustomProperty( 'foo' ) ).to.equal( 'bar' );
} );

it( 'should allow to add symbol property', () => {
const fragment = new DocumentFragment( document );
const symbol = Symbol( 'custom' );

fragment._setCustomProperty( symbol, 'bar' );

expect( fragment.getCustomProperty( symbol ) ).to.equal( 'bar' );
} );

it( 'should allow to remove custom property', () => {
const fragment = new DocumentFragment( document );
const symbol = Symbol( 'quix' );

fragment._setCustomProperty( 'bar', 'baz' );
fragment._setCustomProperty( symbol, 'test' );

expect( fragment.getCustomProperty( 'bar' ) ).to.equal( 'baz' );
expect( fragment.getCustomProperty( symbol ) ).to.equal( 'test' );

fragment._removeCustomProperty( 'bar' );
fragment._removeCustomProperty( symbol );

expect( fragment.getCustomProperty( 'bar' ) ).to.be.undefined;
expect( fragment.getCustomProperty( symbol ) ).to.be.undefined;
} );

it( 'should allow to iterate over custom properties', () => {
const fragment = new DocumentFragment( document );

fragment._setCustomProperty( 'foo', 1 );
fragment._setCustomProperty( 'bar', 2 );
fragment._setCustomProperty( 'baz', 3 );

const properties = Array.from( fragment.getCustomProperties() );

expect( properties[ 0 ][ 0 ] ).to.equal( 'foo' );
expect( properties[ 0 ][ 1 ] ).to.equal( 1 );
expect( properties[ 1 ][ 0 ] ).to.equal( 'bar' );
expect( properties[ 1 ][ 1 ] ).to.equal( 2 );
expect( properties[ 2 ][ 0 ] ).to.equal( 'baz' );
expect( properties[ 2 ][ 1 ] ).to.equal( 3 );
} );
} );
} );
18 changes: 18 additions & 0 deletions packages/ckeditor5-engine/tests/view/downcastwriter/writer.js
Original file line number Diff line number Diff line change
Expand Up @@ -426,6 +426,14 @@ describe( 'DowncastWriter', () => {

expect( element.getCustomProperty( 'foo' ) ).to.equal( 'bar' );
} );

it( 'should set custom property to given document fragment', () => {
const fragment = writer.createDocumentFragment();

writer.setCustomProperty( 'foo', 'bar', fragment );

expect( fragment.getCustomProperty( 'foo' ) ).to.equal( 'bar' );
} );
} );

describe( 'removeCustomProperty()', () => {
Expand All @@ -438,6 +446,16 @@ describe( 'DowncastWriter', () => {
writer.removeCustomProperty( 'foo', element );
expect( element.getCustomProperty( 'foo' ) ).to.be.undefined;
} );

it( 'should remove custom property from given document fragment', () => {
const fragment = writer.createDocumentFragment();

writer.setCustomProperty( 'foo', 'bar', fragment );
expect( fragment.getCustomProperty( 'foo' ) ).to.equal( 'bar' );

writer.removeCustomProperty( 'foo', fragment );
expect( fragment.getCustomProperty( 'foo' ) ).to.be.undefined;
} );
} );

describe( 'createPositionAt()', () => {
Expand Down
37 changes: 35 additions & 2 deletions packages/ckeditor5-engine/tests/view/upcastwriter.js
Original file line number Diff line number Diff line change
Expand Up @@ -536,7 +536,7 @@ describe( 'UpcastWriter', () => {
} );

describe( 'setCustomProperty', () => {
it( 'should add or update custom property', () => {
it( 'should add or update custom property on element', () => {
const el = new Element( 'span' );

writer.setCustomProperty( 'prop1', 'foo', el );
Expand All @@ -553,10 +553,29 @@ describe( 'UpcastWriter', () => {
expect( el.getCustomProperty( 'prop2' ) ).to.equal( objectProperty );
expect( Array.from( el.getCustomProperties() ).length ).to.equal( 2 );
} );

it( 'should add or update custom property on document fragment', () => {
const fragment = new DocumentFragment();

writer.setCustomProperty( 'prop1', 'foo', fragment );
writer.setCustomProperty( 'prop2', 'bar', fragment );

expect( fragment.getCustomProperty( 'prop1' ) ).to.equal( 'foo' );
expect( fragment.getCustomProperty( 'prop2' ) ).to.equal( 'bar' );
expect( Array.from( fragment.getCustomProperties() ).length ).to.equal( 2 );

const objectProperty = { foo: 'bar' };

writer.setCustomProperty( 'prop2', objectProperty, fragment );

expect( fragment.getCustomProperty( 'prop1' ) ).to.equal( 'foo' );
expect( fragment.getCustomProperty( 'prop2' ) ).to.equal( objectProperty );
expect( Array.from( fragment.getCustomProperties() ).length ).to.equal( 2 );
} );
} );

describe( 'removeCustomProperty', () => {
it( 'should remove existing custom property', () => {
it( 'should remove existing custom property from element', () => {
const el = new Element( 'p' );

writer.setCustomProperty( 'prop1', 'foo', el );
Expand All @@ -570,6 +589,20 @@ describe( 'UpcastWriter', () => {
expect( Array.from( el.getCustomProperties() ).length ).to.equal( 0 );
} );

it( 'should remove existing custom property from document fragment', () => {
const fragment = new DocumentFragment();

writer.setCustomProperty( 'prop1', 'foo', fragment );

expect( fragment.getCustomProperty( 'prop1' ) ).to.equal( 'foo' );
expect( Array.from( fragment.getCustomProperties() ).length ).to.equal( 1 );

writer.removeCustomProperty( 'prop1', fragment );

expect( fragment.getCustomProperty( 'prop1' ) ).to.undefined;
expect( Array.from( fragment.getCustomProperties() ).length ).to.equal( 0 );
} );

it( 'should have no effect if custom property does not exists', () => {
const el = new Element( 'h1' );

Expand Down
1 change: 1 addition & 0 deletions packages/ckeditor5-html-support/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
"@ckeditor/ckeditor5-alignment": "^35.3.2",
"@ckeditor/ckeditor5-basic-styles": "^35.3.2",
"@ckeditor/ckeditor5-block-quote": "^35.3.2",
"@ckeditor/ckeditor5-clipboard": "^35.3.2",
"@ckeditor/ckeditor5-cloud-services": "^35.3.2",
"@ckeditor/ckeditor5-code-block": "^35.3.2",
"@ckeditor/ckeditor5-core": "^35.3.2",
Expand Down
Loading