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

Merged WidgetEngine into Widget #5

Merged
merged 1 commit into from
Apr 3, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 28 additions & 9 deletions src/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,38 +8,57 @@
*/

import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import WidgetEngine from './widgetengine';
import MouseObserver from '@ckeditor/ckeditor5-engine/src/view/observer/mouseobserver';
import ModelRange from '@ckeditor/ckeditor5-engine/src/model/range';
import ModelSelection from '@ckeditor/ckeditor5-engine/src/model/selection';
import ModelElement from '@ckeditor/ckeditor5-engine/src/model/element';
import ViewEditableElement from '@ckeditor/ckeditor5-engine/src/view/editableelement';
import RootEditableElement from '@ckeditor/ckeditor5-engine/src/view/rooteditableelement';
import { isWidget } from './utils';
import { isWidget, WIDGET_SELECTED_CLASS_NAME, getLabel } from './utils';
import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';

import '../theme/theme.scss';

/**
* The widget plugin.
* Registers model to view selection converter for editing pipeline. It is hooked after default selection conversion.
* If converted selection is placed around widget element, selection is marked as fake. Additionally, proper CSS class
* is added to indicate that widget has been selected.
* Adds default {@link module:engine/view/document~Document#event:mousedown mousedown} handling on widget elements.
*
* @extends module:core/plugin~Plugin.
*/
export default class Widget extends Plugin {
/**
* @inheritDoc
*/
static get requires() {
return [ WidgetEngine ];
}

/**
* @inheritDoc
*/
init() {
const viewDocument = this.editor.editing.view;

let previouslySelected;

// Model to view selection converter.
// Converts selection placed over widget element to fake selection
this.editor.editing.modelToView.on( 'selection', ( evt, data, consumable, conversionApi ) => {
// Remove selected class from previously selected widget.
if ( previouslySelected && previouslySelected.hasClass( WIDGET_SELECTED_CLASS_NAME ) ) {
previouslySelected.removeClass( WIDGET_SELECTED_CLASS_NAME );
}

const viewSelection = conversionApi.viewSelection;

// Check if widget was clicked or some sub-element.
const selectedElement = viewSelection.getSelectedElement();

if ( !selectedElement || !isWidget( selectedElement ) ) {
return;
}

viewSelection.setFake( true, { label: getLabel( selectedElement ) } );
selectedElement.addClass( WIDGET_SELECTED_CLASS_NAME );
previouslySelected = selectedElement;
}, { priority: 'low' } );

// If mouse down is pressed on widget - create selection over whole widget.
viewDocument.addObserver( MouseObserver );
this.listenTo( viewDocument, 'mousedown', ( ...args ) => this._onMousedown( ...args ) );
Expand Down
50 changes: 0 additions & 50 deletions src/widgetengine.js

This file was deleted.

60 changes: 59 additions & 1 deletion tests/widget.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import ViewEditable from '@ckeditor/ckeditor5-engine/src/view/editableelement';
import DomEventData from '@ckeditor/ckeditor5-engine/src/view/observer/domeventdata';
import AttributeContainer from '@ckeditor/ckeditor5-engine/src/view/attributeelement';
import { setData as setModelData, getData as getModelData } from '@ckeditor/ckeditor5-engine/src/dev-utils/model';
import { getData as getViewData } from '@ckeditor/ckeditor5-engine/src/dev-utils/view';
import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';

/* global document */
Expand All @@ -37,6 +38,10 @@ describe( 'Widget', () => {
doc.schema.registerItem( 'nested' );
doc.schema.allow( { name: '$inline', inside: 'nested' } );
doc.schema.allow( { name: 'nested', inside: 'widget' } );
doc.schema.registerItem( 'editable' );
doc.schema.allow( { name: '$inline', inside: 'editable' } );
doc.schema.allow( { name: 'editable', inside: 'widget' } );
doc.schema.allow( { name: 'editable', inside: '$root' } );

buildModelConverter().for( editor.editing.modelToView )
.fromElement( 'paragraph' )
Expand All @@ -48,7 +53,7 @@ describe( 'Widget', () => {
const b = new AttributeContainer( 'b' );
const div = new ViewContainer( 'div', null, b );

return toWidget( div );
return toWidget( div, { label: 'element label' } );
} );

buildModelConverter().for( editor.editing.modelToView )
Expand All @@ -58,6 +63,10 @@ describe( 'Widget', () => {
buildModelConverter().for( editor.editing.modelToView )
.fromElement( 'nested' )
.toElement( () => new ViewEditable( 'figcaption', { contenteditable: true } ) );

buildModelConverter().for( editor.editing.modelToView )
.fromElement( 'editable' )
.toElement( () => new ViewEditable( 'figcaption', { contenteditable: true } ) );
} );
} );

Expand Down Expand Up @@ -145,6 +154,55 @@ describe( 'Widget', () => {
expect( getModelData( doc ) ).to.equal( '[<widget></widget>]' );
} );

it( 'should apply fake view selection if model selection is on widget element', () => {
setModelData( doc, '[<widget>foo bar</widget>]' );

expect( getViewData( viewDocument ) ).to.equal(
'[<div class="ck-widget ck-widget_selected" contenteditable="false">foo bar<b></b></div>]'
);
expect( viewDocument.selection.isFake ).to.be.true;
} );

it( 'should use element\'s label to set fake selection if one is provided', () => {
setModelData( doc, '[<widget>foo bar</widget>]' );

expect( viewDocument.selection.fakeSelectionLabel ).to.equal( 'element label' );
} );

it( 'fake selection should be empty if widget is not selected', () => {
setModelData( doc, '<widget>foo bar</widget>' );

expect( viewDocument.selection.fakeSelectionLabel ).to.equal( '' );
} );

it( 'should toggle selected class', () => {
setModelData( doc, '[<widget>foo</widget>]' );

expect( getViewData( viewDocument ) ).to.equal(
'[<div class="ck-widget ck-widget_selected" contenteditable="false">foo<b></b></div>]'
);

doc.enqueueChanges( () => {
doc.selection.collapseToStart();
} );

expect( getViewData( viewDocument ) ).to.equal(
'[]<div class="ck-widget" contenteditable="false">foo<b></b></div>'
);
} );

it( 'should do nothing when selection is placed in other editable', () => {
setModelData( doc, '<widget><editable>foo bar</editable></widget><editable>[baz]</editable>' );

expect( getViewData( viewDocument ) ).to.equal(
'<div class="ck-widget" contenteditable="false">' +
'<figcaption contenteditable="true">foo bar</figcaption>' +
'<b></b>' +
'</div>' +
'<figcaption contenteditable="true">{baz}</figcaption>'
);
} );

describe( 'keys handling', () => {
describe( 'delete and backspace', () => {
test(
Expand Down
97 changes: 0 additions & 97 deletions tests/widgetengine.js

This file was deleted.