Skip to content
This repository has been archived by the owner on Jun 26, 2020. It is now read-only.

Commit

Permalink
Merge pull request #2 from ckeditor/t/1
Browse files Browse the repository at this point in the history
Feature: Initial implementation of highlight editing. Closes #1.
  • Loading branch information
szymonkups authored Nov 10, 2017
2 parents f52e425 + dfca70c commit 5c687cf
Show file tree
Hide file tree
Showing 12 changed files with 678 additions and 0 deletions.
10 changes: 10 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,18 @@
"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-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",
Expand Down
36 changes: 36 additions & 0 deletions src/highlight.js
Original file line number Diff line number Diff line change
@@ -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';
}
}
68 changes: 68 additions & 0 deletions src/highlightcommand.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/**
* @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. It is used by the {@link module:highlight/highlightediting~HighlightEditing highlight feature}
* to apply text highlighting.
*
* @extends module:core/command~Command
*/
export default class HighlightCommand extends Command {
/**
* @inheritDoc
*/
refresh() {
const doc = this.editor.document;

this.value = doc.selection.getAttribute( 'highlight' );
this.isEnabled = doc.schema.checkAttributeInSelection( doc.selection, 'highlight' );
}

/**
* Executes the command.
*
* @protected
* @param {Object} [options] Options for the executed command.
* @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;

// Do not apply highlight no collapsed selection.
if ( selection.isCollapsed ) {
return;
}

doc.enqueueChanges( () => {
const ranges = doc.schema.getValidRanges( selection.getRanges(), 'highlight' );
const batch = options.batch || doc.batch();

for ( const range of ranges ) {
if ( options.class ) {
batch.setAttribute( range, 'highlight', options.class );
} else {
batch.removeAttribute( range, 'highlight' );
}
}
} );
}
}

/**
* Holds current highlight class. If there is no highlight in selection then value will be undefined.
*
* @observable
* @readonly
* @member {undefined|String} module:highlight/highlightcommand~HighlightCommand#value
*/
123 changes: 123 additions & 0 deletions src/highlightediting.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* @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 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 {
/**
* @inheritDoc
*/
constructor( editor ) {
super( 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' }
] );
}

/**
* @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' } );
// 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()
.for( data.modelToView, editing.modelToView )
.fromAttribute( 'highlight' )
.toElement( data => new AttributeElement( 'mark', { class: data } ) );

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 => {
for ( const className of viewElement.getClassNames() ) {
if ( configuredClasses.indexOf( className ) > -1 ) {
return { key: 'highlight', value: className };
}
}
} );

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:
* - "marker" - will use #color as background,
* - "pen" - will use #color as font color.
*/

/**
* 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#highlight
*/

/**
* 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 `<mark>` element with defined background color.
* - 'pen' - rendered as `<mark>` 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~HeadingOption>} module:heading/heading~HeadingConfig#options
*/
33 changes: 33 additions & 0 deletions src/highlightui.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* @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';
}
}
39 changes: 39 additions & 0 deletions tests/highlight.js
Original file line number Diff line number Diff line change
@@ -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 ] );
} );
} );
Loading

0 comments on commit 5c687cf

Please sign in to comment.