From 7e095b43d3f50794b7b4c5c00db46d76e6a7a73b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Mon, 6 Nov 2017 14:32:27 +0100 Subject: [PATCH 01/20] Other: Bootstrap highlight feature classes. --- package.json | 4 ++ src/highlight.js | 36 ++++++++++++++++ src/highlightcommand.js | 91 +++++++++++++++++++++++++++++++++++++++ src/highlightediting.js | 26 +++++++++++ src/highlightui.js | 40 +++++++++++++++++ tests/highlight.js | 39 +++++++++++++++++ tests/highlightcommand.js | 67 ++++++++++++++++++++++++++++ tests/highlightediting.js | 91 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 394 insertions(+) create mode 100644 src/highlight.js create mode 100644 src/highlightcommand.js create mode 100644 src/highlightediting.js create mode 100644 src/highlightui.js create mode 100644 tests/highlight.js create mode 100644 tests/highlightcommand.js create mode 100644 tests/highlightediting.js diff --git a/package.json b/package.json index 5e47d2b..8dc1719 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,12 @@ "ckeditor5-feature" ], "dependencies": { + "@ckeditor/ckeditor5-core": "^1.0.0-alpha.1", + "@ckeditor/ckeditor5-engine": "^1.0.0-alpha.1", + "@ckeditor/ckeditor5-ui": "^1.0.0-alpha.1" }, "devDependencies": { + "@ckeditor/ckeditor5-paragraph": "^1.0.0-alpha.1", "eslint": "^4.8.0", "eslint-config-ckeditor5": "^1.0.6", "husky": "^0.14.3", diff --git a/src/highlight.js b/src/highlight.js new file mode 100644 index 0000000..c1ddaf6 --- /dev/null +++ b/src/highlight.js @@ -0,0 +1,36 @@ +/** + * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ + +/** + * @module highlight/highlight + */ + +import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; + +import HighlightEditing from './highlightediting'; +import HighlightUI from './highlightui'; + +/** + * The highlight plugin. + * + * It requires {@link module:highlight/highlightediting~HighlightEditing} and {@link module:highlight/highlightui~HighlightUI} plugins. + * + * @extends module:core/plugin~Plugin + */ +export default class Highlight extends Plugin { + /** + * @inheritDoc + */ + static get requires() { + return [ HighlightEditing, HighlightUI ]; + } + + /** + * @inheritDoc + */ + static get pluginName() { + return 'Highlight'; + } +} diff --git a/src/highlightcommand.js b/src/highlightcommand.js new file mode 100644 index 0000000..4b3ef8e --- /dev/null +++ b/src/highlightcommand.js @@ -0,0 +1,91 @@ +/** + * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ + +/** + * @module highlight/highlightcommand + */ + +import Command from '@ckeditor/ckeditor5-core/src/command'; + +/** + * The highlight command. + * + * @extends module:core/command~Command + */ +export default class HighlightCommand extends Command { + /** + * Creates an instance of the command. + * + * @param {module:core/editor/editor~Editor} editor The editor instance. + * @param {'left'|'right'|'center'|'justify'} type Highlight type to be handled by this command. + */ + constructor( editor, type ) { + super( editor ); + + /** + * The type of the list created by the command. + * + * @readonly + * @member {'left'|'right'|'center'|'justify'} + */ + this.type = type; + + /** + * A flag indicating whether the command is active, which means that the selection starts in a block + * that has defined highlight of the same type. + * + * @observable + * @readonly + * @member {Boolean} #value + */ + } + + /** + * @inheritDoc + */ + refresh() { + this.isEnabled = this._checkEnabled(); + this.value = this._getValue(); + } + + /** + * Executes the command. + * + * @protected + * @param {Object} [options] Options for the executed command. + * @param {module:engine/model/batch~Batch} [options.batch] A batch to collect all the change steps. + * A new batch will be created if this option is not set. + */ + execute() { + const editor = this.editor; + const document = editor.document; + + document.enqueueChanges( () => { + // TODO + } ); + } + + /** + * Checks whether the command can be enabled in the current context. + * + * @private + * @param {module:engine/model/element~Element} firstBlock A first block in selection to be checked. + * @returns {Boolean} Whether the command should be enabled. + */ + _checkEnabled() { + return true; + } + + /** + * Checks the command's {@link #value}. + * + * @private + * @param {module:engine/model/element~Element} firstBlock A first block in selection to be checked. + * @returns {Boolean} The current value. + */ + _getValue() { + return true; + } +} diff --git a/src/highlightediting.js b/src/highlightediting.js new file mode 100644 index 0000000..59a623d --- /dev/null +++ b/src/highlightediting.js @@ -0,0 +1,26 @@ +/** + * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ + +/** + * @module highlight/highlightediting + */ + +import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; + +import HighlightCommand from './highlightcommand'; + +/** + * @extends module:core/plugin~Plugin + */ +export default class HighlightEditing extends Plugin { + /** + * @inheritDoc + */ + init() { + const editor = this.editor; + + editor.commands.add( 'highlight', new HighlightCommand( editor ) ); + } +} diff --git a/src/highlightui.js b/src/highlightui.js new file mode 100644 index 0000000..a1bf053 --- /dev/null +++ b/src/highlightui.js @@ -0,0 +1,40 @@ +/** + * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ + +/** + * @module highlight/highlightui + */ + +import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; + +import HighlightEditing from './highlightediting'; + +/** + * The default Highlight UI plugin. + * + * @extends module:core/plugin~Plugin + */ +export default class HighlightUI extends Plugin { + /** + * @inheritDoc + */ + static get requires() { + return [ HighlightEditing ]; + } + + /** + * @inheritDoc + */ + static get pluginName() { + return 'HighlightUI'; + } + + /** + * @inheritDoc + */ + init() { + // TODO + } +} diff --git a/tests/highlight.js b/tests/highlight.js new file mode 100644 index 0000000..1f1daea --- /dev/null +++ b/tests/highlight.js @@ -0,0 +1,39 @@ +/** + * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ + +/* global document */ + +import Highlight from './../src/highlight'; +import HighlightEditing from './../src/highlightediting'; +import HighlightUI from './../src/highlightui'; + +import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; + +describe( 'Highlight', () => { + let editor, element; + + beforeEach( () => { + element = document.createElement( 'div' ); + document.body.appendChild( element ); + + return ClassicTestEditor + .create( element, { + plugins: [ Highlight ] + } ) + .then( newEditor => { + editor = newEditor; + } ); + } ); + + afterEach( () => { + element.remove(); + + return editor.destroy(); + } ); + + it( 'requires HighlightEditing and HighlightUI', () => { + expect( Highlight.requires ).to.deep.equal( [ HighlightEditing, HighlightUI ] ); + } ); +} ); diff --git a/tests/highlightcommand.js b/tests/highlightcommand.js new file mode 100644 index 0000000..5417e42 --- /dev/null +++ b/tests/highlightcommand.js @@ -0,0 +1,67 @@ +/** + * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ + +import HighlightCommand from './../src/highlightcommand'; + +import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; + +import Command from '@ckeditor/ckeditor5-core/src/command'; +import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor'; + +describe( 'HighlightCommand', () => { + let editor, doc, command; + + beforeEach( () => { + return ModelTestEditor.create() + .then( newEditor => { + doc = newEditor.document; + command = new HighlightCommand( newEditor ); + editor = newEditor; + + editor.commands.add( 'highlight', command ); + + doc.schema.registerItem( 'paragraph', '$block' ); + + doc.schema.allow( { name: '$block', inside: '$root', attributes: 'highlight' } ); + } ); + } ); + + afterEach( () => { + editor.destroy(); + } ); + + it( 'is a command', () => { + expect( HighlightCommand.prototype ).to.be.instanceOf( Command ); + expect( command ).to.be.instanceOf( Command ); + } ); + + describe( 'value', () => { + it( 'is true when selection is in block with commend type highlight', () => { + setModelData( doc, '<$text highlight="true">fo[]o' ); + + expect( command ).to.have.property( 'value', true ); + } ); + } ); + + describe( 'isEnabled', () => { + it( 'is true when selection is in a block which can have added highlight', () => { + setModelData( doc, '<$text highlight="true">fo[]o' ); + + expect( command ).to.have.property( 'isEnabled', true ); + } ); + } ); + + describe.skip( 'execute()', () => { + describe( 'applying highlight', () => { + it( 'adds highlight to selected text element', () => { + setModelData( doc, 'f[o]o' ); + + editor.execute( 'highlight' ); + + expect( getModelData( doc ) ).to.equal( 'f<$text highlight="true">[o]o' ); + } ); + } ); + } ); +} ); diff --git a/tests/highlightediting.js b/tests/highlightediting.js new file mode 100644 index 0000000..5a4a167 --- /dev/null +++ b/tests/highlightediting.js @@ -0,0 +1,91 @@ +/** + * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ + +import HighlightEditing from './../src/highlightediting'; +import HighlightCommand from './../src/highlightcommand'; + +import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; + +import VirtualTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/virtualtesteditor'; +import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; + +describe( 'HighlightEditing', () => { + let editor, doc; + + beforeEach( () => { + return VirtualTestEditor + .create( { + plugins: [ HighlightEditing, Paragraph ] + } ) + .then( newEditor => { + editor = newEditor; + + doc = editor.document; + } ); + } ); + + afterEach( () => { + editor.destroy(); + } ); + + it( 'adds highlight commands', () => { + expect( editor.commands.get( 'highlight' ) ).to.be.instanceOf( HighlightCommand ); + } ); + + it.skip( 'allows for highlight in $blocks', () => { + expect( doc.schema.check( { name: '$text', inside: '$root', attributes: 'highlight' } ) ).to.be.true; + } ); + + describe.skip( 'integration', () => { + beforeEach( () => { + return VirtualTestEditor + .create( { + plugins: [ HighlightEditing, Paragraph ] + } ) + .then( newEditor => { + editor = newEditor; + + doc = editor.document; + } ); + } ); + + it( 'is allowed inside paragraph', () => { + expect( doc.schema.check( { name: 'paragraph', attributes: 'highlight' } ) ).to.be.true; + } ); + } ); + + describe.skip( 'highlight', () => { + it( 'adds converters to the data pipeline', () => { + const data = '

foo

'; + + editor.setData( data ); + + expect( getModelData( doc ) ).to.equal( 'f<$text highlight="">oo' ); + expect( editor.getData() ).to.equal( '

x

' ); + } ); + + it( 'adds a converter to the view pipeline for removing attribute', () => { + setModelData( doc, 'f<$text highlight="">oo' ); + + expect( editor.getData() ).to.equal( '

foo

' ); + + const command = editor.commands.get( 'highlight' ); + + command.execute(); + + expect( editor.getData() ).to.equal( '

x

' ); + } ); + } ); + + describe.skip( 'config', () => { + describe( 'styles', () => { + describe( 'default value', () => { + it( 'should be set', () => { + expect( editor.config.get( 'highlight.styles' ) ).to.deep.equal( {} ); + } ); + } ); + } ); + } ); +} ); From 60285c72da42cf33f9a4fa677a570d61e83c3f00 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Mon, 6 Nov 2017 15:51:58 +0100 Subject: [PATCH 02/20] Other: Implement HighlightCommand value and isEnabled properties calculation on refresh. --- src/highlightcommand.js | 28 ++++------------------------ tests/highlightcommand.js | 22 ++++++++++++++-------- 2 files changed, 18 insertions(+), 32 deletions(-) diff --git a/src/highlightcommand.js b/src/highlightcommand.js index 4b3ef8e..a267489 100644 --- a/src/highlightcommand.js +++ b/src/highlightcommand.js @@ -46,8 +46,10 @@ export default class HighlightCommand extends Command { * @inheritDoc */ refresh() { - this.isEnabled = this._checkEnabled(); - this.value = this._getValue(); + const doc = this.editor.document; + + this.value = doc.selection.getAttribute( 'highlight' ); + this.isEnabled = doc.schema.checkAttributeInSelection( doc.selection, 'highlight' ); } /** @@ -66,26 +68,4 @@ export default class HighlightCommand extends Command { // TODO } ); } - - /** - * Checks whether the command can be enabled in the current context. - * - * @private - * @param {module:engine/model/element~Element} firstBlock A first block in selection to be checked. - * @returns {Boolean} Whether the command should be enabled. - */ - _checkEnabled() { - return true; - } - - /** - * Checks the command's {@link #value}. - * - * @private - * @param {module:engine/model/element~Element} firstBlock A first block in selection to be checked. - * @returns {Boolean} The current value. - */ - _getValue() { - return true; - } } diff --git a/tests/highlightcommand.js b/tests/highlightcommand.js index 5417e42..2fe17e9 100644 --- a/tests/highlightcommand.js +++ b/tests/highlightcommand.js @@ -24,7 +24,7 @@ describe( 'HighlightCommand', () => { doc.schema.registerItem( 'paragraph', '$block' ); - doc.schema.allow( { name: '$block', inside: '$root', attributes: 'highlight' } ); + doc.schema.allow( { name: '$inline', attributes: 'highlight', inside: '$block' } ); } ); } ); @@ -38,16 +38,22 @@ describe( 'HighlightCommand', () => { } ); describe( 'value', () => { - it( 'is true when selection is in block with commend type highlight', () => { - setModelData( doc, '<$text highlight="true">fo[]o' ); + it( 'is set to highlight attribute value when selection is in text with highlight attribute', () => { + setModelData( doc, '<$text highlight="marker">fo[]o' ); - expect( command ).to.have.property( 'value', true ); + expect( command ).to.have.property( 'value', 'marker' ); + } ); + + it( 'is undefined when selection is not in text with highlight attribute', () => { + setModelData( doc, 'fo[]o' ); + + expect( command ).to.have.property( 'value', undefined ); } ); } ); describe( 'isEnabled', () => { - it( 'is true when selection is in a block which can have added highlight', () => { - setModelData( doc, '<$text highlight="true">fo[]o' ); + it( 'is true when selection is on text which can have highlight added', () => { + setModelData( doc, 'fo[]o' ); expect( command ).to.have.property( 'isEnabled', true ); } ); @@ -58,9 +64,9 @@ describe( 'HighlightCommand', () => { it( 'adds highlight to selected text element', () => { setModelData( doc, 'f[o]o' ); - editor.execute( 'highlight' ); + editor.execute( 'highlight', { class: 'marker' } ); - expect( getModelData( doc ) ).to.equal( 'f<$text highlight="true">[o]o' ); + expect( getModelData( doc ) ).to.equal( 'f<$text highlight="marker">[o]o' ); } ); } ); } ); From 8a2e63d37d881d32bfb462a02b3eb3db8e2136ae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Mon, 6 Nov 2017 16:17:44 +0100 Subject: [PATCH 03/20] Other: Initial implementation of `HighlightCommand#execute` method. --- src/highlightcommand.js | 29 ++++++++++++++++++++----- tests/highlightcommand.js | 45 ++++++++++++++++++++++++++++++++------- 2 files changed, 61 insertions(+), 13 deletions(-) diff --git a/src/highlightcommand.js b/src/highlightcommand.js index a267489..d029176 100644 --- a/src/highlightcommand.js +++ b/src/highlightcommand.js @@ -57,15 +57,34 @@ export default class HighlightCommand extends Command { * * @protected * @param {Object} [options] Options for the executed command. + * @param {String} options.class Name of marker class name. * @param {module:engine/model/batch~Batch} [options.batch] A batch to collect all the change steps. * A new batch will be created if this option is not set. */ - execute() { - const editor = this.editor; - const document = editor.document; + execute( options = {} ) { + const doc = this.editor.document; + const selection = doc.selection; + const value = options.class; + + doc.enqueueChanges( () => { + if ( selection.isCollapsed ) { + if ( value ) { + selection.setAttribute( 'highlight', value ); + } else { + selection.removeAttribute( 'highlight' ); + } + } else { + const ranges = doc.schema.getValidRanges( selection.getRanges(), 'highlight' ); + const batch = options.batch || doc.batch(); - document.enqueueChanges( () => { - // TODO + for ( const range of ranges ) { + if ( value ) { + batch.setAttribute( range, 'highlight', value ); + } else { + batch.removeAttribute( range, 'highlight' ); + } + } + } } ); } } diff --git a/tests/highlightcommand.js b/tests/highlightcommand.js index 2fe17e9..1d6499d 100644 --- a/tests/highlightcommand.js +++ b/tests/highlightcommand.js @@ -5,10 +5,11 @@ import HighlightCommand from './../src/highlightcommand'; -import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; +import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; import Command from '@ckeditor/ckeditor5-core/src/command'; import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor'; +import { getData, setData } from '../../ckeditor5-engine/src/dev-utils/model'; describe( 'HighlightCommand', () => { let editor, doc, command; @@ -59,15 +60,43 @@ describe( 'HighlightCommand', () => { } ); } ); - describe.skip( 'execute()', () => { - describe( 'applying highlight', () => { - it( 'adds highlight to selected text element', () => { - setModelData( doc, 'f[o]o' ); + describe( 'execute()', () => { + it( 'should add highlight attribute on selected nodes nodes when passed as parameter', () => { + setData( doc, 'a[bc<$text highlight="marker">fo]obarxyz' ); - editor.execute( 'highlight', { class: 'marker' } ); + expect( command.value ).to.be.undefined; - expect( getModelData( doc ) ).to.equal( 'f<$text highlight="marker">[o]o' ); - } ); + command.execute( { class: 'marker' } ); + + expect( command.value ).to.equal( 'marker' ); + + expect( getData( doc ) ).to.equal( 'a[<$text highlight="marker">bcfo]obarxyz' ); + } ); + + it( 'should set highlight attribute on selected nodes when passed as parameter', () => { + setData( doc, 'abc[<$text highlight="marker">foo]barxyz' ); + + expect( command.value ).to.equal( 'marker' ); + + command.execute( { class: 'foo' } ); + + expect( getData( doc ) ).to.equal( + 'abc[<$text highlight="foo">foo]<$text highlight="marker">barxyz' + ); + + expect( command.value ).to.equal( 'foo' ); + } ); + + it( 'should remove highlight attribute on selected nodes nodes when undefined passed as parameter', () => { + setData( doc, 'abc[<$text highlight="marker">foo]barxyz' ); + + expect( command.value ).to.equal( 'marker' ); + + command.execute(); + + expect( getData( doc ) ).to.equal( 'abc[foo]<$text highlight="marker">barxyz' ); + + expect( command.value ).to.be.undefined; } ); } ); } ); From cfa059de1d7a1c8d5183b5440fd4b586e7387923 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Mon, 6 Nov 2017 16:21:04 +0100 Subject: [PATCH 04/20] Other: Do nothing on collapsed ranges in `HighlightCommand#exectue()`. --- src/highlightcommand.js | 24 ++++++++++-------------- tests/highlightcommand.js | 12 ++++++++++++ 2 files changed, 22 insertions(+), 14 deletions(-) diff --git a/src/highlightcommand.js b/src/highlightcommand.js index d029176..b110abf 100644 --- a/src/highlightcommand.js +++ b/src/highlightcommand.js @@ -66,23 +66,19 @@ export default class HighlightCommand extends Command { const selection = doc.selection; const value = options.class; + if ( selection.isCollapsed ) { + return; + } + doc.enqueueChanges( () => { - if ( selection.isCollapsed ) { + const ranges = doc.schema.getValidRanges( selection.getRanges(), 'highlight' ); + const batch = options.batch || doc.batch(); + + for ( const range of ranges ) { if ( value ) { - selection.setAttribute( 'highlight', value ); + batch.setAttribute( range, 'highlight', value ); } else { - selection.removeAttribute( 'highlight' ); - } - } else { - const ranges = doc.schema.getValidRanges( selection.getRanges(), 'highlight' ); - const batch = options.batch || doc.batch(); - - for ( const range of ranges ) { - if ( value ) { - batch.setAttribute( range, 'highlight', value ); - } else { - batch.removeAttribute( range, 'highlight' ); - } + batch.removeAttribute( range, 'highlight' ); } } } ); diff --git a/tests/highlightcommand.js b/tests/highlightcommand.js index 1d6499d..ddbdb30 100644 --- a/tests/highlightcommand.js +++ b/tests/highlightcommand.js @@ -98,5 +98,17 @@ describe( 'HighlightCommand', () => { expect( command.value ).to.be.undefined; } ); + + it( 'should do nothing on collapsed range', () => { + setData( doc, 'abc<$text highlight="marker">foo[]barxyz' ); + + expect( command.value ).to.equal( 'marker' ); + + command.execute(); + + expect( getData( doc ) ).to.equal( 'abc<$text highlight="marker">foo[]barxyz' ); + + expect( command.value ).to.equal( 'marker' ); + } ); } ); } ); From 351c192ae5b1485bfc97d858ab2eaf2df636281a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Mon, 6 Nov 2017 16:48:20 +0100 Subject: [PATCH 05/20] Other: Provide configuration stub. --- src/highlightediting.js | 8 ++++++++ tests/highlightediting.js | 24 +++++++++++++++--------- 2 files changed, 23 insertions(+), 9 deletions(-) diff --git a/src/highlightediting.js b/src/highlightediting.js index 59a623d..ca4d490 100644 --- a/src/highlightediting.js +++ b/src/highlightediting.js @@ -21,6 +21,14 @@ export default class HighlightEditing extends Plugin { init() { const editor = this.editor; + editor.config.define( 'highlight', [ + { class: 'marker', title: 'Marker', color: '#ffff66', type: 'marker' }, + { class: 'marker-green', title: 'Green Marker', color: '#66ff00', type: 'marker' }, + { class: 'marker-pink', title: 'Pink Marker', color: '#ff6fff', type: 'marker' }, + { class: 'pen-red', title: 'Red Pen', color: '#ff0000', type: 'pen' }, + { class: 'pen-blue', title: 'Blue Pen', color: '#0000ff', type: 'pen' } + ] ); + editor.commands.add( 'highlight', new HighlightCommand( editor ) ); } } diff --git a/tests/highlightediting.js b/tests/highlightediting.js index 5a4a167..c68fea7 100644 --- a/tests/highlightediting.js +++ b/tests/highlightediting.js @@ -56,16 +56,18 @@ describe( 'HighlightEditing', () => { } ); } ); - describe.skip( 'highlight', () => { - it( 'adds converters to the data pipeline', () => { - const data = '

foo

'; + describe.skip( 'data pipeline conversions', () => { + it( 'should convert defined marker classes', () => { + const data = '

foo

'; editor.setData( data ); expect( getModelData( doc ) ).to.equal( 'f<$text highlight="">oo' ); expect( editor.getData() ).to.equal( '

x

' ); } ); + } ); + describe.skip( 'editing pipeline conversion', () => { it( 'adds a converter to the view pipeline for removing attribute', () => { setModelData( doc, 'f<$text highlight="">oo' ); @@ -79,12 +81,16 @@ describe( 'HighlightEditing', () => { } ); } ); - describe.skip( 'config', () => { - describe( 'styles', () => { - describe( 'default value', () => { - it( 'should be set', () => { - expect( editor.config.get( 'highlight.styles' ) ).to.deep.equal( {} ); - } ); + describe( 'config', () => { + describe( 'default value', () => { + it( 'should be set', () => { + expect( editor.config.get( 'highlight' ) ).to.deep.equal( [ + { class: 'marker', title: 'Marker', color: '#ffff66', type: 'marker' }, + { class: 'marker-green', title: 'Green Marker', color: '#66ff00', type: 'marker' }, + { class: 'marker-pink', title: 'Pink Marker', color: '#ff6fff', type: 'marker' }, + { class: 'pen-red', title: 'Red Pen', color: '#ff0000', type: 'pen' }, + { class: 'pen-blue', title: 'Blue Pen', color: '#0000ff', type: 'pen' } + ] ); } ); } ); } ); From 23adf9216168b45fd380ae39633ad4dcf495e425 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Mon, 6 Nov 2017 17:04:20 +0100 Subject: [PATCH 06/20] Tests: Fix paths in test files. --- tests/highlightcommand.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/tests/highlightcommand.js b/tests/highlightcommand.js index ddbdb30..be51172 100644 --- a/tests/highlightcommand.js +++ b/tests/highlightcommand.js @@ -5,11 +5,9 @@ import HighlightCommand from './../src/highlightcommand'; -import { setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; - import Command from '@ckeditor/ckeditor5-core/src/command'; import ModelTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/modeltesteditor'; -import { getData, setData } from '../../ckeditor5-engine/src/dev-utils/model'; +import { getData, setData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; describe( 'HighlightCommand', () => { let editor, doc, command; @@ -40,13 +38,13 @@ describe( 'HighlightCommand', () => { describe( 'value', () => { it( 'is set to highlight attribute value when selection is in text with highlight attribute', () => { - setModelData( doc, '<$text highlight="marker">fo[]o' ); + setData( doc, '<$text highlight="marker">fo[]o' ); expect( command ).to.have.property( 'value', 'marker' ); } ); it( 'is undefined when selection is not in text with highlight attribute', () => { - setModelData( doc, 'fo[]o' ); + setData( doc, 'fo[]o' ); expect( command ).to.have.property( 'value', undefined ); } ); @@ -54,7 +52,7 @@ describe( 'HighlightCommand', () => { describe( 'isEnabled', () => { it( 'is true when selection is on text which can have highlight added', () => { - setModelData( doc, 'fo[]o' ); + setData( doc, 'fo[]o' ); expect( command ).to.have.property( 'isEnabled', true ); } ); From c167c1309ea1a0c64cf44a6232d015abfe862b67 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Mon, 6 Nov 2017 17:59:49 +0100 Subject: [PATCH 07/20] Tests: Add manual tests stub. --- tests/manual/highlight.html | 49 +++++++++++++++++++++++++++++++++++++ tests/manual/highlight.js | 24 ++++++++++++++++++ tests/manual/highlight.md | 9 +++++++ 3 files changed, 82 insertions(+) create mode 100644 tests/manual/highlight.html create mode 100644 tests/manual/highlight.js create mode 100644 tests/manual/highlight.md diff --git a/tests/manual/highlight.html b/tests/manual/highlight.html new file mode 100644 index 0000000..c854a9c --- /dev/null +++ b/tests/manual/highlight.html @@ -0,0 +1,49 @@ + +
+

Lorem + ipsum dolor sit amet + , consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis + nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate + velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat + + cupidatat non proident, sunt in culpa qui officia + deserunt mollit anim id est laborum. +

+

Lorem ipsum dolor sit amet, consectetur + adipiscing elit + , sed do eiusmod tempor incididunt ut labore et dolore magna + aliqua. Ut enim ad minim veniam + , quis nostrud exercitation ullamco + laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit + esse cillum dolore eu + + fugiat nulla pariatur. + Excepteur + sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est + laborum. +

+
diff --git a/tests/manual/highlight.js b/tests/manual/highlight.js new file mode 100644 index 0000000..657424a --- /dev/null +++ b/tests/manual/highlight.js @@ -0,0 +1,24 @@ +/** + * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ + +/* globals console, window, document */ + +import ClassicEditor from '../../../ckeditor5-editor-classic/src/classiceditor'; +import ArticlePluginSet from '../../../ckeditor5-core/tests/_utils/articlepluginset'; +import Highlight from '../../src/highlight'; + +ClassicEditor + .create( document.querySelector( '#editor' ), { + plugins: [ ArticlePluginSet, Highlight ], + toolbar: [ + 'headings', 'bold', 'italic', 'link', 'mark', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' + ] + } ) + .then( editor => { + window.editor = editor; + } ) + .catch( err => { + console.error( err.stack ); + } ); diff --git a/tests/manual/highlight.md b/tests/manual/highlight.md new file mode 100644 index 0000000..793d4e6 --- /dev/null +++ b/tests/manual/highlight.md @@ -0,0 +1,9 @@ +### Loading + +1. The data should be loaded with: + +### Testing + +You should be able to: + + From c284402132175e67effcac307ad5674bc91d321e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Mon, 6 Nov 2017 18:10:07 +0100 Subject: [PATCH 08/20] Other: Define highlight feature conversions. --- src/highlightediting.js | 43 +++++++++++++++++++++++++++++++++++++++ tests/highlightediting.js | 36 ++++++++++++++++++++++---------- 2 files changed, 68 insertions(+), 11 deletions(-) diff --git a/src/highlightediting.js b/src/highlightediting.js index ca4d490..a6eef7b 100644 --- a/src/highlightediting.js +++ b/src/highlightediting.js @@ -10,6 +10,10 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; import HighlightCommand from './highlightcommand'; +import buildViewConverter from '@ckeditor/ckeditor5-engine/src/conversion/buildviewconverter'; +import buildModelConverter from '@ckeditor/ckeditor5-engine/src/conversion/buildmodelconverter'; + +import AttributeElement from '@ckeditor/ckeditor5-engine/src/view/attributeelement'; /** * @extends module:core/plugin~Plugin @@ -20,6 +24,8 @@ export default class HighlightEditing extends Plugin { */ init() { const editor = this.editor; + const data = editor.data; + const editing = editor.editing; editor.config.define( 'highlight', [ { class: 'marker', title: 'Marker', color: '#ffff66', type: 'marker' }, @@ -29,6 +35,43 @@ export default class HighlightEditing extends Plugin { { class: 'pen-blue', title: 'Blue Pen', color: '#0000ff', type: 'pen' } ] ); + // Allow highlight attribute on all elements + editor.document.schema.allow( { name: '$inline', attributes: 'highlight', inside: '$block' } ); + + // Convert highlight attribute to a mark element with associated class. + buildModelConverter() + .for( data.modelToView, editing.modelToView ) + .fromAttribute( 'highlight' ) + .toElement( data => { + const attributeElement = new AttributeElement( 'mark' ); + + attributeElement.addClass( data ); + + return attributeElement; + } ); + + const configuredClasses = editor.config.get( 'highlight' ).map( config => config.class ); + + // Convert `mark` attribute with class name to model's highlight attribute. + buildViewConverter() + .for( data.viewToModel ) + .fromElement( 'mark' ) + .toAttribute( viewElement => { + const viewClassNames = [ ...viewElement.getClassNames() ]; + + if ( !viewClassNames.length ) { + return; + } + + const highlightClassNames = viewClassNames.filter( className => configuredClasses.includes( className ) ); + + if ( !highlightClassNames.length ) { + return; + } + + return { key: 'highlight', value: highlightClassNames[ 0 ] }; + } ); + editor.commands.add( 'highlight', new HighlightCommand( editor ) ); } } diff --git a/tests/highlightediting.js b/tests/highlightediting.js index c68fea7..7658816 100644 --- a/tests/highlightediting.js +++ b/tests/highlightediting.js @@ -56,28 +56,42 @@ describe( 'HighlightEditing', () => { } ); } ); - describe.skip( 'data pipeline conversions', () => { + describe( 'data pipeline conversions', () => { it( 'should convert defined marker classes', () => { const data = '

foo

'; editor.setData( data ); - expect( getModelData( doc ) ).to.equal( 'f<$text highlight="">oo' ); - expect( editor.getData() ).to.equal( '

x

' ); + expect( getModelData( doc ) ).to.equal( '[]f<$text highlight="marker">oo' ); + expect( editor.getData() ).to.equal( data ); + } ); + it( 'should convert only one defined marker classes', () => { + editor.setData( '

foo

' ); + + expect( getModelData( doc ) ).to.equal( '[]f<$text highlight="marker-green">oo' ); + expect( editor.getData() ).to.equal( '

foo

' ); } ); - } ); - describe.skip( 'editing pipeline conversion', () => { - it( 'adds a converter to the view pipeline for removing attribute', () => { - setModelData( doc, 'f<$text highlight="">oo' ); + it( 'should not convert undefined marker classes', () => { + editor.setData( '

foo

' ); - expect( editor.getData() ).to.equal( '

foo

' ); + expect( getModelData( doc ) ).to.equal( '[]foo' ); + expect( editor.getData() ).to.equal( '

foo

' ); + } ); - const command = editor.commands.get( 'highlight' ); + it( 'should not convert marker without class', () => { + editor.setData( '

foo

' ); + + expect( getModelData( doc ) ).to.equal( '[]foo' ); + expect( editor.getData() ).to.equal( '

foo

' ); + } ); + } ); - command.execute(); + describe( 'editing pipeline conversion', () => { + it( 'should convert mark element with defined class', () => { + setModelData( doc, 'f<$text highlight="marker">oo' ); - expect( editor.getData() ).to.equal( '

x

' ); + expect( editor.getData() ).to.equal( '

foo

' ); } ); } ); From 4f69319ef66a02259fab2ea9bcedc66829513876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Mon, 6 Nov 2017 18:16:08 +0100 Subject: [PATCH 09/20] Tests: Remove unknown button from toolbar in manual tests. --- tests/manual/highlight.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/manual/highlight.js b/tests/manual/highlight.js index 657424a..2884081 100644 --- a/tests/manual/highlight.js +++ b/tests/manual/highlight.js @@ -13,7 +13,7 @@ ClassicEditor .create( document.querySelector( '#editor' ), { plugins: [ ArticlePluginSet, Highlight ], toolbar: [ - 'headings', 'bold', 'italic', 'link', 'mark', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' + 'headings', 'bold', 'italic', 'link', 'bulletedList', 'numberedList', 'blockQuote', 'undo', 'redo' ] } ) .then( editor => { From 8ec55f8fb7b96aabe4242fdba91f81995f7e9691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Tue, 7 Nov 2017 09:32:31 +0100 Subject: [PATCH 10/20] Other: Simplify model converter. --- src/highlightediting.js | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/highlightediting.js b/src/highlightediting.js index a6eef7b..1e33689 100644 --- a/src/highlightediting.js +++ b/src/highlightediting.js @@ -42,13 +42,7 @@ export default class HighlightEditing extends Plugin { buildModelConverter() .for( data.modelToView, editing.modelToView ) .fromAttribute( 'highlight' ) - .toElement( data => { - const attributeElement = new AttributeElement( 'mark' ); - - attributeElement.addClass( data ); - - return attributeElement; - } ); + .toElement( data => new AttributeElement( 'mark', { class: data } ) ); const configuredClasses = editor.config.get( 'highlight' ).map( config => config.class ); From b6a3970e69947896d06b063d3e0f46809eec2b0a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Tue, 7 Nov 2017 10:45:13 +0100 Subject: [PATCH 11/20] Docs: Update documentation. --- src/highlightcommand.js | 46 +++++++++++------------------------- src/highlightediting.js | 52 ++++++++++++++++++++++++++++++++++++++++- src/highlightui.js | 7 ------ 3 files changed, 65 insertions(+), 40 deletions(-) diff --git a/src/highlightcommand.js b/src/highlightcommand.js index b110abf..9bb0878 100644 --- a/src/highlightcommand.js +++ b/src/highlightcommand.js @@ -10,38 +10,12 @@ import Command from '@ckeditor/ckeditor5-core/src/command'; /** - * The highlight command. + * The highlight command. It is used by the {@link module:highlight/highlight~HighlightEditing highlight feature} + * to apply text highlighting. * * @extends module:core/command~Command */ export default class HighlightCommand extends Command { - /** - * Creates an instance of the command. - * - * @param {module:core/editor/editor~Editor} editor The editor instance. - * @param {'left'|'right'|'center'|'justify'} type Highlight type to be handled by this command. - */ - constructor( editor, type ) { - super( editor ); - - /** - * The type of the list created by the command. - * - * @readonly - * @member {'left'|'right'|'center'|'justify'} - */ - this.type = type; - - /** - * A flag indicating whether the command is active, which means that the selection starts in a block - * that has defined highlight of the same type. - * - * @observable - * @readonly - * @member {Boolean} #value - */ - } - /** * @inheritDoc */ @@ -57,15 +31,15 @@ export default class HighlightCommand extends Command { * * @protected * @param {Object} [options] Options for the executed command. - * @param {String} options.class Name of marker class name. + * @param {String} options.class Name of highlighter class. * @param {module:engine/model/batch~Batch} [options.batch] A batch to collect all the change steps. * A new batch will be created if this option is not set. */ execute( options = {} ) { const doc = this.editor.document; const selection = doc.selection; - const value = options.class; + // Do not apply highlight no collapsed selection. if ( selection.isCollapsed ) { return; } @@ -75,8 +49,8 @@ export default class HighlightCommand extends Command { const batch = options.batch || doc.batch(); for ( const range of ranges ) { - if ( value ) { - batch.setAttribute( range, 'highlight', value ); + if ( options.class ) { + batch.setAttribute( range, 'highlight', options.class ); } else { batch.removeAttribute( range, 'highlight' ); } @@ -84,3 +58,11 @@ export default class HighlightCommand extends Command { } ); } } + +/** + * Holds current highlight class. If there is no highlight in selection then value will be undefined. + * + * @observable + * @readonly + * @member {undefined|String} HighlightCommand#value + */ diff --git a/src/highlightediting.js b/src/highlightediting.js index 1e33689..8157f4b 100644 --- a/src/highlightediting.js +++ b/src/highlightediting.js @@ -9,13 +9,16 @@ import Plugin from '@ckeditor/ckeditor5-core/src/plugin'; -import HighlightCommand from './highlightcommand'; import buildViewConverter from '@ckeditor/ckeditor5-engine/src/conversion/buildviewconverter'; import buildModelConverter from '@ckeditor/ckeditor5-engine/src/conversion/buildmodelconverter'; import AttributeElement from '@ckeditor/ckeditor5-engine/src/view/attributeelement'; +import HighlightCommand from './highlightcommand'; + /** + * The highlight editing feature. It introduces `highlight` command which allow to highlight selected text with defined 'marker' or 'pen'. + * * @extends module:core/plugin~Plugin */ export default class HighlightEditing extends Plugin { @@ -69,3 +72,50 @@ export default class HighlightEditing extends Plugin { editor.commands.add( 'highlight', new HighlightCommand( editor ) ); } } + +/** + * Highlight option descriptor. + * + * @typedef {Object} module:highlight/highlightediting~HeadingOption + * @property {String} class The class which is used to differentiate highlighters. + * @property {String} title The user-readable title of the option. + * @property {String} color Color used for highlighter. Should be coherent with CSS class definition. + * @property {'marker'|'pen'} type The type of highlighter. Either "marker" - will use #color as background name + * of the view element that will be used to represent the model element in the view. + */ + +/** + * The configuration of the {@link module:highlight/highlightediting~HighlightEditing Highlight feature}. + * + * Read more in {@link module:highlight/highlightediting~HighlightEditingConfig}. + * + * @member {module:highlight/highlightediting~HighlightEditingConfig} module:core/editor/editorconfig~EditorConfig#alignment + */ + +/** + * The configuration of the {@link module:highlight/highlightediting~HighlightEditing Highlight feature}. + * + * ClassicEditor + * .create( editorElement, { + * highlight: ... // Highlight feature config. + * } ) + * .then( ... ) + * .catch( ... ); + * + * See {@link module:core/editor/editorconfig~EditorConfig all editor options}. + * + * @interface HighlightEditingConfig + */ + +/** + * Available highlighters options. + * + * There are two types of highlighters: + * - 'marker' - rendered as `` element with defined background color. + * - 'pen' - rendered as `` element with defined foreground (font) color. + * + * Note: Each highlighter must have it's own CSS class defined to properly match content data. Also it is advised + * that color value should match the values defined in content CSS stylesheet. + * + * @member {Array.} module:heading/heading~HeadingConfig#options + */ diff --git a/src/highlightui.js b/src/highlightui.js index a1bf053..92b796f 100644 --- a/src/highlightui.js +++ b/src/highlightui.js @@ -30,11 +30,4 @@ export default class HighlightUI extends Plugin { static get pluginName() { return 'HighlightUI'; } - - /** - * @inheritDoc - */ - init() { - // TODO - } } From 82d70ad540129f2706a035b85323846cf70e274e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Tue, 7 Nov 2017 11:46:55 +0100 Subject: [PATCH 12/20] Tests: Update highlight manual tests. --- tests/manual/highlight.html | 26 +++++--------------------- tests/manual/highlight.md | 6 +++--- 2 files changed, 8 insertions(+), 24 deletions(-) diff --git a/tests/manual/highlight.html b/tests/manual/highlight.html index c854a9c..f9de287 100644 --- a/tests/manual/highlight.html +++ b/tests/manual/highlight.html @@ -23,27 +23,11 @@
-

Lorem - ipsum dolor sit amet - , consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis - nostrud exercitation ullamco - laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate - velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat - - cupidatat non proident, sunt in culpa qui officia - deserunt mollit anim id est laborum. +

Highlight feature example.

+

Here ares some markers: + yellow one, pink one and green one.

-

Lorem ipsum dolor sit amet, consectetur - adipiscing elit - , sed do eiusmod tempor incididunt ut labore et dolore magna - aliqua. Ut enim ad minim veniam - , quis nostrud exercitation ullamco - laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit - esse cillum dolore eu - - fugiat nulla pariatur. - Excepteur - sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est - laborum. +

Here ares some pens: + red pen and blue one.

diff --git a/tests/manual/highlight.md b/tests/manual/highlight.md index 793d4e6..ed702d1 100644 --- a/tests/manual/highlight.md +++ b/tests/manual/highlight.md @@ -1,9 +1,9 @@ ### Loading -1. The data should be loaded with: +1. The data should be loaded with different markers and pens. ### Testing You should be able to: - - +- see different markers class +- manually invoke highlight command in console From 31d547f14e10e872b99837713503f60b154c3e98 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Tue, 7 Nov 2017 12:09:49 +0100 Subject: [PATCH 13/20] Tests: Add some integration tests and remove skipped. --- tests/highlightcommand.js | 19 +++++++++++ tests/highlightediting.js | 22 ------------- tests/integration.js | 69 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 88 insertions(+), 22 deletions(-) create mode 100644 tests/integration.js diff --git a/tests/highlightcommand.js b/tests/highlightcommand.js index be51172..df20344 100644 --- a/tests/highlightcommand.js +++ b/tests/highlightcommand.js @@ -71,6 +71,25 @@ describe( 'HighlightCommand', () => { expect( getData( doc ) ).to.equal( 'a[<$text highlight="marker">bcfo]obarxyz' ); } ); + it( 'should add highlight attribute on selected nodes nodes when passed as parameter (multiple nodes)', () => { + setData( + doc, + 'abcabc[abc' + + 'foofoofoo' + + 'barbar]bar' + ); + + command.execute( { class: 'marker' } ); + + expect( command.value ).to.equal( 'marker' ); + + expect( getData( doc ) ).to.equal( + 'abcabc[<$text highlight="marker">abc' + + '<$text highlight="marker">foofoofoo' + + '<$text highlight="marker">barbar]bar' + ); + } ); + it( 'should set highlight attribute on selected nodes when passed as parameter', () => { setData( doc, 'abc[<$text highlight="marker">foo]barxyz' ); diff --git a/tests/highlightediting.js b/tests/highlightediting.js index 7658816..1cc689f 100644 --- a/tests/highlightediting.js +++ b/tests/highlightediting.js @@ -34,28 +34,6 @@ describe( 'HighlightEditing', () => { expect( editor.commands.get( 'highlight' ) ).to.be.instanceOf( HighlightCommand ); } ); - it.skip( 'allows for highlight in $blocks', () => { - expect( doc.schema.check( { name: '$text', inside: '$root', attributes: 'highlight' } ) ).to.be.true; - } ); - - describe.skip( 'integration', () => { - beforeEach( () => { - return VirtualTestEditor - .create( { - plugins: [ HighlightEditing, Paragraph ] - } ) - .then( newEditor => { - editor = newEditor; - - doc = editor.document; - } ); - } ); - - it( 'is allowed inside paragraph', () => { - expect( doc.schema.check( { name: 'paragraph', attributes: 'highlight' } ) ).to.be.true; - } ); - } ); - describe( 'data pipeline conversions', () => { it( 'should convert defined marker classes', () => { const data = '

foo

'; diff --git a/tests/integration.js b/tests/integration.js new file mode 100644 index 0000000..1fd3f40 --- /dev/null +++ b/tests/integration.js @@ -0,0 +1,69 @@ +/** + * @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved. + * For licensing, see LICENSE.md. + */ + +/* global document */ + +import Highlight from '../src/highlight'; +import BlockQuote from '@ckeditor/ckeditor5-block-quote/src/blockquote'; +import Paragraph from '@ckeditor/ckeditor5-paragraph/src/paragraph'; +import Heading from '@ckeditor/ckeditor5-heading/src/heading'; +import Image from '@ckeditor/ckeditor5-image/src/image'; +import ImageCaption from '@ckeditor/ckeditor5-image/src/imagecaption'; +import List from '@ckeditor/ckeditor5-list/src/list'; +import Enter from '@ckeditor/ckeditor5-enter/src/enter'; +import Delete from '@ckeditor/ckeditor5-typing/src/delete'; + +import ClassicTestEditor from '@ckeditor/ckeditor5-core/tests/_utils/classictesteditor'; +import { getData as getModelData, setData as setModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model'; + +describe( 'Highlight', () => { + let editor, doc, element; + + beforeEach( () => { + element = document.createElement( 'div' ); + document.body.appendChild( element ); + + return ClassicTestEditor + .create( element, { + plugins: [ Highlight, BlockQuote, Paragraph, Heading, Image, ImageCaption, List, Enter, Delete ] + } ) + .then( newEditor => { + editor = newEditor; + doc = editor.document; + } ); + } ); + + afterEach( () => { + element.remove(); + + return editor.destroy(); + } ); + + describe( 'compatibility with images', () => { + it( 'does not work inside image caption', () => { + setModelData( doc, 'foo[bar]baz' ); + + editor.execute( 'highlight', { class: 'marker' } ); + + expect( getModelData( doc ) ) + .to.equal( 'foo[<$text highlight="marker">bar]baz' ); + } ); + + it( 'does not work on selection with image', () => { + setModelData( + doc, + 'foo[fooabcbar]bar' + ); + + editor.execute( 'highlight', { class: 'marker' } ); + + expect( getModelData( doc ) ).to.equal( + 'foo[<$text highlight="marker">foo' + + '<$text highlight="marker">abc' + + '<$text highlight="marker">bar]bar' + ); + } ); + } ); +} ); From 45716e5f0ce5d94b5f44b1767a6f0f7f543d313e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Tue, 7 Nov 2017 12:25:10 +0100 Subject: [PATCH 14/20] Other: Add missing dev dependencies. --- package.json | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/package.json b/package.json index 8dc1719..cc80704 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,13 @@ "@ckeditor/ckeditor5-ui": "^1.0.0-alpha.1" }, "devDependencies": { + "@ckeditor/ckeditor5-block-quote": "^1.0.0-alpha.1", + "@ckeditor/ckeditor5-enter": "^1.0.0-alpha.1", + "@ckeditor/ckeditor5-heading": "^1.0.0-alpha.1", + "@ckeditor/ckeditor5-image": "^1.0.0-alpha.1", + "@ckeditor/ckeditor5-list": "^1.0.0-alpha.1", "@ckeditor/ckeditor5-paragraph": "^1.0.0-alpha.1", + "@ckeditor/ckeditor5-typing": "^1.0.0-alpha.1", "eslint": "^4.8.0", "eslint-config-ckeditor5": "^1.0.6", "husky": "^0.14.3", From cbc29276367af51012c66e4b91d445d6df362eff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 9 Nov 2017 14:25:16 +0100 Subject: [PATCH 15/20] Other: Move configuration definition to constructor. --- src/highlightediting.js | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/highlightediting.js b/src/highlightediting.js index 8157f4b..5130abd 100644 --- a/src/highlightediting.js +++ b/src/highlightediting.js @@ -25,10 +25,8 @@ export default class HighlightEditing extends Plugin { /** * @inheritDoc */ - init() { - const editor = this.editor; - const data = editor.data; - const editing = editor.editing; + constructor( editor ) { + super( editor ); editor.config.define( 'highlight', [ { class: 'marker', title: 'Marker', color: '#ffff66', type: 'marker' }, @@ -37,6 +35,15 @@ export default class HighlightEditing extends Plugin { { class: 'pen-red', title: 'Red Pen', color: '#ff0000', type: 'pen' }, { class: 'pen-blue', title: 'Blue Pen', color: '#0000ff', type: 'pen' } ] ); + } + + /** + * @inheritDoc + */ + init() { + const editor = this.editor; + const data = editor.data; + const editing = editor.editing; // Allow highlight attribute on all elements editor.document.schema.allow( { name: '$inline', attributes: 'highlight', inside: '$block' } ); From c9c102a959a1f0fee06a31f28576fff62bb97922 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 9 Nov 2017 14:32:41 +0100 Subject: [PATCH 16/20] Docs: Fix documentation links and highlighters description. --- src/highlightcommand.js | 4 ++-- src/highlightediting.js | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/highlightcommand.js b/src/highlightcommand.js index 9bb0878..2ad2bde 100644 --- a/src/highlightcommand.js +++ b/src/highlightcommand.js @@ -10,7 +10,7 @@ import Command from '@ckeditor/ckeditor5-core/src/command'; /** - * The highlight command. It is used by the {@link module:highlight/highlight~HighlightEditing highlight feature} + * The highlight command. It is used by the {@link module:highlight/highlightediting~HighlightEditing highlight feature} * to apply text highlighting. * * @extends module:core/command~Command @@ -64,5 +64,5 @@ export default class HighlightCommand extends Command { * * @observable * @readonly - * @member {undefined|String} HighlightCommand#value + * @member {undefined|String} module:highlight/highlightcommand~HighlightCommand#value */ diff --git a/src/highlightediting.js b/src/highlightediting.js index 5130abd..3c4b7dd 100644 --- a/src/highlightediting.js +++ b/src/highlightediting.js @@ -87,8 +87,9 @@ export default class HighlightEditing extends Plugin { * @property {String} class The class which is used to differentiate highlighters. * @property {String} title The user-readable title of the option. * @property {String} color Color used for highlighter. Should be coherent with CSS class definition. - * @property {'marker'|'pen'} type The type of highlighter. Either "marker" - will use #color as background name - * of the view element that will be used to represent the model element in the view. + * @property {'marker'|'pen'} type The type of highlighter: + * - "marker" - will use #color as background, + * - "pen" - will use #color as font color. */ /** @@ -96,7 +97,7 @@ export default class HighlightEditing extends Plugin { * * Read more in {@link module:highlight/highlightediting~HighlightEditingConfig}. * - * @member {module:highlight/highlightediting~HighlightEditingConfig} module:core/editor/editorconfig~EditorConfig#alignment + * @member {module:highlight/highlightediting~HighlightEditingConfig} module:core/editor/editorconfig~EditorConfig#highlight */ /** From 7de95c62f6c1e1cb13cdcacb483a8e53b0fe8e9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 9 Nov 2017 14:39:09 +0100 Subject: [PATCH 17/20] Other: Add workaround to allow highlighters in clipboard holder. --- src/highlightediting.js | 2 ++ tests/highlightediting.js | 5 +++++ 2 files changed, 7 insertions(+) diff --git a/src/highlightediting.js b/src/highlightediting.js index 3c4b7dd..d4532ed 100644 --- a/src/highlightediting.js +++ b/src/highlightediting.js @@ -47,6 +47,8 @@ export default class HighlightEditing extends Plugin { // Allow highlight attribute on all elements editor.document.schema.allow( { name: '$inline', attributes: 'highlight', inside: '$block' } ); + // Temporary workaround. See https://github.com/ckeditor/ckeditor5/issues/477. + editor.document.schema.allow( { name: '$inline', attributes: 'highlight', inside: '$clipboardHolder' } ); // Convert highlight attribute to a mark element with associated class. buildModelConverter() diff --git a/tests/highlightediting.js b/tests/highlightediting.js index 1cc689f..3c32090 100644 --- a/tests/highlightediting.js +++ b/tests/highlightediting.js @@ -30,6 +30,11 @@ describe( 'HighlightEditing', () => { editor.destroy(); } ); + it( 'should set proper schema rules', () => { + expect( doc.schema.check( { name: '$inline', attributes: 'highlight', inside: '$block' } ) ).to.be.true; + expect( doc.schema.check( { name: '$inline', attributes: 'highlight', inside: '$clipboardHolder' } ) ).to.be.true; + } ); + it( 'adds highlight commands', () => { expect( editor.commands.get( 'highlight' ) ).to.be.instanceOf( HighlightCommand ); } ); From 9fc067088df0be91fa07f1ac37c3a0a1b2c2cbad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 9 Nov 2017 14:41:10 +0100 Subject: [PATCH 18/20] Other: Simplify toAttribute converter method. --- src/highlightediting.js | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/highlightediting.js b/src/highlightediting.js index d4532ed..ce14c59 100644 --- a/src/highlightediting.js +++ b/src/highlightediting.js @@ -65,17 +65,11 @@ export default class HighlightEditing extends Plugin { .toAttribute( viewElement => { const viewClassNames = [ ...viewElement.getClassNames() ]; - if ( !viewClassNames.length ) { - return; + for ( const className of viewClassNames ) { + if ( configuredClasses.indexOf( className ) > -1 ) { + return { key: 'highlight', value: className }; + } } - - const highlightClassNames = viewClassNames.filter( className => configuredClasses.includes( className ) ); - - if ( !highlightClassNames.length ) { - return; - } - - return { key: 'highlight', value: highlightClassNames[ 0 ] }; } ); editor.commands.add( 'highlight', new HighlightCommand( editor ) ); From b18525f80f6d3ee44b76bcb664214b9dead4385e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20Go=C5=82aszewski?= Date: Thu, 9 Nov 2017 15:14:15 +0100 Subject: [PATCH 19/20] Other: Save precious ms by using generator directly. --- src/highlightediting.js | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/highlightediting.js b/src/highlightediting.js index ce14c59..1293657 100644 --- a/src/highlightediting.js +++ b/src/highlightediting.js @@ -63,9 +63,7 @@ export default class HighlightEditing extends Plugin { .for( data.viewToModel ) .fromElement( 'mark' ) .toAttribute( viewElement => { - const viewClassNames = [ ...viewElement.getClassNames() ]; - - for ( const className of viewClassNames ) { + for ( const className of viewElement.getClassNames() ) { if ( configuredClasses.indexOf( className ) > -1 ) { return { key: 'highlight', value: className }; } From dfca70c202168c5120b9c4ad60b019c9a3490656 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Szymon=20Kup=C5=9B?= Date: Fri, 10 Nov 2017 11:21:36 +0100 Subject: [PATCH 20/20] Added command execution examples to manual test. --- tests/manual/highlight.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/tests/manual/highlight.md b/tests/manual/highlight.md index ed702d1..f169f1e 100644 --- a/tests/manual/highlight.md +++ b/tests/manual/highlight.md @@ -6,4 +6,13 @@ You should be able to: - see different markers class -- manually invoke highlight command in console +- manually invoke highlight command in console: + +``` +editor.execute( 'highlight', { class: 'marker' } ); +editor.execute( 'highlight', { class: 'marker-green' } ); +editor.execute( 'highlight', { class: 'marker-pink' } ); + +editor.execute( 'highlight', { class: 'pen-red' } ); +editor.execute( 'highlight', { class: 'pen-blue' } ); +```