From de0e73f26309d194719a8b90eba6c71c23926a7c Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Wed, 28 Aug 2019 14:43:17 +0200 Subject: [PATCH 01/24] Converters for the horizontal rule. --- package.json | 3 ++ src/horizontalrule.js | 34 +++++++++++++++++++++ src/horizontalruleediting.js | 59 ++++++++++++++++++++++++++++++++++++ src/horizontalruleui.js | 16 ++++++++++ 4 files changed, 112 insertions(+) create mode 100644 src/horizontalrule.js create mode 100644 src/horizontalruleediting.js create mode 100644 src/horizontalruleui.js diff --git a/package.json b/package.json index 670732c..2e7c78b 100644 --- a/package.json +++ b/package.json @@ -10,8 +10,11 @@ "ckeditor5-plugin" ], "dependencies": { + "@ckeditor/ckeditor5-core": "^12.2.1", + "@ckeditor/ckeditor5-widget": "^11.0.4" }, "devDependencies": { + "@ckeditor/ckeditor5-editor-classic": "^12.1.3", "eslint": "^5.5.0", "eslint-config-ckeditor5": "^2.0.0", "husky": "^1.3.1", diff --git a/src/horizontalrule.js b/src/horizontalrule.js new file mode 100644 index 0000000..9ba1bce --- /dev/null +++ b/src/horizontalrule.js @@ -0,0 +1,34 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module horizontal-rule/horizontalrule + */ + +import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; +import HorizontalRuleEditing from './horizontalruleediting'; +import HorizontalRuleUI from './horizontalruleui'; + +/** + * The horizontal rule plugin. + * + * + * @extends module:core/plugin~Plugin + */ +export default class HorizontalRule extends Plugin { + /** + * @inheritDoc + */ + static get requires() { + return [ HorizontalRuleEditing, HorizontalRuleUI ]; + } + + /** + * @inheritDoc + */ + static get pluginName() { + return 'HorizontalRule'; + } +} diff --git a/src/horizontalruleediting.js b/src/horizontalruleediting.js new file mode 100644 index 0000000..b28749e --- /dev/null +++ b/src/horizontalruleediting.js @@ -0,0 +1,59 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module horizontal-rule/horizontalruleediting + */ + +import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; +import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; + +/** + * @extends module:core/plugin~Plugin + */ +export default class HorizontalRuleEditing extends Plugin { + /** + * @inheritDoc + */ + init() { + const editor = this.editor; + const schema = editor.model.schema; + const t = editor.t; + const conversion = editor.conversion; + + schema.register( 'horizontalRule', { + isBlock: true, + isObject: true, + allowWhere: '$block' + } ); + + conversion.for( 'dataDowncast' ).elementToElement( { + model: 'horizontalRule', + view: ( modelElement, viewWriter ) => { + return viewWriter.createEmptyElement( 'hr' ); + } + } ); + + conversion.for( 'editingDowncast' ).elementToElement( { + model: 'horizontalRule', + view: ( modelElement, viewWriter ) => { + const label = t( 'Horizontal rule' ); + const viewElement = viewWriter.createEmptyElement( 'hr' ); + + viewWriter.setCustomProperty( 'hr', true, viewElement ); + + return toWidget( viewElement, viewWriter, { label } ); + } + } ); + + conversion.for( 'upcast' ) + .elementToElement( { + view: 'hr', + model: ( viewElement, modelWriter ) => { + return modelWriter.createElement( 'horizontalRule' ); + } + } ); + } +} diff --git a/src/horizontalruleui.js b/src/horizontalruleui.js new file mode 100644 index 0000000..4be471d --- /dev/null +++ b/src/horizontalruleui.js @@ -0,0 +1,16 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module horizontal-rule/horizontalruleui + */ + +import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; + +/** + * @extends module:core/plugin~Plugin + */ +export default class HorizontalRuleUI extends Plugin { +} From b77824efd99da153d9e1aed5ad5d6ecebd05ba99 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Wed, 28 Aug 2019 14:43:28 +0200 Subject: [PATCH 02/24] Added manual test. --- tests/manual/horizontalrule.html | 5 +++++ tests/manual/horizontalrule.js | 24 ++++++++++++++++++++++++ tests/manual/horizontalrule.md | 1 + 3 files changed, 30 insertions(+) create mode 100644 tests/manual/horizontalrule.html create mode 100644 tests/manual/horizontalrule.js create mode 100644 tests/manual/horizontalrule.md diff --git a/tests/manual/horizontalrule.html b/tests/manual/horizontalrule.html new file mode 100644 index 0000000..a468dc5 --- /dev/null +++ b/tests/manual/horizontalrule.html @@ -0,0 +1,5 @@ +
+

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Mauris viverra ipsum a sapien accumsan, in fringilla ligula congue. Suspendisse eget urna ac nulla dignissim sollicitudin vel non sem. Curabitur consequat nisi vel orci mollis tincidunt. Nam eget sapien non ligula aliquet commodo vel sed lectus. Sed arcu orci, vehicula vitae augue lobortis, posuere tristique nisl. Sed eleifend venenatis magna in elementum. Cras sit amet arcu mi. Suspendisse vel purus a ex maximus pharetra quis in massa. Mauris pellentesque leo sed mi faucibus molestie. Cras felis justo, volutpat sed erat at, lacinia fermentum nunc. Pellentesque est leo, dignissim at odio sit amet, vulputate placerat turpis. Vestibulum ante ipsum primis in faucibus orci luctus et ultrices posuere cubilia Curae; Nulla eget pharetra enim. Donec fermentum ligula est, quis ultrices arcu tristique eu. Vivamus a dui sem.

+
+

Nunc mattis vehicula quam, eu ultrices elit. Nam rutrum, magna vel pharetra fermentum, mauris lectus aliquam mauris, ultrices sagittis massa justo ut urna. Curabitur nec odio commodo, euismod orci quis, lacinia magna. Cras cursus id dui et eleifend. Fusce eget consequat ante. Quisque at odio diam. Praesent vel lacinia urna, vel hendrerit diam. Nulla facilisi. Curabitur finibus augue luctus mi dapibus rutrum. Vestibulum id mi quam. Donec accumsan felis lacus, ac luctus arcu sagittis eget. Suspendisse porttitor mattis magna, in finibus ligula suscipit non. Mauris dictum convallis vehicula.

+
diff --git a/tests/manual/horizontalrule.js b/tests/manual/horizontalrule.js new file mode 100644 index 0000000..96d5a28 --- /dev/null +++ b/tests/manual/horizontalrule.js @@ -0,0 +1,24 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/* globals console, window, document */ + +import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor'; +import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset'; +import HorizontalRule from '../../src/horizontalrule'; + +ClassicEditor + .create( document.querySelector( '#editor' ), { + plugins: [ ArticlePluginSet, HorizontalRule ], + toolbar: [ + 'heading', 'bold', 'italic', 'bulletedList', 'numberedList', 'blockQuote', 'link', 'undo', 'redo' + ] + } ) + .then( editor => { + window.editor = editor; + } ) + .catch( err => { + console.error( err.stack ); + } ); diff --git a/tests/manual/horizontalrule.md b/tests/manual/horizontalrule.md new file mode 100644 index 0000000..bd5b7b9 --- /dev/null +++ b/tests/manual/horizontalrule.md @@ -0,0 +1 @@ +There should be a horizontal line between two paragraphs in the editor. From 98f47be1eb2261047acee754e980fcbb0e6fa40c Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Wed, 28 Aug 2019 16:12:12 +0200 Subject: [PATCH 03/24] Use selection handler for the editing element. --- src/horizontalruleediting.js | 10 ++++++++-- theme/horizontalrule.css | 12 ++++++++++++ 2 files changed, 20 insertions(+), 2 deletions(-) create mode 100644 theme/horizontalrule.css diff --git a/src/horizontalruleediting.js b/src/horizontalruleediting.js index b28749e..511bf84 100644 --- a/src/horizontalruleediting.js +++ b/src/horizontalruleediting.js @@ -10,6 +10,8 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; +import '../theme/horizontalrule.css'; + /** * @extends module:core/plugin~Plugin */ @@ -40,11 +42,15 @@ export default class HorizontalRuleEditing extends Plugin { model: 'horizontalRule', view: ( modelElement, viewWriter ) => { const label = t( 'Horizontal rule' ); - const viewElement = viewWriter.createEmptyElement( 'hr' ); + const viewElement = viewWriter.createContainerElement( 'div' ); + viewWriter.addClass( 'ck-horizontal-rule', viewElement ); viewWriter.setCustomProperty( 'hr', true, viewElement ); - return toWidget( viewElement, viewWriter, { label } ); + return toWidget( viewElement, viewWriter, { + label, + hasSelectionHandler: true + } ); } } ); diff --git a/theme/horizontalrule.css b/theme/horizontalrule.css new file mode 100644 index 0000000..9342eb4 --- /dev/null +++ b/theme/horizontalrule.css @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +.ck-horizontal-rule { + border: 1px solid var(--ck-color-toolbar-border); + border-radius: 50%; + width: 90%; + margin-left: auto; + margin-right: auto; +} From f6fa712355a9e32d7130d43ba707e201e91d0994 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Thu, 29 Aug 2019 09:41:40 +0200 Subject: [PATCH 04/24] Added a fake icon and introduced a command that adds the horizontal rule to the editor. --- lang/contexts.json | 3 +++ package.json | 1 + src/horizontalrulecommand.js | 37 ++++++++++++++++++++++++++++++++++ src/horizontalruleediting.js | 3 +++ src/horizontalruleui.js | 26 ++++++++++++++++++++++++ tests/manual/horizontalrule.js | 2 +- theme/icons/horizontalrule.svg | 1 + 7 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 lang/contexts.json create mode 100644 src/horizontalrulecommand.js create mode 100644 theme/icons/horizontalrule.svg diff --git a/lang/contexts.json b/lang/contexts.json new file mode 100644 index 0000000..a2a4b0b --- /dev/null +++ b/lang/contexts.json @@ -0,0 +1,3 @@ +{ + "Horizontal rule": "Horizontal rule" +} diff --git a/package.json b/package.json index 2e7c78b..0cfe24d 100644 --- a/package.json +++ b/package.json @@ -11,6 +11,7 @@ ], "dependencies": { "@ckeditor/ckeditor5-core": "^12.2.1", + "@ckeditor/ckeditor5-ui": "^14.0.0", "@ckeditor/ckeditor5-widget": "^11.0.4" }, "devDependencies": { diff --git a/src/horizontalrulecommand.js b/src/horizontalrulecommand.js new file mode 100644 index 0000000..5b7d13c --- /dev/null +++ b/src/horizontalrulecommand.js @@ -0,0 +1,37 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module horizontal-rule/horizontalrulecommand + */ + +import Command from '@ckeditor/ckeditor5-core/src/command'; +import { findOptimalInsertionPosition } from '@ckeditor/ckeditor5-widget/src/utils'; + +export default class HorizontalRuleCommand extends Command { + /** + * @inheritDoc + */ + refresh() { + this.isEnabled = true; + } + + /** + * Executes the command. + * + * @fires execute + */ + execute() { + const model = this.editor.model; + const selection = model.document.selection; + + model.change( writer => { + const modelElement = writer.createElement( 'horizontalRule' ); + const insertPosition = findOptimalInsertionPosition( selection, model ); + + model.insertContent( modelElement, insertPosition ); + } ); + } +} diff --git a/src/horizontalruleediting.js b/src/horizontalruleediting.js index 511bf84..5dfe19b 100644 --- a/src/horizontalruleediting.js +++ b/src/horizontalruleediting.js @@ -9,6 +9,7 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; +import HorizontalRuleCommand from './horizontalrulecommand'; import '../theme/horizontalrule.css'; @@ -61,5 +62,7 @@ export default class HorizontalRuleEditing extends Plugin { return modelWriter.createElement( 'horizontalRule' ); } } ); + + editor.commands.add( 'horizontalRule', new HorizontalRuleCommand( editor ) ); } } diff --git a/src/horizontalruleui.js b/src/horizontalruleui.js index 4be471d..5205561 100644 --- a/src/horizontalruleui.js +++ b/src/horizontalruleui.js @@ -8,9 +8,35 @@ */ import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; +import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview'; +import horizontalRuleIcon from '../theme/icons/horizontalrule.svg'; /** * @extends module:core/plugin~Plugin */ export default class HorizontalRuleUI extends Plugin { + init() { + const editor = this.editor; + const t = editor.t; + + // Add horizontalRule button to feature components. + editor.ui.componentFactory.add( 'horizontalRule', locale => { + const command = editor.commands.get( 'horizontalRule' ); + const view = new ButtonView( locale ); + + view.set( { + label: t( 'Horizontal rule' ), + icon: horizontalRuleIcon, + tooltip: true, + isToggleable: true + } ); + + view.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' ); + + // Execute command. + this.listenTo( view, 'execute', () => editor.execute( 'horizontalRule' ) ); + + return view; + } ); + } } diff --git a/tests/manual/horizontalrule.js b/tests/manual/horizontalrule.js index 96d5a28..656c6a2 100644 --- a/tests/manual/horizontalrule.js +++ b/tests/manual/horizontalrule.js @@ -13,7 +13,7 @@ ClassicEditor .create( document.querySelector( '#editor' ), { plugins: [ ArticlePluginSet, HorizontalRule ], toolbar: [ - 'heading', 'bold', 'italic', 'bulletedList', 'numberedList', 'blockQuote', 'link', 'undo', 'redo' + 'heading', 'bold', 'italic', 'bulletedList', 'numberedList', 'blockQuote', 'link', 'undo', 'redo', 'horizontalRule' ] } ) .then( editor => { diff --git a/theme/icons/horizontalrule.svg b/theme/icons/horizontalrule.svg new file mode 100644 index 0000000..4cf547d --- /dev/null +++ b/theme/icons/horizontalrule.svg @@ -0,0 +1 @@ + \ No newline at end of file From 38bcb2fd8a8f954d0f812b1edcabde8faf249b4d Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Thu, 29 Aug 2019 10:18:49 +0200 Subject: [PATCH 05/24] Support for "HorizontalRuleCommand#isEnabled". --- src/horizontalrulecommand.js | 3 +- src/horizontalruleediting.js | 7 +-- src/utils.js | 86 ++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 6 deletions(-) create mode 100644 src/utils.js diff --git a/src/horizontalrulecommand.js b/src/horizontalrulecommand.js index 5b7d13c..d386f4e 100644 --- a/src/horizontalrulecommand.js +++ b/src/horizontalrulecommand.js @@ -9,13 +9,14 @@ import Command from '@ckeditor/ckeditor5-core/src/command'; import { findOptimalInsertionPosition } from '@ckeditor/ckeditor5-widget/src/utils'; +import { isHorizontalRuleAllowed } from './utils'; export default class HorizontalRuleCommand extends Command { /** * @inheritDoc */ refresh() { - this.isEnabled = true; + this.isEnabled = isHorizontalRuleAllowed( this.editor.model ); } /** diff --git a/src/horizontalruleediting.js b/src/horizontalruleediting.js index 5dfe19b..cde4037 100644 --- a/src/horizontalruleediting.js +++ b/src/horizontalruleediting.js @@ -8,8 +8,8 @@ */ import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; -import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; import HorizontalRuleCommand from './horizontalrulecommand'; +import { toHorizontalRuleWidget } from './utils'; import '../theme/horizontalrule.css'; @@ -48,10 +48,7 @@ export default class HorizontalRuleEditing extends Plugin { viewWriter.addClass( 'ck-horizontal-rule', viewElement ); viewWriter.setCustomProperty( 'hr', true, viewElement ); - return toWidget( viewElement, viewWriter, { - label, - hasSelectionHandler: true - } ); + return toHorizontalRuleWidget( viewElement, viewWriter, label ); } } ); diff --git a/src/utils.js b/src/utils.js new file mode 100644 index 0000000..c77d4bb --- /dev/null +++ b/src/utils.js @@ -0,0 +1,86 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/** + * @module horizontal-rule/utils + */ + +import { findOptimalInsertionPosition, isWidget, toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; + +/** + * @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} + */ +export function toHorizontalRuleWidget( viewElement, writer, label ) { + writer.setCustomProperty( 'horizontalRule', true, viewElement ); + + return toWidget( viewElement, writer, { label, hasSelectionHandler: true } ); +} + +/** + * Checks if a given view element is a horizontal rule widget. + * + * @param {module:engine/view/element~Element} viewElement + * @returns {Boolean} + */ +export function isHorizontalRuleWidget( viewElement ) { + return !!viewElement.getCustomProperty( 'horizontalRule' ) && isWidget( viewElement ); +} + +/** + * Checks if the `horizontalRule` element can be inserted at current model selection. + * + * @param {module:engine/model/model~Model} model + * @returns {Boolean} + */ +export function isHorizontalRuleAllowed( model ) { + const schema = model.schema; + const selection = model.document.selection; + + return isHorizontalRuleAllowedInParent( selection, schema, model ) && + !checkSelectionOnObject( selection, schema ); +} + +// Checks if horizontal rule is allowed by schema in 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 isHorizontalRuleAllowedInParent( selection, schema, model ) { + const parent = getInsertHorizontalRuleParent( selection, model ); + + return schema.checkChild( parent, 'horizontalRule' ); +} + +// Check if selection is on object. +// +// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection +// @param {module:engine/model/schema~Schema} schema +// @returns {Boolean} +function checkSelectionOnObject( selection, schema ) { + const selectedElement = selection.getSelectedElement(); + + return selectedElement && schema.isObject( selectedElement ); +} + +// Returns a node that will be used to insert horizontal rule with `model.insertContent` to check if horizontal rule 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 getInsertHorizontalRuleParent( selection, model ) { + const insertAt = findOptimalInsertionPosition( selection, model ); + + const parent = insertAt.parent; + + if ( parent.isEmpty && !parent.is( '$root' ) ) { + return parent.parent; + } + + return parent; +} From 3eeabdbc0a3caa0c0327b14cdad8be49de7bdcf8 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Thu, 29 Aug 2019 10:35:27 +0200 Subject: [PATCH 06/24] Added Webhook URL for notifications. --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index b7d3ea8..ae01c32 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,3 +28,4 @@ after_script: - ckeditor5-dev-tests-notify-travis-status env: global: + secure: p5cZoH4j/z6VehtqZyAC/zSlpg9/L0rGGTojMJGQVE14Rk7RV9biotIp+qjYnh99dZx+Zxa6YkhFgrlVlX6ibdwxqS8PU7YQWm1N8xSbUkO5hfXt2gRkBjW+bZFCadcyRgiE/riwBMEgtTaHMCRFxaN9KXcfzRzJs0mTu/jQQJOpHyrKyZMsb0mNaWZ9yP+wOQjzJ/NOgUE5HwsXoZKtfMMUUqYHZU7m3HFtXdOo3andY19lmR6nthkDWsB8V3duCUn2LhFLT4DDQfvNWL3TLddX6YYRfGzx79uU7hzRTynZxUpTFE56Y0dyoSSkUIsUmdthdz9Je3WCVJNZl3nVsfn/zczP7xqaFSWfAw2vdnDMvneo+nyz+Lelwf7VKpyXosWgUsO5EeMiqrf/qRul6W9beSA5fUeZ6kkKlcdkPrcbbPhnBfBrnhTaOwbEsRXNte8EWZABrm9W7hWSkbXNowamGUwnojheZRziJBUKMgrBbSy+3SDNt6A5z6jgLmtnWaT6Fy0e20S0lYRjaSpns5KA1AWCRp7DkFUI9z1jP0/itCSBKM8QIsLgxRWgCka3DTXChgHD6Tif4d+4SjRkUcMOZ4M+ai586SbS+ki/JBXM42nuvgbdmGB/XbiZYzTGhhHeCeK8BUTgPVHoh9kGDuOjBCRCVdFQiJMB0WQ8bX4= From 63f23b647ebdfba02c4ee9752fa249b753b8c332 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Thu, 29 Aug 2019 12:29:16 +0200 Subject: [PATCH 07/24] Improved the manual test. --- tests/manual/horizontalrule.js | 39 +++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/tests/manual/horizontalrule.js b/tests/manual/horizontalrule.js index 656c6a2..4df2219 100644 --- a/tests/manual/horizontalrule.js +++ b/tests/manual/horizontalrule.js @@ -7,14 +7,47 @@ import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classiceditor'; import ArticlePluginSet from '@ckeditor/ckeditor5-core/tests/_utils/articlepluginset'; +import ImageUpload from '@ckeditor/ckeditor5-image/src/imageupload'; +import EasyImage from '@ckeditor/ckeditor5-easy-image/src/easyimage'; +import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config'; import HorizontalRule from '../../src/horizontalrule'; ClassicEditor .create( document.querySelector( '#editor' ), { - plugins: [ ArticlePluginSet, HorizontalRule ], + cloudServices: CS_CONFIG, + plugins: [ ArticlePluginSet, ImageUpload, EasyImage, HorizontalRule ], toolbar: [ - 'heading', 'bold', 'italic', 'bulletedList', 'numberedList', 'blockQuote', 'link', 'undo', 'redo', 'horizontalRule' - ] + 'heading', + '|', + 'bold', 'italic', 'numberedList', 'bulletedList', + '|', + 'link', 'blockquote', 'imageUpload', 'insertTable', 'mediaEmbed', + '|', + 'undo', 'redo', + '|', + 'horizontalRule' + ], + image: { + styles: [ + 'full', + 'alignLeft', + 'alignRight' + ], + toolbar: [ + 'imageStyle:alignLeft', + 'imageStyle:full', + 'imageStyle:alignRight', + '|', + 'imageTextAlternative' + ] + }, + table: { + contentToolbar: [ + 'tableColumn', + 'tableRow', + 'mergeTableCells' + ] + }, } ) .then( editor => { window.editor = editor; From 1c1816fbccd7630dfdfc82f0cf1ddfe352475c3a Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Thu, 29 Aug 2019 13:04:25 +0200 Subject: [PATCH 08/24] Simplified the code. --- src/horizontalruleediting.js | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/horizontalruleediting.js b/src/horizontalruleediting.js index cde4037..b80149f 100644 --- a/src/horizontalruleediting.js +++ b/src/horizontalruleediting.js @@ -27,7 +27,6 @@ export default class HorizontalRuleEditing extends Plugin { const conversion = editor.conversion; schema.register( 'horizontalRule', { - isBlock: true, isObject: true, allowWhere: '$block' } ); @@ -52,13 +51,7 @@ export default class HorizontalRuleEditing extends Plugin { } } ); - conversion.for( 'upcast' ) - .elementToElement( { - view: 'hr', - model: ( viewElement, modelWriter ) => { - return modelWriter.createElement( 'horizontalRule' ); - } - } ); + conversion.for( 'upcast' ).elementToElement( { view: 'hr', model: 'horizontalRule' } ); editor.commands.add( 'horizontalRule', new HorizontalRuleCommand( editor ) ); } From 1bc930aa1a954eaf28184f2a24bc16bc63971d8e Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Thu, 29 Aug 2019 13:06:54 +0200 Subject: [PATCH 09/24] Added missing dependencies. --- package.json | 3 +++ 1 file changed, 3 insertions(+) diff --git a/package.json b/package.json index 0cfe24d..ce1eb06 100644 --- a/package.json +++ b/package.json @@ -15,7 +15,10 @@ "@ckeditor/ckeditor5-widget": "^11.0.4" }, "devDependencies": { + "@ckeditor/ckeditor5-cloud-services": "^11.0.5", "@ckeditor/ckeditor5-editor-classic": "^12.1.3", + "@ckeditor/ckeditor5-easy-image": "^11.0.5", + "@ckeditor/ckeditor5-image": "^14.0.0", "eslint": "^5.5.0", "eslint-config-ckeditor5": "^2.0.0", "husky": "^1.3.1", From 33871514b6d345443da4ced3cf5fbf6b8df1bd4c Mon Sep 17 00:00:00 2001 From: dkonopka Date: Fri, 30 Aug 2019 10:45:42 +0200 Subject: [PATCH 10/24] Added horizontal rule icon. --- theme/icons/horizontalrule.svg | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/theme/icons/horizontalrule.svg b/theme/icons/horizontalrule.svg index 4cf547d..7326c54 100644 --- a/theme/icons/horizontalrule.svg +++ b/theme/icons/horizontalrule.svg @@ -1 +1 @@ - \ No newline at end of file + From 4806bc06b16316f8790415843ef2e8aae8ce43b9 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Mon, 2 Sep 2019 14:25:33 +0200 Subject: [PATCH 11/24] After inserting a horizontal rule element, selection will be set on the element. --- src/horizontalrulecommand.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/horizontalrulecommand.js b/src/horizontalrulecommand.js index d386f4e..6f535a7 100644 --- a/src/horizontalrulecommand.js +++ b/src/horizontalrulecommand.js @@ -33,6 +33,7 @@ export default class HorizontalRuleCommand extends Command { const insertPosition = findOptimalInsertionPosition( selection, model ); model.insertContent( modelElement, insertPosition ); + writer.setSelection( modelElement, 'on' ); } ); } } From 6abc437a600514ce27e0576bdcee3f7f4c19528c Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Mon, 2 Sep 2019 14:26:13 +0200 Subject: [PATCH 12/24]
element must be inserted in the editing view. --- src/horizontalruleediting.js | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/src/horizontalruleediting.js b/src/horizontalruleediting.js index b80149f..7b3cb1f 100644 --- a/src/horizontalruleediting.js +++ b/src/horizontalruleediting.js @@ -42,12 +42,15 @@ export default class HorizontalRuleEditing extends Plugin { model: 'horizontalRule', view: ( modelElement, viewWriter ) => { const label = t( 'Horizontal rule' ); - const viewElement = viewWriter.createContainerElement( 'div' ); + const viewWrapper = viewWriter.createContainerElement( 'div' ); + const viewHrElement = viewWriter.createEmptyElement( 'hr' ); - viewWriter.addClass( 'ck-horizontal-rule', viewElement ); - viewWriter.setCustomProperty( 'hr', true, viewElement ); + viewWriter.addClass( 'ck-horizontal-rule', viewWrapper ); + viewWriter.setCustomProperty( 'hr', true, viewWrapper ); - return toHorizontalRuleWidget( viewElement, viewWriter, label ); + viewWriter.insert( viewWriter.createPositionAt( viewWrapper, 0 ), viewHrElement ); + + return toHorizontalRuleWidget( viewWrapper, viewWriter, label ); } } ); From f381c09c0536cb1ee6f9599e07dcc4ac942cbf12 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Mon, 2 Sep 2019 14:31:37 +0200 Subject: [PATCH 13/24] Simplified the code. --- src/horizontalruleui.js | 2 +- src/utils.js | 14 ++------------ 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/src/horizontalruleui.js b/src/horizontalruleui.js index 5205561..54e0519 100644 --- a/src/horizontalruleui.js +++ b/src/horizontalruleui.js @@ -31,7 +31,7 @@ export default class HorizontalRuleUI extends Plugin { isToggleable: true } ); - view.bind( 'isOn', 'isEnabled' ).to( command, 'value', 'isEnabled' ); + view.bind( 'isEnabled' ).to( command, 'isEnabled' ); // Execute command. this.listenTo( view, 'execute', () => editor.execute( 'horizontalRule' ) ); diff --git a/src/utils.js b/src/utils.js index c77d4bb..605d763 100644 --- a/src/utils.js +++ b/src/utils.js @@ -7,7 +7,7 @@ * @module horizontal-rule/utils */ -import { findOptimalInsertionPosition, isWidget, toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; +import { findOptimalInsertionPosition, toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; /** * @param {module:engine/view/element~Element} viewElement @@ -18,17 +18,7 @@ import { findOptimalInsertionPosition, isWidget, toWidget } from '@ckeditor/cked export function toHorizontalRuleWidget( viewElement, writer, label ) { writer.setCustomProperty( 'horizontalRule', true, viewElement ); - return toWidget( viewElement, writer, { label, hasSelectionHandler: true } ); -} - -/** - * Checks if a given view element is a horizontal rule widget. - * - * @param {module:engine/view/element~Element} viewElement - * @returns {Boolean} - */ -export function isHorizontalRuleWidget( viewElement ) { - return !!viewElement.getCustomProperty( 'horizontalRule' ) && isWidget( viewElement ); + return toWidget( viewElement, writer, { label } ); } /** From 5c0aecc6d2669347c4e52674a8ce5dc95b09289c Mon Sep 17 00:00:00 2001 From: dkonopka Date: Mon, 2 Sep 2019 15:11:51 +0200 Subject: [PATCH 14/24] Used `.ck-content` for styling horizontal-rule. --- theme/horizontalrule.css | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/theme/horizontalrule.css b/theme/horizontalrule.css index 9342eb4..da81a9f 100644 --- a/theme/horizontalrule.css +++ b/theme/horizontalrule.css @@ -3,10 +3,11 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ -.ck-horizontal-rule { - border: 1px solid var(--ck-color-toolbar-border); - border-radius: 50%; - width: 90%; - margin-left: auto; - margin-right: auto; +.ck-content .ck-horizontal-rule { + padding: 5px; +} + +.ck-content .ck-horizontal-rule hr { + border: 1px solid hsl(0, 0%, 77%); + margin: 0; } From 963e3417a3ca1be6eb93cea8238b27bed09c3d00 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Mon, 2 Sep 2019 15:13:34 +0200 Subject: [PATCH 15/24] Simplified inserting the element. --- src/horizontalrulecommand.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/horizontalrulecommand.js b/src/horizontalrulecommand.js index 6f535a7..67fba0f 100644 --- a/src/horizontalrulecommand.js +++ b/src/horizontalrulecommand.js @@ -26,13 +26,11 @@ export default class HorizontalRuleCommand extends Command { */ execute() { const model = this.editor.model; - const selection = model.document.selection; model.change( writer => { const modelElement = writer.createElement( 'horizontalRule' ); - const insertPosition = findOptimalInsertionPosition( selection, model ); - model.insertContent( modelElement, insertPosition ); + model.insertContent( modelElement ); writer.setSelection( modelElement, 'on' ); } ); } From 0a73ffa5ac4a5763de453b18d8beac7b937ec2cb Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Tue, 3 Sep 2019 08:43:35 +0200 Subject: [PATCH 16/24] Added tests. --- package.json | 1 + src/utils.js | 12 ++- tests/horizontalrule.js | 18 ++++ tests/horizontalrulecommand.js | 154 +++++++++++++++++++++++++++++++++ tests/horizontalruleediting.js | 107 +++++++++++++++++++++++ tests/horizontalruleui.js | 67 ++++++++++++++ 6 files changed, 358 insertions(+), 1 deletion(-) create mode 100644 tests/horizontalrule.js create mode 100644 tests/horizontalrulecommand.js create mode 100644 tests/horizontalruleediting.js create mode 100644 tests/horizontalruleui.js diff --git a/package.json b/package.json index ce1eb06..7bc7396 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "@ckeditor/ckeditor5-editor-classic": "^12.1.3", "@ckeditor/ckeditor5-easy-image": "^11.0.5", "@ckeditor/ckeditor5-image": "^14.0.0", + "@ckeditor/ckeditor5-paragraph": "^11.0.5", "eslint": "^5.5.0", "eslint-config-ckeditor5": "^2.0.0", "husky": "^1.3.1", diff --git a/src/utils.js b/src/utils.js index 605d763..91604d0 100644 --- a/src/utils.js +++ b/src/utils.js @@ -7,7 +7,7 @@ * @module horizontal-rule/utils */ -import { findOptimalInsertionPosition, toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; +import { findOptimalInsertionPosition, isWidget, toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; /** * @param {module:engine/view/element~Element} viewElement @@ -21,6 +21,16 @@ export function toHorizontalRuleWidget( viewElement, writer, label ) { return toWidget( viewElement, writer, { label } ); } +/** + * Checks if a given view element is a horizontal rule widget. + * + * @param {module:engine/view/element~Element} viewElement + * @returns {Boolean} + */ +export function isHorizontalRuleWidget( viewElement ) { + return !!viewElement.getCustomProperty( 'horizontalRule' ) && isWidget( viewElement ); +} + /** * Checks if the `horizontalRule` element can be inserted at current model selection. * diff --git a/tests/horizontalrule.js b/tests/horizontalrule.js new file mode 100644 index 0000000..2af22e3 --- /dev/null +++ b/tests/horizontalrule.js @@ -0,0 +1,18 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +import HorizontalRule from '../src/horizontalrule'; +import HorizontalRuleEditing from '../src/horizontalruleediting'; +import HorizontalRuleUI from '../src/horizontalruleui'; + +describe( 'HorizontalRule', () => { + it( 'should require HorizontalRuleEditing and HorizontalRuleUI', () => { + expect( HorizontalRule.requires ).to.deep.equal( [ HorizontalRuleEditing, HorizontalRuleUI ] ); + } ); + + it( 'should be named', () => { + expect( HorizontalRule.pluginName ).to.equal( 'HorizontalRule' ); + } ); +} ); diff --git a/tests/horizontalrulecommand.js b/tests/horizontalrulecommand.js new file mode 100644 index 0000000..2430834 --- /dev/null +++ b/tests/horizontalrulecommand.js @@ -0,0 +1,154 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/* globals document */ + +import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; +import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; +import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; +import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; +import HorizontalRuleEditing from '../src/horizontalruleediting'; + +describe( 'HorizontalRuleCommand', () => { + let editor, model, editorElement, command; + + testUtils.createSinonSandbox(); + + beforeEach( () => { + editorElement = document.createElement( 'div' ); + document.body.appendChild( editorElement ); + + return ClassicTestEditor + .create( editorElement, { + plugins: [ Paragraph, HorizontalRuleEditing ] + } ) + .then( newEditor => { + editor = newEditor; + model = editor.model; + command = editor.commands.get( 'horizontalRule' ); + } ); + } ); + + afterEach( () => { + return editor.destroy() + .then( () => { + editorElement.remove(); + } ); + } ); + + describe( 'isEnabled', () => { + it( 'should be true when the selection directly in the root', () => { + model.enqueueChange( 'transparent', () => { + setModelData( model, '[]' ); + + command.refresh(); + expect( command.isEnabled ).to.be.true; + } ); + } ); + + it( 'should be true when the selection is in empty block', () => { + setModelData( model, '[]' ); + + expect( command.isEnabled ).to.be.true; + } ); + + it( 'should be true when the selection directly in a paragraph', () => { + setModelData( model, 'foo[]' ); + expect( command.isEnabled ).to.be.true; + } ); + + it( 'should be true when the selection directly in a block', () => { + model.schema.register( 'block', { inheritAllFrom: '$block' } ); + model.schema.extend( '$text', { allowIn: 'block' } ); + editor.conversion.for( 'downcast' ).elementToElement( { model: 'block', view: 'block' } ); + + setModelData( model, 'foo[]' ); + expect( command.isEnabled ).to.be.true; + } ); + + it( 'should be false when the selection is on other horizontal rule element', () => { + setModelData( model, '[]' ); + expect( command.isEnabled ).to.be.false; + } ); + + it( 'should be false when the selection is on other object', () => { + model.schema.register( 'object', { isObject: true, allowIn: '$root' } ); + editor.conversion.for( 'downcast' ).elementToElement( { model: 'object', view: 'object' } ); + setModelData( model, '[]' ); + + expect( command.isEnabled ).to.be.false; + } ); + + it( 'should be true when the selection is inside block element inside isLimit element which allows horizontal rule', () => { + model.schema.register( 'table', { allowWhere: '$block', isLimit: true, isObject: true, isBlock: true } ); + model.schema.register( 'tableRow', { allowIn: 'table', isLimit: true } ); + model.schema.register( 'tableCell', { allowIn: 'tableRow', isLimit: true } ); + model.schema.extend( '$block', { allowIn: 'tableCell' } ); + editor.conversion.for( 'downcast' ).elementToElement( { model: 'table', view: 'table' } ); + editor.conversion.for( 'downcast' ).elementToElement( { model: 'tableRow', view: 'tableRow' } ); + editor.conversion.for( 'downcast' ).elementToElement( { model: 'tableCell', view: 'tableCell' } ); + + setModelData( model, 'foo[]
' ); + } ); + + it( 'should be false when schema disallows horizontal rule', () => { + model.schema.register( 'block', { inheritAllFrom: '$block' } ); + model.schema.extend( 'paragraph', { allowIn: 'block' } ); + // Block horizontal rule in block. + model.schema.addChildCheck( ( context, childDefinition ) => { + if ( childDefinition.name === 'horizontalRule' && context.last.name === 'block' ) { + return false; + } + } ); + editor.conversion.for( 'downcast' ).elementToElement( { model: 'block', view: 'block' } ); + + setModelData( model, '[]' ); + + expect( command.isEnabled ).to.be.false; + } ); + } ); + + describe( 'execute()', () => { + it( 'should create a single batch', () => { + setModelData( model, 'foo[]' ); + + const spy = sinon.spy(); + + model.document.on( 'change', spy ); + + command.execute(); + + sinon.assert.calledOnce( spy ); + } ); + + it( 'should insert a horizontal rule in an empty root and select it', () => { + setModelData( model, '[]' ); + + command.execute(); + + expect( getModelData( model ) ).to.equal( '[]' ); + } ); + + it( 'should split an element where selection is placed and insert a horizontal rule (non-collapsed selection)', () => { + setModelData( model, 'f[o]o' ); + + command.execute(); + + expect( getModelData( model ) ).to.equal( + 'f[]o' + ); + } ); + + it( 'should split an element where selection is placed and insert a horizontal rule (collapsed selection)', () => { + setModelData( model, 'fo[]o' ); + + command.execute(); + + expect( getModelData( model ) ).to.equal( + 'fo[]o' + ); + } ); + } ); +} ); diff --git a/tests/horizontalruleediting.js b/tests/horizontalruleediting.js new file mode 100644 index 0000000..a8ac84b --- /dev/null +++ b/tests/horizontalruleediting.js @@ -0,0 +1,107 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor'; +import HorizontalRuleEditing from '../src/horizontalruleediting'; +import HorizontalRuleCommand from '../src/horizontalrulecommand'; +import { isHorizontalRuleWidget } from '../src/utils'; +import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; +import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view'; +import env from '@ckeditor/ckeditor5-utils/src/env'; +import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; + +describe( 'HorizontalRuleEditing', () => { + let editor, model, view, viewDocument; + + testUtils.createSinonSandbox(); + + beforeEach( () => { + // Most tests assume non-edge environment but we do not set `contenteditable=false` on Edge so stub `env.isEdge`. + testUtils.sinon.stub( env, 'isEdge' ).get( () => false ); + + return VirtualTestEditor + .create( { + plugins: [ HorizontalRuleEditing ] + } ) + .then( newEditor => { + editor = newEditor; + model = editor.model; + view = editor.editing.view; + viewDocument = view.document; + } ); + } ); + + it( 'should be loaded', () => { + expect( editor.plugins.get( HorizontalRuleEditing ) ).to.be.instanceOf( HorizontalRuleEditing ); + } ); + + it( 'should set proper schema rules', () => { + expect( model.schema.checkChild( [ '$root' ], 'horizontalRule' ) ).to.be.true; + + expect( model.schema.isObject( 'horizontalRule' ) ).to.be.true; + + expect( model.schema.checkChild( [ '$root', 'horizontalRule' ], '$text' ) ).to.be.false; + expect( model.schema.checkChild( [ '$root', '$block' ], 'horizontalRule' ) ).to.be.false; + } ); + + it( 'should register imageInsert command', () => { + expect( editor.commands.get( 'horizontalRule' ) ).to.be.instanceOf( HorizontalRuleCommand ); + } ); + + describe( 'conversion in data pipeline', () => { + describe( 'model to view', () => { + it( 'should convert', () => { + setModelData( model, '' ); + + expect( editor.getData() ).to.equal( '
' ); + } ); + } ); + + describe( 'view to model', () => { + it( 'should convert the
element', () => { + editor.setData( '
' ); + + expect( getModelData( model, { withoutSelection: true } ) ) + .to.equal( '' ); + } ); + + it( 'should not convert in wrong context', () => { + model.schema.register( 'div', { inheritAllFrom: '$block' } ); + model.schema.addChildCheck( ( ctx, childDef ) => { + if ( ctx.endsWith( '$root' ) && childDef.name == 'horizontalRule' ) { + return false; + } + } ); + + editor.conversion.elementToElement( { model: 'div', view: 'div' } ); + + editor.setData( '

