From 21da4a2cfc6dc69f23ec2d064d5ca987945a679b Mon Sep 17 00:00:00 2001 From: Marcin Panek Date: Fri, 23 Dec 2022 14:21:00 +0100 Subject: [PATCH 1/4] Rewrite ckeditor5-page-break to TypeScript. --- .gitignore | 1 + packages/ckeditor5-page-break/package.json | 10 +++++--- .../src/{index.js => index.ts} | 0 .../src/{pagebreak.js => pagebreak.ts} | 13 +++++++--- ...agebreakcommand.js => pagebreakcommand.ts} | 13 +++++----- ...agebreakediting.js => pagebreakediting.ts} | 25 +++++++++++++------ .../src/{pagebreakui.js => pagebreakui.ts} | 12 ++++++--- packages/ckeditor5-page-break/tsconfig.json | 7 ++++++ .../tsconfig.release.json | 10 ++++++++ 9 files changed, 69 insertions(+), 22 deletions(-) rename packages/ckeditor5-page-break/src/{index.js => index.ts} (100%) rename packages/ckeditor5-page-break/src/{pagebreak.js => pagebreak.ts} (74%) rename packages/ckeditor5-page-break/src/{pagebreakcommand.js => pagebreakcommand.ts} (84%) rename packages/ckeditor5-page-break/src/{pagebreakediting.js => pagebreakediting.ts} (86%) rename packages/ckeditor5-page-break/src/{pagebreakui.js => pagebreakui.ts} (81%) create mode 100644 packages/ckeditor5-page-break/tsconfig.json create mode 100644 packages/ckeditor5-page-break/tsconfig.release.json diff --git a/.gitignore b/.gitignore index 7de95735d97..e54bdd92999 100644 --- a/.gitignore +++ b/.gitignore @@ -39,6 +39,7 @@ packages/ckeditor5-engine/src/**/*.js packages/ckeditor5-enter/src/**/*.js packages/ckeditor5-essentials/src/**/*.js packages/ckeditor5-list/src/**/*.js +packages/ckeditor5-page-break/src/**/*.js packages/ckeditor5-paragraph/src/**/*.js packages/ckeditor5-paste-from-office/src/**/*.js packages/ckeditor5-select-all/src/**/*.js diff --git a/packages/ckeditor5-page-break/package.json b/packages/ckeditor5-page-break/package.json index a5831f2ff0e..2ee65a25888 100644 --- a/packages/ckeditor5-page-break/package.json +++ b/packages/ckeditor5-page-break/package.json @@ -10,7 +10,7 @@ "ckeditor5-plugin", "ckeditor5-dll" ], - "main": "src/index.js", + "main": "src/index.ts", "dependencies": { "ckeditor5": "^35.4.0" }, @@ -26,6 +26,7 @@ "@ckeditor/ckeditor5-theme-lark": "^35.4.0", "@ckeditor/ckeditor5-ui": "^35.4.0", "@ckeditor/ckeditor5-widget": "^35.4.0", + "typescript": "^4.8.4", "webpack": "^5.58.1", "webpack-cli": "^4.9.0" }, @@ -44,13 +45,16 @@ }, "files": [ "lang", - "src", + "src/**/*.js", + "src/**/*.d.ts", "theme", "build", "ckeditor5-metadata.json", "CHANGELOG.md" ], "scripts": { - "dll:build": "webpack" + "dll:build": "webpack", + "build": "tsc -p ./tsconfig.release.json", + "postversion": "npm run build" } } diff --git a/packages/ckeditor5-page-break/src/index.js b/packages/ckeditor5-page-break/src/index.ts similarity index 100% rename from packages/ckeditor5-page-break/src/index.js rename to packages/ckeditor5-page-break/src/index.ts diff --git a/packages/ckeditor5-page-break/src/pagebreak.js b/packages/ckeditor5-page-break/src/pagebreak.ts similarity index 74% rename from packages/ckeditor5-page-break/src/pagebreak.js rename to packages/ckeditor5-page-break/src/pagebreak.ts index 35737292523..e36954b0629 100644 --- a/packages/ckeditor5-page-break/src/pagebreak.js +++ b/packages/ckeditor5-page-break/src/pagebreak.ts @@ -7,8 +7,9 @@ * @module page-break/pagebreak */ -import { Plugin } from 'ckeditor5/src/core'; +import { Plugin, type PluginDependencies } from 'ckeditor5/src/core'; import { Widget } from 'ckeditor5/src/widget'; + import PageBreakEditing from './pagebreakediting'; import PageBreakUI from './pagebreakui'; @@ -25,14 +26,20 @@ export default class PageBreak extends Plugin { /** * @inheritDoc */ - static get requires() { + public static get requires(): PluginDependencies { return [ PageBreakEditing, PageBreakUI, Widget ]; } /** * @inheritDoc */ - static get pluginName() { + public static get pluginName(): 'PageBreak' { return 'PageBreak'; } } + +declare module '@ckeditor/ckeditor5-core' { + interface PluginsMap { + [ PageBreak.pluginName ]: PageBreak; + } +} diff --git a/packages/ckeditor5-page-break/src/pagebreakcommand.js b/packages/ckeditor5-page-break/src/pagebreakcommand.ts similarity index 84% rename from packages/ckeditor5-page-break/src/pagebreakcommand.js rename to packages/ckeditor5-page-break/src/pagebreakcommand.ts index 278ae9414df..e697ef08d3a 100644 --- a/packages/ckeditor5-page-break/src/pagebreakcommand.js +++ b/packages/ckeditor5-page-break/src/pagebreakcommand.ts @@ -9,6 +9,7 @@ import { Command } from 'ckeditor5/src/core'; import { findOptimalInsertionRange } from 'ckeditor5/src/widget'; +import type { DocumentSelection, Element, Model, Schema } from 'ckeditor5/src/engine'; /** * The page break command. @@ -25,7 +26,7 @@ export default class PageBreakCommand extends Command { /** * @inheritDoc */ - refresh() { + public override refresh(): void { const model = this.editor.model; const schema = model.schema; const selection = model.document.selection; @@ -38,7 +39,7 @@ export default class PageBreakCommand extends Command { * * @fires execute */ - execute() { + public override execute(): void { const model = this.editor.model; model.change( writer => { @@ -57,7 +58,7 @@ export default class PageBreakCommand extends Command { // @param {module:engine/model/schema~Schema} schema // @param {module:engine/model/model~Model} model Model instance. // @returns {Boolean} -function isPageBreakAllowedInParent( selection, schema, model ) { +function isPageBreakAllowedInParent( selection: DocumentSelection, schema: Schema, model: Model ) { const parent = getInsertPageBreakParent( selection, model ); return schema.checkChild( parent, 'pageBreak' ); @@ -68,13 +69,13 @@ function isPageBreakAllowedInParent( selection, schema, model ) { // @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection // @param {module:engine/model/model~Model} model Model instance. // @returns {module:engine/model/element~Element} -function getInsertPageBreakParent( selection, model ) { +function getInsertPageBreakParent( selection: DocumentSelection, model: Model ) { const insertionRange = findOptimalInsertionRange( selection, model ); const parent = insertionRange.start.parent; if ( parent.isEmpty && !parent.is( 'element', '$root' ) ) { - return parent.parent; + return parent.parent as Element; } - return parent; + return parent as Element; } diff --git a/packages/ckeditor5-page-break/src/pagebreakediting.js b/packages/ckeditor5-page-break/src/pagebreakediting.ts similarity index 86% rename from packages/ckeditor5-page-break/src/pagebreakediting.js rename to packages/ckeditor5-page-break/src/pagebreakediting.ts index 5d8056d9dd8..f52d0e6aaf5 100644 --- a/packages/ckeditor5-page-break/src/pagebreakediting.js +++ b/packages/ckeditor5-page-break/src/pagebreakediting.ts @@ -9,6 +9,7 @@ import { Plugin } from 'ckeditor5/src/core'; import { toWidget } from 'ckeditor5/src/widget'; +import type { DowncastWriter, ViewContainerElement } from 'ckeditor5/src/engine'; import PageBreakCommand from './pagebreakcommand'; @@ -23,14 +24,14 @@ export default class PageBreakEditing extends Plugin { /** * @inheritDoc */ - static get pluginName() { + public static get pluginName(): 'PageBreakEditing' { return 'PageBreakEditing'; } /** * @inheritDoc */ - init() { + public init(): void { const editor = this.editor; const schema = editor.model.schema; const t = editor.t; @@ -90,7 +91,7 @@ export default class PageBreakEditing extends Plugin { const hasPageBreakAfter = element.getStyle( 'page-break-after' ) == 'always'; if ( !hasPageBreakBefore && !hasPageBreakAfter ) { - return; + return null; } // The "page break" div accepts only single child or no child at all. @@ -98,11 +99,11 @@ export default class PageBreakEditing extends Plugin { const viewSpan = element.getChild( 0 ); // The child must be the "span" element that is not displayed. - if ( !viewSpan.is( 'element', 'span' ) || viewSpan.getStyle( 'display' ) != 'none' ) { - return; + if ( !viewSpan!.is( 'element', 'span' ) || viewSpan.getStyle( 'display' ) != 'none' ) { + return null; } } else if ( element.childCount > 1 ) { - return; + return null; } return { name: true }; @@ -127,8 +128,18 @@ export default class PageBreakEditing extends Plugin { // @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer. // @param {String} label The element's label. // @returns {module:engine/view/element~Element} -function toPageBreakWidget( viewElement, writer, label ) { +function toPageBreakWidget( viewElement: ViewContainerElement, writer: DowncastWriter, label: string ) { writer.setCustomProperty( 'pageBreak', true, viewElement ); return toWidget( viewElement, writer, { label } ); } + +declare module '@ckeditor/ckeditor5-core' { + interface CommandsMap { + pageBreak: PageBreakCommand; + } + + interface PluginsMap { + [ PageBreakEditing.pluginName ]: PageBreakEditing; + } +} diff --git a/packages/ckeditor5-page-break/src/pagebreakui.js b/packages/ckeditor5-page-break/src/pagebreakui.ts similarity index 81% rename from packages/ckeditor5-page-break/src/pagebreakui.js rename to packages/ckeditor5-page-break/src/pagebreakui.ts index fda040532c9..d84cb4cc8d9 100644 --- a/packages/ckeditor5-page-break/src/pagebreakui.js +++ b/packages/ckeditor5-page-break/src/pagebreakui.ts @@ -21,20 +21,20 @@ export default class PageBreakUI extends Plugin { /** * @inheritDoc */ - static get pluginName() { + public static get pluginName(): 'PageBreakUI' { return 'PageBreakUI'; } /** * @inheritDoc */ - init() { + public init(): void { const editor = this.editor; const t = editor.t; // Add pageBreak button to feature components. editor.ui.componentFactory.add( 'pageBreak', locale => { - const command = editor.commands.get( 'pageBreak' ); + const command = editor.commands.get( 'pageBreak' )!; const view = new ButtonView( locale ); view.set( { @@ -55,3 +55,9 @@ export default class PageBreakUI extends Plugin { } ); } } + +declare module '@ckeditor/ckeditor5-core' { + interface PluginsMap { + [ PageBreakUI.pluginName ]: PageBreakUI; + } +} diff --git a/packages/ckeditor5-page-break/tsconfig.json b/packages/ckeditor5-page-break/tsconfig.json new file mode 100644 index 00000000000..9d4c891939c --- /dev/null +++ b/packages/ckeditor5-page-break/tsconfig.json @@ -0,0 +1,7 @@ +{ + "extends": "ckeditor5/tsconfig.json", + "include": [ + "src", + "../../typings" + ] +} diff --git a/packages/ckeditor5-page-break/tsconfig.release.json b/packages/ckeditor5-page-break/tsconfig.release.json new file mode 100644 index 00000000000..6d2d43909f9 --- /dev/null +++ b/packages/ckeditor5-page-break/tsconfig.release.json @@ -0,0 +1,10 @@ +{ + "extends": "../../tsconfig.release.json", + "include": [ + "./src/", + "../../typings/" + ], + "exclude": [ + "./tests/" + ] +} From 2a5dc23e9f9689bf67f5742327792209ccf42eaa Mon Sep 17 00:00:00 2001 From: Marcin Panek Date: Tue, 27 Dec 2022 14:48:36 +0100 Subject: [PATCH 2/4] Cleanup in documentation types. --- packages/ckeditor5-page-break/src/pagebreak.ts | 2 -- .../ckeditor5-page-break/src/pagebreakcommand.ts | 15 ++------------- .../ckeditor5-page-break/src/pagebreakediting.ts | 11 ++--------- packages/ckeditor5-page-break/src/pagebreakui.ts | 2 -- 4 files changed, 4 insertions(+), 26 deletions(-) diff --git a/packages/ckeditor5-page-break/src/pagebreak.ts b/packages/ckeditor5-page-break/src/pagebreak.ts index e36954b0629..85e881312fc 100644 --- a/packages/ckeditor5-page-break/src/pagebreak.ts +++ b/packages/ckeditor5-page-break/src/pagebreak.ts @@ -19,8 +19,6 @@ import PageBreakUI from './pagebreakui'; * It provides the possibility to insert a page break into the rich-text editor. * * For a detailed overview, check the {@glink features/page-break Page break feature} documentation. - * - * @extends module:core/plugin~Plugin */ export default class PageBreak extends Plugin { /** diff --git a/packages/ckeditor5-page-break/src/pagebreakcommand.ts b/packages/ckeditor5-page-break/src/pagebreakcommand.ts index e697ef08d3a..9202b9bd11a 100644 --- a/packages/ckeditor5-page-break/src/pagebreakcommand.ts +++ b/packages/ckeditor5-page-break/src/pagebreakcommand.ts @@ -19,8 +19,6 @@ import type { DocumentSelection, Element, Model, Schema } from 'ckeditor5/src/en * To insert a page break at the current selection, execute the command: * * editor.execute( 'pageBreak' ); - * - * @extends module:core/command~Command */ export default class PageBreakCommand extends Command { /** @@ -53,23 +51,14 @@ export default class PageBreakCommand extends Command { } // Checks if a page break is allowed by the schema in the optimal insertion parent. -// -// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection -// @param {module:engine/model/schema~Schema} schema -// @param {module:engine/model/model~Model} model Model instance. -// @returns {Boolean} -function isPageBreakAllowedInParent( selection: DocumentSelection, schema: Schema, model: Model ) { +function isPageBreakAllowedInParent( selection: DocumentSelection, schema: Schema, model: Model ): boolean { const parent = getInsertPageBreakParent( selection, model ); return schema.checkChild( parent, 'pageBreak' ); } // Returns a node that will be used to insert a page break with `model.insertContent` to check if the page break can be placed there. -// -// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection -// @param {module:engine/model/model~Model} model Model instance. -// @returns {module:engine/model/element~Element} -function getInsertPageBreakParent( selection: DocumentSelection, model: Model ) { +function getInsertPageBreakParent( selection: DocumentSelection, model: Model ): Element { const insertionRange = findOptimalInsertionRange( selection, model ); const parent = insertionRange.start.parent; diff --git a/packages/ckeditor5-page-break/src/pagebreakediting.ts b/packages/ckeditor5-page-break/src/pagebreakediting.ts index f52d0e6aaf5..7e3384db773 100644 --- a/packages/ckeditor5-page-break/src/pagebreakediting.ts +++ b/packages/ckeditor5-page-break/src/pagebreakediting.ts @@ -9,7 +9,7 @@ import { Plugin } from 'ckeditor5/src/core'; import { toWidget } from 'ckeditor5/src/widget'; -import type { DowncastWriter, ViewContainerElement } from 'ckeditor5/src/engine'; +import type { DowncastWriter, ViewElement } from 'ckeditor5/src/engine'; import PageBreakCommand from './pagebreakcommand'; @@ -17,8 +17,6 @@ import '../theme/pagebreak.css'; /** * The page break editing feature. - * - * @extends module:core/plugin~Plugin */ export default class PageBreakEditing extends Plugin { /** @@ -123,12 +121,7 @@ export default class PageBreakEditing extends Plugin { // * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to // recognize the page break widget element. // * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator. -// -// @param {module:engine/view/element~Element} viewElement -// @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer. -// @param {String} label The element's label. -// @returns {module:engine/view/element~Element} -function toPageBreakWidget( viewElement: ViewContainerElement, writer: DowncastWriter, label: string ) { +function toPageBreakWidget( viewElement: ViewElement, writer: DowncastWriter, label: string ): ViewElement { writer.setCustomProperty( 'pageBreak', true, viewElement ); return toWidget( viewElement, writer, { label } ); diff --git a/packages/ckeditor5-page-break/src/pagebreakui.ts b/packages/ckeditor5-page-break/src/pagebreakui.ts index d84cb4cc8d9..9c6f63dfea7 100644 --- a/packages/ckeditor5-page-break/src/pagebreakui.ts +++ b/packages/ckeditor5-page-break/src/pagebreakui.ts @@ -14,8 +14,6 @@ import pageBreakIcon from '../theme/icons/pagebreak.svg'; /** * The page break UI plugin. - * - * @extends module:core/plugin~Plugin */ export default class PageBreakUI extends Plugin { /** From c7dae7f8be928f3e67f9d13843b40eab490bec2f Mon Sep 17 00:00:00 2001 From: Marcin Panek Date: Wed, 28 Dec 2022 11:58:08 +0100 Subject: [PATCH 3/4] Update function comments to doclets. --- packages/ckeditor5-page-break/src/pagebreakcommand.ts | 8 ++++++-- packages/ckeditor5-page-break/src/pagebreakediting.ts | 10 ++++++---- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/ckeditor5-page-break/src/pagebreakcommand.ts b/packages/ckeditor5-page-break/src/pagebreakcommand.ts index 9202b9bd11a..382203d4dd5 100644 --- a/packages/ckeditor5-page-break/src/pagebreakcommand.ts +++ b/packages/ckeditor5-page-break/src/pagebreakcommand.ts @@ -50,14 +50,18 @@ export default class PageBreakCommand extends Command { } } -// Checks if a page break is allowed by the schema in the optimal insertion parent. +/** + * Checks if a page break is allowed by the schema in the optimal insertion parent. + */ function isPageBreakAllowedInParent( selection: DocumentSelection, schema: Schema, model: Model ): boolean { const parent = getInsertPageBreakParent( selection, model ); return schema.checkChild( parent, 'pageBreak' ); } -// Returns a node that will be used to insert a page break with `model.insertContent` to check if the page break can be placed there. +/** + * Returns a node that will be used to insert a page break with `model.insertContent` to check if the page break can be placed there. + */ function getInsertPageBreakParent( selection: DocumentSelection, model: Model ): Element { const insertionRange = findOptimalInsertionRange( selection, model ); const parent = insertionRange.start.parent; diff --git a/packages/ckeditor5-page-break/src/pagebreakediting.ts b/packages/ckeditor5-page-break/src/pagebreakediting.ts index 7e3384db773..1ea3d337a89 100644 --- a/packages/ckeditor5-page-break/src/pagebreakediting.ts +++ b/packages/ckeditor5-page-break/src/pagebreakediting.ts @@ -117,10 +117,12 @@ export default class PageBreakEditing extends Plugin { } } -// Converts a given {@link module:engine/view/element~Element} to a page break widget: -// * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to -// recognize the page break widget element. -// * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator. +/** + * Converts a given {@link module:engine/view/element~Element} to a page break widget: + * * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to + * recognize the page break widget element. + * * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator. + */ function toPageBreakWidget( viewElement: ViewElement, writer: DowncastWriter, label: string ): ViewElement { writer.setCustomProperty( 'pageBreak', true, viewElement ); From 69ed2b27345053242e34e175549441865d4da253 Mon Sep 17 00:00:00 2001 From: Arkadiusz Filipczak Date: Thu, 29 Dec 2022 11:20:32 +0100 Subject: [PATCH 4/4] Added ckeditor5-page-break/_src. --- packages/ckeditor5-page-break/_src/index.js | 12 ++ .../ckeditor5-page-break/_src/pagebreak.js | 38 +++++ .../_src/pagebreakcommand.js | 80 +++++++++++ .../_src/pagebreakediting.js | 134 ++++++++++++++++++ .../ckeditor5-page-break/_src/pagebreakui.js | 57 ++++++++ 5 files changed, 321 insertions(+) create mode 100644 packages/ckeditor5-page-break/_src/index.js create mode 100644 packages/ckeditor5-page-break/_src/pagebreak.js create mode 100644 packages/ckeditor5-page-break/_src/pagebreakcommand.js create mode 100644 packages/ckeditor5-page-break/_src/pagebreakediting.js create mode 100644 packages/ckeditor5-page-break/_src/pagebreakui.js diff --git a/packages/ckeditor5-page-break/_src/index.js b/packages/ckeditor5-page-break/_src/index.js new file mode 100644 index 00000000000..e8db1747953 --- /dev/null +++ b/packages/ckeditor5-page-break/_src/index.js @@ -0,0 +1,12 @@ +/** + * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module page-break + */ + +export { default as PageBreak } from './pagebreak'; +export { default as PageBreakEditing } from './pagebreakediting'; +export { default as PageBreakUI } from './pagebreakui'; diff --git a/packages/ckeditor5-page-break/_src/pagebreak.js b/packages/ckeditor5-page-break/_src/pagebreak.js new file mode 100644 index 00000000000..35737292523 --- /dev/null +++ b/packages/ckeditor5-page-break/_src/pagebreak.js @@ -0,0 +1,38 @@ +/** + * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module page-break/pagebreak + */ + +import { Plugin } from 'ckeditor5/src/core'; +import { Widget } from 'ckeditor5/src/widget'; +import PageBreakEditing from './pagebreakediting'; +import PageBreakUI from './pagebreakui'; + +/** + * The page break feature. + * + * It provides the possibility to insert a page break into the rich-text editor. + * + * For a detailed overview, check the {@glink features/page-break Page break feature} documentation. + * + * @extends module:core/plugin~Plugin + */ +export default class PageBreak extends Plugin { + /** + * @inheritDoc + */ + static get requires() { + return [ PageBreakEditing, PageBreakUI, Widget ]; + } + + /** + * @inheritDoc + */ + static get pluginName() { + return 'PageBreak'; + } +} diff --git a/packages/ckeditor5-page-break/_src/pagebreakcommand.js b/packages/ckeditor5-page-break/_src/pagebreakcommand.js new file mode 100644 index 00000000000..278ae9414df --- /dev/null +++ b/packages/ckeditor5-page-break/_src/pagebreakcommand.js @@ -0,0 +1,80 @@ +/** + * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module page-break/pagebreakcommand + */ + +import { Command } from 'ckeditor5/src/core'; +import { findOptimalInsertionRange } from 'ckeditor5/src/widget'; + +/** + * The page break command. + * + * The command is registered by {@link module:page-break/pagebreakediting~PageBreakEditing} as `'pageBreak'`. + * + * To insert a page break at the current selection, execute the command: + * + * editor.execute( 'pageBreak' ); + * + * @extends module:core/command~Command + */ +export default class PageBreakCommand extends Command { + /** + * @inheritDoc + */ + refresh() { + const model = this.editor.model; + const schema = model.schema; + const selection = model.document.selection; + + this.isEnabled = isPageBreakAllowedInParent( selection, schema, model ); + } + + /** + * Executes the command. + * + * @fires execute + */ + execute() { + const model = this.editor.model; + + model.change( writer => { + const pageBreakElement = writer.createElement( 'pageBreak' ); + + model.insertObject( pageBreakElement, null, null, { + setSelection: 'after' + } ); + } ); + } +} + +// Checks if a page break is allowed by the schema in the optimal insertion parent. +// +// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection +// @param {module:engine/model/schema~Schema} schema +// @param {module:engine/model/model~Model} model Model instance. +// @returns {Boolean} +function isPageBreakAllowedInParent( selection, schema, model ) { + const parent = getInsertPageBreakParent( selection, model ); + + return schema.checkChild( parent, 'pageBreak' ); +} + +// Returns a node that will be used to insert a page break with `model.insertContent` to check if the page break can be placed there. +// +// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection +// @param {module:engine/model/model~Model} model Model instance. +// @returns {module:engine/model/element~Element} +function getInsertPageBreakParent( selection, model ) { + const insertionRange = findOptimalInsertionRange( selection, model ); + const parent = insertionRange.start.parent; + + if ( parent.isEmpty && !parent.is( 'element', '$root' ) ) { + return parent.parent; + } + + return parent; +} diff --git a/packages/ckeditor5-page-break/_src/pagebreakediting.js b/packages/ckeditor5-page-break/_src/pagebreakediting.js new file mode 100644 index 00000000000..5d8056d9dd8 --- /dev/null +++ b/packages/ckeditor5-page-break/_src/pagebreakediting.js @@ -0,0 +1,134 @@ +/** + * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module page-break/pagebreakediting + */ + +import { Plugin } from 'ckeditor5/src/core'; +import { toWidget } from 'ckeditor5/src/widget'; + +import PageBreakCommand from './pagebreakcommand'; + +import '../theme/pagebreak.css'; + +/** + * The page break editing feature. + * + * @extends module:core/plugin~Plugin + */ +export default class PageBreakEditing extends Plugin { + /** + * @inheritDoc + */ + static get pluginName() { + return 'PageBreakEditing'; + } + + /** + * @inheritDoc + */ + init() { + const editor = this.editor; + const schema = editor.model.schema; + const t = editor.t; + const conversion = editor.conversion; + + schema.register( 'pageBreak', { + inheritAllFrom: '$blockObject' + } ); + + conversion.for( 'dataDowncast' ).elementToStructure( { + model: 'pageBreak', + view: ( modelElement, { writer } ) => { + const divElement = writer.createContainerElement( 'div', + { + class: 'page-break', + // If user has no `.ck-content` styles, it should always break a page during print. + style: 'page-break-after: always' + }, + // For a rationale of using span inside a div see: + // https://github.com/ckeditor/ckeditor5-page-break/pull/1#discussion_r328934062. + writer.createContainerElement( 'span', { + style: 'display: none' + } ) + ); + + return divElement; + } + } ); + + conversion.for( 'editingDowncast' ).elementToStructure( { + model: 'pageBreak', + view: ( modelElement, { writer } ) => { + const label = t( 'Page break' ); + const viewWrapper = writer.createContainerElement( 'div' ); + const viewLabelElement = writer.createRawElement( + 'span', + { class: 'page-break__label' }, + function( domElement ) { + domElement.innerText = t( 'Page break' ); + } + ); + + writer.addClass( 'page-break', viewWrapper ); + writer.insert( writer.createPositionAt( viewWrapper, 0 ), viewLabelElement ); + + return toPageBreakWidget( viewWrapper, writer, label ); + } + } ); + + conversion.for( 'upcast' ) + .elementToElement( { + view: element => { + // For upcast conversion it's enough if we check for element style and verify if it's empty + // or contains only hidden span element. + + const hasPageBreakBefore = element.getStyle( 'page-break-before' ) == 'always'; + const hasPageBreakAfter = element.getStyle( 'page-break-after' ) == 'always'; + + if ( !hasPageBreakBefore && !hasPageBreakAfter ) { + return; + } + + // The "page break" div accepts only single child or no child at all. + if ( element.childCount == 1 ) { + const viewSpan = element.getChild( 0 ); + + // The child must be the "span" element that is not displayed. + if ( !viewSpan.is( 'element', 'span' ) || viewSpan.getStyle( 'display' ) != 'none' ) { + return; + } + } else if ( element.childCount > 1 ) { + return; + } + + return { name: true }; + }, + model: 'pageBreak', + + // This conversion must be checked before
conversion because some editors use + //
as a page break marker. + converterPriority: 'high' + } ); + + editor.commands.add( 'pageBreak', new PageBreakCommand( editor ) ); + } +} + +// Converts a given {@link module:engine/view/element~Element} to a page break widget: +// * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to +// recognize the page break widget element. +// * Calls the {@link module:widget/utils~toWidget} function with the proper element's label creator. +// +// @param {module:engine/view/element~Element} viewElement +// @param {module:engine/view/downcastwriter~DowncastWriter} writer An instance of the view writer. +// @param {String} label The element's label. +// @returns {module:engine/view/element~Element} +function toPageBreakWidget( viewElement, writer, label ) { + writer.setCustomProperty( 'pageBreak', true, viewElement ); + + return toWidget( viewElement, writer, { label } ); +} diff --git a/packages/ckeditor5-page-break/_src/pagebreakui.js b/packages/ckeditor5-page-break/_src/pagebreakui.js new file mode 100644 index 00000000000..fda040532c9 --- /dev/null +++ b/packages/ckeditor5-page-break/_src/pagebreakui.js @@ -0,0 +1,57 @@ +/** + * @license Copyright (c) 2003-2022, CKSource Holding sp. z o.o. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module page-break/pagebreakui + */ + +import { Plugin } from 'ckeditor5/src/core'; +import { ButtonView } from 'ckeditor5/src/ui'; + +import pageBreakIcon from '../theme/icons/pagebreak.svg'; + +/** + * The page break UI plugin. + * + * @extends module:core/plugin~Plugin + */ +export default class PageBreakUI extends Plugin { + /** + * @inheritDoc + */ + static get pluginName() { + return 'PageBreakUI'; + } + + /** + * @inheritDoc + */ + init() { + const editor = this.editor; + const t = editor.t; + + // Add pageBreak button to feature components. + editor.ui.componentFactory.add( 'pageBreak', locale => { + const command = editor.commands.get( 'pageBreak' ); + const view = new ButtonView( locale ); + + view.set( { + label: t( 'Page break' ), + icon: pageBreakIcon, + tooltip: true + } ); + + view.bind( 'isEnabled' ).to( command, 'isEnabled' ); + + // Execute command. + this.listenTo( view, 'execute', () => { + editor.execute( 'pageBreak' ); + editor.editing.view.focus(); + } ); + + return view; + } ); + } +}