' ); + + expect( getModelData( model, { withoutSelection: true } ) ) + .to.equal( '
' ); + } ); + } ); + } ); + + describe( 'conversion in editing pipeline', () => { + describe( 'model to view', () => { + it( 'should convert', () => { + setModelData( model, '' ); + + expect( getViewData( view, { withoutSelection: true } ) ).to.equal( + '

' + ); + } ); + + it( 'converted element should be widgetized', () => { + setModelData( model, '' ); + const widget = viewDocument.getRoot().getChild( 0 ); + + expect( widget.name ).to.equal( 'div' ); + expect( isHorizontalRuleWidget( widget ) ).to.be.true; + } ); + } ); + } ); +} ); diff --git a/tests/horizontalruleui.js b/tests/horizontalruleui.js new file mode 100644 index 0000000..201a911 --- /dev/null +++ b/tests/horizontalruleui.js @@ -0,0 +1,67 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/* globals document */ + +import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; +import HorizontalRuleEditing from '../src/horizontalruleediting'; +import HorizontalRuleUI from '../src/horizontalruleui'; +import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview'; +import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; + +import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; + +describe( 'HorizontalRuleUI', () => { + let editor, editorElement, horizontalRuleView; + + testUtils.createSinonSandbox(); + + beforeEach( () => { + editorElement = document.createElement( 'div' ); + document.body.appendChild( editorElement ); + + return ClassicTestEditor + .create( editorElement, { + plugins: [ Paragraph, HorizontalRuleEditing, HorizontalRuleUI ] + } ) + .then( newEditor => { + editor = newEditor; + + horizontalRuleView = editor.ui.componentFactory.create( 'horizontalRule' ); + } ); + } ); + + afterEach( () => { + return editor.destroy() + .then( () => { + editorElement.remove(); + } ); + } ); + + it( 'should register horizontalRule feature component', () => { + expect( horizontalRuleView ).to.be.instanceOf( ButtonView ); + expect( horizontalRuleView.label ).to.equal( 'Horizontal rule' ); + expect( horizontalRuleView.icon ).to.match( / { + const executeSpy = testUtils.sinon.spy( editor, 'execute' ); + + horizontalRuleView.fire( 'execute' ); + + sinon.assert.calledOnce( executeSpy ); + sinon.assert.calledWithExactly( executeSpy, 'horizontalRule' ); + } ); + + it( 'should bind model to horizontalRule command', () => { + const command = editor.commands.get( 'horizontalRule' ); + + expect( horizontalRuleView.isEnabled ).to.be.true; + + command.isEnabled = false; + expect( horizontalRuleView.isEnabled ).to.be.false; + } ); +} ); From 27e1f424172a1909eb4023330d82722d4200ae15 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Tue, 3 Sep 2019 10:11:34 +0200 Subject: [PATCH 17/24] Improved the documentation of the plugin. --- docs/_snippets/features/horizontal-rule.html | 6 +++ docs/_snippets/features/horizontal-rule.js | 45 ++++++++++++++++++++ docs/api/horizontal-rule.md | 34 +++++++++++++++ docs/features/horizontal-rule.md | 43 +++++++++++++++++++ src/horizontalrule.js | 3 +- src/horizontalrulecommand.js | 12 +++++- src/horizontalruleediting.js | 2 + src/horizontalruleui.js | 2 + src/utils.js | 5 +++ 9 files changed, 149 insertions(+), 3 deletions(-) create mode 100644 docs/_snippets/features/horizontal-rule.html create mode 100644 docs/_snippets/features/horizontal-rule.js create mode 100644 docs/api/horizontal-rule.md create mode 100644 docs/features/horizontal-rule.md diff --git a/docs/_snippets/features/horizontal-rule.html b/docs/_snippets/features/horizontal-rule.html new file mode 100644 index 0000000..7fd6fd1 --- /dev/null +++ b/docs/_snippets/features/horizontal-rule.html @@ -0,0 +1,6 @@ +
+

What is Lorem Ipsum?

+

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.

+
+

It has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. It was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum.

+
diff --git a/docs/_snippets/features/horizontal-rule.js b/docs/_snippets/features/horizontal-rule.js new file mode 100644 index 0000000..1b64d50 --- /dev/null +++ b/docs/_snippets/features/horizontal-rule.js @@ -0,0 +1,45 @@ +/** + * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license + */ + +/* globals window, document, console */ + +import ClassicEditor from '@ckeditor/ckeditor5-build-classic/src/ckeditor'; +import HorizontalRule from '@ckeditor/ckeditor5-horizontal-rule/src/horizontalrule'; + +ClassicEditor.builtinPlugins.push( HorizontalRule ); + +ClassicEditor + .create( document.querySelector( '#demo-editor' ), { + toolbar: { + items: [ + 'heading', + '|', + 'bold', + 'italic', + 'bulletedList', + 'numberedList', + 'blockQuote', + 'link', + '|', + 'mediaEmbed', + 'insertTable', + '|', + 'undo', + 'redo', + '|', + 'horizontalRule' + ], + viewportTopOffset: window.getViewportTopOffsetConfig() + }, + table: { + contentToolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells' ] + } + } ) + .then( editor => { + window.editor = editor; + } ) + .catch( err => { + console.error( err.stack ); + } ); diff --git a/docs/api/horizontal-rule.md b/docs/api/horizontal-rule.md new file mode 100644 index 0000000..12df344 --- /dev/null +++ b/docs/api/horizontal-rule.md @@ -0,0 +1,34 @@ +--- +category: api-reference +--- + +# Horizontal rule feature for CKEditor 5 + +[![npm version](https://badge.fury.io/js/%40ckeditor%2Fckeditor5-horizontal-rule.svg)](https://www.npmjs.com/package/@ckeditor/ckeditor5-horizontal-rule) + +This package implements the horizontal rule feature for CKEditor 5. + +## Demo + +Check out the {@link features/horizontal-rule#demo demo in the Horizontal rule feature} guide. + +## Documentation + +See the {@link features/horizontal-rule Horizontal rule feature} guide and the {@link module:horizontal-rule/horizontalrule~HorizontalRule} plugin documentation. + +## Installation + +```bash +npm install --save @ckeditor/ckeditor5-horizontal-rule +``` + +## Contribute + +The source code of this package is available on GitHub in https://github.com/ckeditor/ckeditor5-horizontal-rule. + +## External links + +* [`@ckeditor/ckeditor5-horizontal-rule` on npm](https://www.npmjs.com/package/@ckeditor/ckeditor5-horizontal-rule) +* [`ckeditor/ckeditor5-horizontal-rule` on GitHub](https://github.com/ckeditor/ckeditor5-horizontal-rule) +* [Issue tracker](https://github.com/ckeditor/ckeditor5/issues) +* [Changelog](https://github.com/ckeditor/ckeditor5-horizontal-rule/blob/master/CHANGELOG.md) diff --git a/docs/features/horizontal-rule.md b/docs/features/horizontal-rule.md new file mode 100644 index 0000000..05b0ad2 --- /dev/null +++ b/docs/features/horizontal-rule.md @@ -0,0 +1,43 @@ +--- +category: features +menu-title: Horizontal rule +--- + +# Horizontal rule + +The {@link module:horizontal-rule/horizontalrule~HorizontalRule} plugin provides a possibility to insert a horizontal rule in the rich-text editor. + +## Demo + +Use the editor below to see the {@link module:horizontal-rule/horizontalrule~HorizontalRule} plugin in action. + +{@snippet features/horizontal-rule} + +## Installation + +To add this feature to your rich-text editor, install the [`@ckeditor/ckeditor5-horizontal-rule`](https://www.npmjs.com/package/@ckeditor/ckeditor5-horizontal-rule) package: + +```bash +npm install --save @ckeditor/ckeditor5-horizontal-rule +``` + +And add it to your plugin list configuration: + +```js +import HorizontalRule from '@ckeditor/ckeditor5-horizontal-rule/src/horizontalrule'; + +ClassicEditor + .create( document.querySelector( '#editor' ), { + plugins: [ HorizontalRule, ... ], + } ) + .then( ... ) + .catch( ... ); +``` + + + Read more about {@link builds/guides/integration/installing-plugins installing plugins}. + + +## Contribute + +The source code of the feature is available on GitHub in https://github.com/ckeditor/ckeditor5-horizontal-rule. diff --git a/src/horizontalrule.js b/src/horizontalrule.js index 9ba1bce..4dff2dd 100644 --- a/src/horizontalrule.js +++ b/src/horizontalrule.js @@ -12,8 +12,7 @@ import HorizontalRuleEditing from './horizontalruleediting'; import HorizontalRuleUI from './horizontalruleui'; /** - * The horizontal rule plugin. - * + * The horizontal rule plugin provides a possibility to insert a horizontal rule in the rich-text editor. * * @extends module:core/plugin~Plugin */ diff --git a/src/horizontalrulecommand.js b/src/horizontalrulecommand.js index 67fba0f..f34fd18 100644 --- a/src/horizontalrulecommand.js +++ b/src/horizontalrulecommand.js @@ -8,9 +8,19 @@ */ import Command from '@ckeditor/ckeditor5-core/src/command'; -import { findOptimalInsertionPosition } from '@ckeditor/ckeditor5-widget/src/utils'; import { isHorizontalRuleAllowed } from './utils'; +/** + * The insert a horizontal rule command. + * + * The command is registered by the {@link module:horizontal-rule/horizontalruleediting~HorizontalRuleEditing} as `'horizontalRule'`. + * + * To insert the horizuntal rule at the current selection, execute the command: + * + * editor.execute( 'horizontalRule' ); + * + * @extends module:core/command~Command + */ export default class HorizontalRuleCommand extends Command { /** * @inheritDoc diff --git a/src/horizontalruleediting.js b/src/horizontalruleediting.js index 7b3cb1f..bf3af8e 100644 --- a/src/horizontalruleediting.js +++ b/src/horizontalruleediting.js @@ -14,6 +14,8 @@ import { toHorizontalRuleWidget } from './utils'; import '../theme/horizontalrule.css'; /** + * The horizontal rule editing feature. + * * @extends module:core/plugin~Plugin */ export default class HorizontalRuleEditing extends Plugin { diff --git a/src/horizontalruleui.js b/src/horizontalruleui.js index 54e0519..39d0064 100644 --- a/src/horizontalruleui.js +++ b/src/horizontalruleui.js @@ -12,6 +12,8 @@ import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview'; import horizontalRuleIcon from '../theme/icons/horizontalrule.svg'; /** + * The horizontal rule UI plugin. + * * @extends module:core/plugin~Plugin */ export default class HorizontalRuleUI extends Plugin { diff --git a/src/utils.js b/src/utils.js index 91604d0..2ed7a6b 100644 --- a/src/utils.js +++ b/src/utils.js @@ -10,6 +10,11 @@ import { findOptimalInsertionPosition, isWidget, toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; /** + * Converts a given {@link module:engine/view/element~Element} to a horizontal rule widget: + * * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to + * recognize the horizontal rule 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. From 98531ea6ebdf215fa2d1eae19652b5ad46214219 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Tue, 3 Sep 2019 10:15:16 +0200 Subject: [PATCH 18/24] Added the "imageUpload" button to the toolbar. --- docs/_snippets/features/horizontal-rule.js | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/docs/_snippets/features/horizontal-rule.js b/docs/_snippets/features/horizontal-rule.js index 1b64d50..ccfe7c5 100644 --- a/docs/_snippets/features/horizontal-rule.js +++ b/docs/_snippets/features/horizontal-rule.js @@ -7,6 +7,7 @@ import ClassicEditor from '@ckeditor/ckeditor5-build-classic/src/ckeditor'; import HorizontalRule from '@ckeditor/ckeditor5-horizontal-rule/src/horizontalrule'; +import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud-services-config'; ClassicEditor.builtinPlugins.push( HorizontalRule ); @@ -23,6 +24,7 @@ ClassicEditor 'blockQuote', 'link', '|', + 'imageUpload', 'mediaEmbed', 'insertTable', '|', @@ -33,9 +35,24 @@ ClassicEditor ], viewportTopOffset: window.getViewportTopOffsetConfig() }, + image: { + styles: [ + 'full', + 'alignLeft', + 'alignRight' + ], + toolbar: [ + 'imageStyle:alignLeft', + 'imageStyle:full', + 'imageStyle:alignRight', + '|', + 'imageTextAlternative' + ] + }, table: { contentToolbar: [ 'tableColumn', 'tableRow', 'mergeTableCells' ] - } + }, + cloudServices: CS_CONFIG } ) .then( editor => { window.editor = editor; From cf30a20d4cd34ab1a81b31ac4298d1e89659659a Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Tue, 3 Sep 2019 14:42:47 +0200 Subject: [PATCH 19/24] Changed a position of "horizontalRule" button in the toolbar. --- docs/_snippets/features/horizontal-rule.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/docs/_snippets/features/horizontal-rule.js b/docs/_snippets/features/horizontal-rule.js index ccfe7c5..fa0cd99 100644 --- a/docs/_snippets/features/horizontal-rule.js +++ b/docs/_snippets/features/horizontal-rule.js @@ -27,11 +27,10 @@ ClassicEditor 'imageUpload', 'mediaEmbed', 'insertTable', + 'horizontalRule', '|', 'undo', 'redo', - '|', - 'horizontalRule' ], viewportTopOffset: window.getViewportTopOffsetConfig() }, From 5ba4f8f7bd69b2d3c579f0bb1467113902a9e18f Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Tue, 3 Sep 2019 14:43:05 +0200 Subject: [PATCH 20/24] Changed ID of the snippet element. --- docs/_snippets/features/horizontal-rule.html | 2 +- docs/_snippets/features/horizontal-rule.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/_snippets/features/horizontal-rule.html b/docs/_snippets/features/horizontal-rule.html index 7fd6fd1..7f7b4e2 100644 --- a/docs/_snippets/features/horizontal-rule.html +++ b/docs/_snippets/features/horizontal-rule.html @@ -1,4 +1,4 @@ -
+

What is Lorem Ipsum?

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry’s standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book.


diff --git a/docs/_snippets/features/horizontal-rule.js b/docs/_snippets/features/horizontal-rule.js index fa0cd99..3e53759 100644 --- a/docs/_snippets/features/horizontal-rule.js +++ b/docs/_snippets/features/horizontal-rule.js @@ -12,7 +12,7 @@ import { CS_CONFIG } from '@ckeditor/ckeditor5-cloud-services/tests/_utils/cloud ClassicEditor.builtinPlugins.push( HorizontalRule ); ClassicEditor - .create( document.querySelector( '#demo-editor' ), { + .create( document.querySelector( '#snippet-horizontal-rule' ), { toolbar: { items: [ 'heading', From c973472350d40727d67bf663f8f947ce60da365e Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Tue, 3 Sep 2019 14:43:29 +0200 Subject: [PATCH 21/24] Simplified the implementation. Removed the "utils" file. --- src/horizontalrulecommand.js | 57 +++++++++++++++++++-- src/horizontalruleediting.js | 17 ++++++- src/utils.js | 91 ---------------------------------- tests/horizontalruleediting.js | 6 ++- 4 files changed, 75 insertions(+), 96 deletions(-) delete mode 100644 src/utils.js diff --git a/src/horizontalrulecommand.js b/src/horizontalrulecommand.js index f34fd18..68876b0 100644 --- a/src/horizontalrulecommand.js +++ b/src/horizontalrulecommand.js @@ -8,14 +8,14 @@ */ import Command from '@ckeditor/ckeditor5-core/src/command'; -import { isHorizontalRuleAllowed } from './utils'; +import { findOptimalInsertionPosition } from '@ckeditor/ckeditor5-widget/src/utils'; /** * The insert a horizontal rule command. * * The command is registered by the {@link module:horizontal-rule/horizontalruleediting~HorizontalRuleEditing} as `'horizontalRule'`. * - * To insert the horizuntal rule at the current selection, execute the command: + * To insert the horizontal rule at the current selection, execute the command: * * editor.execute( 'horizontalRule' ); * @@ -41,7 +41,58 @@ export default class HorizontalRuleCommand extends Command { const modelElement = writer.createElement( 'horizontalRule' ); model.insertContent( modelElement ); - writer.setSelection( modelElement, 'on' ); } ); } } + +// Checks if the `horizontalRule` element can be inserted at current model selection. +// +// @param {module:engine/model/model~Model} model +// @returns {Boolean} +function isHorizontalRuleAllowed( model ) { + const schema = model.schema; + const selection = model.document.selection; + + return isHorizontalRuleAllowedInParent( selection, schema, model ) && + !checkSelectionOnObject( selection, schema ); +} + +// Checks if horizontal rule is allowed by schema in 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 isHorizontalRuleAllowedInParent( selection, schema, model ) { + const parent = getInsertHorizontalRuleParent( selection, model ); + + return schema.checkChild( parent, 'horizontalRule' ); +} + +// Check if selection is on object. +// +// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection +// @param {module:engine/model/schema~Schema} schema +// @returns {Boolean} +function checkSelectionOnObject( selection, schema ) { + const selectedElement = selection.getSelectedElement(); + + return selectedElement && schema.isObject( selectedElement ); +} + +// Returns a node that will be used to insert horizontal rule with `model.insertContent` to check if horizontal rule 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 getInsertHorizontalRuleParent( selection, model ) { + const insertAt = findOptimalInsertionPosition( selection, model ); + + const parent = insertAt.parent; + + if ( parent.isEmpty && !parent.is( '$root' ) ) { + return parent.parent; + } + + return parent; +} diff --git a/src/horizontalruleediting.js b/src/horizontalruleediting.js index bf3af8e..7b143b8 100644 --- a/src/horizontalruleediting.js +++ b/src/horizontalruleediting.js @@ -9,7 +9,7 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; import HorizontalRuleCommand from './horizontalrulecommand'; -import { toHorizontalRuleWidget } from './utils'; +import { toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; import '../theme/horizontalrule.css'; @@ -61,3 +61,18 @@ export default class HorizontalRuleEditing extends Plugin { editor.commands.add( 'horizontalRule', new HorizontalRuleCommand( editor ) ); } } + +// Converts a given {@link module:engine/view/element~Element} to a horizontal rule widget: +// * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to +// recognize the horizontal rule 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 toHorizontalRuleWidget( viewElement, writer, label ) { + writer.setCustomProperty( 'horizontalRule', true, viewElement ); + + return toWidget( viewElement, writer, { label } ); +} diff --git a/src/utils.js b/src/utils.js deleted file mode 100644 index 2ed7a6b..0000000 --- a/src/utils.js +++ /dev/null @@ -1,91 +0,0 @@ -/** - * @license Copyright (c) 2003-2019, CKSource - Frederico Knabben. All rights reserved. - * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license - */ - -/** - * @module horizontal-rule/utils - */ - -import { findOptimalInsertionPosition, isWidget, toWidget } from '@ckeditor/ckeditor5-widget/src/utils'; - -/** - * Converts a given {@link module:engine/view/element~Element} to a horizontal rule widget: - * * Adds a {@link module:engine/view/element~Element#_setCustomProperty custom property} allowing to - * recognize the horizontal rule 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} - */ -export function toHorizontalRuleWidget( viewElement, writer, label ) { - writer.setCustomProperty( 'horizontalRule', true, viewElement ); - - return toWidget( viewElement, writer, { label } ); -} - -/** - * Checks if a given view element is a horizontal rule widget. - * - * @param {module:engine/view/element~Element} viewElement - * @returns {Boolean} - */ -export function isHorizontalRuleWidget( viewElement ) { - return !!viewElement.getCustomProperty( 'horizontalRule' ) && isWidget( viewElement ); -} - -/** - * Checks if the `horizontalRule` element can be inserted at current model selection. - * - * @param {module:engine/model/model~Model} model - * @returns {Boolean} - */ -export function isHorizontalRuleAllowed( model ) { - const schema = model.schema; - const selection = model.document.selection; - - return isHorizontalRuleAllowedInParent( selection, schema, model ) && - !checkSelectionOnObject( selection, schema ); -} - -// Checks if horizontal rule is allowed by schema in 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 isHorizontalRuleAllowedInParent( selection, schema, model ) { - const parent = getInsertHorizontalRuleParent( selection, model ); - - return schema.checkChild( parent, 'horizontalRule' ); -} - -// Check if selection is on object. -// -// @param {module:engine/model/selection~Selection|module:engine/model/documentselection~DocumentSelection} selection -// @param {module:engine/model/schema~Schema} schema -// @returns {Boolean} -function checkSelectionOnObject( selection, schema ) { - const selectedElement = selection.getSelectedElement(); - - return selectedElement && schema.isObject( selectedElement ); -} - -// Returns a node that will be used to insert horizontal rule with `model.insertContent` to check if horizontal rule 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 getInsertHorizontalRuleParent( selection, model ) { - const insertAt = findOptimalInsertionPosition( selection, model ); - - const parent = insertAt.parent; - - if ( parent.isEmpty && !parent.is( '$root' ) ) { - return parent.parent; - } - - return parent; -} diff --git a/tests/horizontalruleediting.js b/tests/horizontalruleediting.js index a8ac84b..6881af1 100644 --- a/tests/horizontalruleediting.js +++ b/tests/horizontalruleediting.js @@ -6,9 +6,9 @@ import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor'; import HorizontalRuleEditing from '../src/horizontalruleediting'; import HorizontalRuleCommand from '../src/horizontalrulecommand'; -import { isHorizontalRuleWidget } from '../src/utils'; import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view'; +import { isWidget } from '@ckeditor/ckeditor5-widget/src/utils'; import env from '@ckeditor/ckeditor5-utils/src/env'; import testUtils from '@ckeditor/ckeditor5-core/tests/_utils/utils'; @@ -104,4 +104,8 @@ describe( 'HorizontalRuleEditing', () => { } ); } ); } ); + + function isHorizontalRuleWidget( viewElement ) { + return !!viewElement.getCustomProperty( 'horizontalRule' ) && isWidget( viewElement ); + } } ); From 474f3bd346aedc9adaf63425769412b5e0b59c0c Mon Sep 17 00:00:00 2001 From: Damian Konopka Date: Tue, 3 Sep 2019 11:42:34 +0200 Subject: [PATCH 22/24] Handle proper hr display next to elements with float property. --- theme/horizontalrule.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/theme/horizontalrule.css b/theme/horizontalrule.css index da81a9f..48a736c 100644 --- a/theme/horizontalrule.css +++ b/theme/horizontalrule.css @@ -4,6 +4,9 @@ */ .ck-content .ck-horizontal-rule { + /* Handle proper `
` display next to elements with `float` property, e.g. side image case. */ + overflow: hidden; + padding: 5px; } From 4b04d154b43949d41c37d2c6a4eeec0fdd0d301e Mon Sep 17 00:00:00 2001 From: Damian Konopka Date: Thu, 5 Sep 2019 09:23:41 +0200 Subject: [PATCH 23/24] Use `.ck-content` styles for the
element`. --- theme/horizontalrule.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/theme/horizontalrule.css b/theme/horizontalrule.css index 48a736c..abd9d48 100644 --- a/theme/horizontalrule.css +++ b/theme/horizontalrule.css @@ -3,14 +3,14 @@ * For licensing, see LICENSE.md or https://ckeditor.com/legal/ckeditor-oss-license */ -.ck-content .ck-horizontal-rule { +.ck .ck-horizontal-rule { /* Handle proper `
` display next to elements with `float` property, e.g. side image case. */ overflow: hidden; padding: 5px; } -.ck-content .ck-horizontal-rule hr { +.ck-content hr { border: 1px solid hsl(0, 0%, 77%); margin: 0; } From 5878495c3c40536fc5df1fd4f9384bc186b8f5d0 Mon Sep 17 00:00:00 2001 From: Kamil Piechaczek Date: Thu, 5 Sep 2019 11:56:50 +0200 Subject: [PATCH 24/24] Improved docs. --- docs/features/horizontal-rule.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/docs/features/horizontal-rule.md b/docs/features/horizontal-rule.md index 05b0ad2..48672ef 100644 --- a/docs/features/horizontal-rule.md +++ b/docs/features/horizontal-rule.md @@ -29,6 +29,7 @@ import HorizontalRule from '@ckeditor/ckeditor5-horizontal-rule/src/horizontalru ClassicEditor .create( document.querySelector( '#editor' ), { plugins: [ HorizontalRule, ... ], + toolbar: [ 'horizontalRule', ... ], } ) .then( ... ) .catch( ... ); @@ -38,6 +39,17 @@ ClassicEditor Read more about {@link builds/guides/integration/installing-plugins installing plugins}. +## Common API + +The {@link module:horizontal-rule/horizontalrule~HorizontalRule} plugin registers the UI button component (`'horizontalRule'`) and the `'horizontalRule'` command implemented by {@link module:horizontal-rule/horizontalrulecommand~HorizontalRuleCommand}. + +The command can be executed using the {@link module:core/editor/editor~Editor#execute `editor.execute()`} method: + +```js +// Inserts the horizontal rule to the selected content. +editor.execute( 'horizontalRule' ); +``` + ## Contribute The source code of the feature is available on GitHub in https://github.com/ckeditor/ckeditor5-horizontal-rule.