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

Commit

Permalink
Merge branch 'master' into t/44
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/mentionui.js
  • Loading branch information
jodator committed May 8, 2019
2 parents ced456e + 9ae7f30 commit 51b59c8
Show file tree
Hide file tree
Showing 4 changed files with 101 additions and 77 deletions.
2 changes: 1 addition & 1 deletion docs/_snippets/examples/chat-with-mentions.html
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
</ul>
<div class="chat__editor">
<p>
I agree with <a href="mwilson@example.com" class="mention" data-mention="@mwilson">@mwilson</a> 👍.
I agree with <a href="mailto:mwilson@example.com" class="mention" data-mention="@mwilson">@mwilson</a> 👍.
It’s so nice of you to always be providing a few options to try! I love
<a href="https://example.com/social/greek" class="mention" data-mention="#greek">#greek</a> cuisine with a modern twist,
this one will be perfect to try.
Expand Down
2 changes: 1 addition & 1 deletion docs/examples/chat-with-mentions.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ The HTML code of the application is listed below:
</ul>
<div class="chat__editor">
<p>
I agree with <a href="mwilson@example.com" class="mention" data-mention="@mwilson">@mwilson</a> 👍.
I agree with <a href="mailto:mwilson@example.com" class="mention" data-mention="@mwilson">@mwilson</a> 👍.
It’s so nice of you to always be providing a few options to try! I love
<a href="https://example.com/social/greek" class="mention" data-mention="#greek">#greek</a> cuisine with a modern twist,
this one will be perfect to try.
Expand Down
119 changes: 68 additions & 51 deletions src/mentionui.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,12 @@
import Plugin from '@ckeditor/ckeditor5-core/src/plugin';
import ButtonView from '@ckeditor/ckeditor5-ui/src/button/buttonview';
import Collection from '@ckeditor/ckeditor5-utils/src/collection';
import BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview';
import clickOutsideHandler from '@ckeditor/ckeditor5-ui/src/bindings/clickoutsidehandler';
import { keyCodes } from '@ckeditor/ckeditor5-utils/src/keyboard';
import Rect from '@ckeditor/ckeditor5-utils/src/dom/rect';
import CKEditorError from '@ckeditor/ckeditor5-utils/src/ckeditorerror';
import env from '@ckeditor/ckeditor5-utils/src/env';
import ContextualBalloon from '@ckeditor/ckeditor5-ui/src/panel/balloon/contextualballoon';

import TextWatcher from './textwatcher';

Expand Down Expand Up @@ -44,13 +44,6 @@ export default class MentionUI extends Plugin {
constructor( editor ) {
super( editor );

/**
* The balloon panel view containing the mention view.
*
* @type {module:ui/panel/balloon/balloonpanelview~BalloonPanelView}
*/
this.panelView = this._creatPanelView();

/**
* The mention view.
*
Expand All @@ -74,9 +67,19 @@ export default class MentionUI extends Plugin {
* @inheritDoc
*/
init() {
const editor = this.editor;

/**
* The contextual balloon plugin instance.
*
* @private
* @member {module:ui/panel/balloon/contextualballoon~ContextualBalloon}
*/
this._balloon = editor.plugins.get( ContextualBalloon );

// Key listener that handles navigation in mention view.
this.editor.editing.view.document.on( 'keydown', ( evt, data ) => {
if ( isHandledKey( data.keyCode ) && this.panelView.isVisible ) {
editor.editing.view.document.on( 'keydown', ( evt, data ) => {
if ( isHandledKey( data.keyCode ) && this._isUIVisible ) {
data.preventDefault();
evt.stop(); // Required for Enter key overriding.

Expand All @@ -93,20 +96,20 @@ export default class MentionUI extends Plugin {
}

if ( data.keyCode == keyCodes.esc ) {
this._hidePanelAndRemoveMarker();
this._hideUIAndRemoveMarker();
}
}
}, { priority: 'highest' } ); // Required to override the Enter key.

// Close the #panelView upon clicking outside of the plugin UI.
// Close the dropdown upon clicking outside of the plugin UI.
clickOutsideHandler( {
emitter: this.panelView,
contextElements: [ this.panelView.element ],
activator: () => this.panelView.isVisible,
callback: () => this._hidePanelAndRemoveMarker()
emitter: this._mentionsView,
activator: () => this._isUIVisible,
contextElements: [ this._balloon.view.element ],
callback: () => this._hideUIAndRemoveMarker()
} );

const feeds = this.editor.config.get( 'mention.feeds' );
const feeds = editor.config.get( 'mention.feeds' );

for ( const mentionDescription of feeds ) {
const feed = mentionDescription.feed;
Expand Down Expand Up @@ -146,24 +149,26 @@ export default class MentionUI extends Plugin {
super.destroy();

// Destroy created UI components as they are not automatically destroyed (see ckeditor5#1341).
this.panelView.destroy();
this._mentionsView.destroy();
}

/**
* Creates the {@link #panelView}.
*
* @private
* @returns {module:ui/panel/balloon/balloonpanelview~BalloonPanelView}
* @inheritDoc
*/
_creatPanelView() {
const panelView = new BalloonPanelView( this.editor.locale );

panelView.withArrow = false;
panelView.render();

this.editor.ui.view.body.add( panelView );
static get requires() {
return [ ContextualBalloon ];
}

return panelView;
/**
* Returns true when {@link #_mentionsView} is in the {@link module:ui/panel/balloon/contextualballoon~ContextualBalloon} and it is
* currently visible.
*
* @readonly
* @protected
* @type {Boolean}
*/
get _isUIVisible() {
return this._balloon.visibleView === this._mentionsView;
}

/**
Expand All @@ -179,8 +184,6 @@ export default class MentionUI extends Plugin {

this._items = new Collection();

this.panelView.content.add( mentionsView );

mentionsView.items.bindTo( this._items ).using( data => {
const { item, marker } = data;

Expand Down Expand Up @@ -223,7 +226,7 @@ export default class MentionUI extends Plugin {
const start = end.getShiftedBy( -matchedTextLength );
const range = model.createRange( start, end );

this._hidePanelAndRemoveMarker();
this._hideUIAndRemoveMarker();

editor.execute( 'mention', {
mention: item,
Expand Down Expand Up @@ -329,15 +332,15 @@ export default class MentionUI extends Plugin {
}

if ( this._items.length ) {
this._showPanel( mentionMarker );
this._showUI( mentionMarker );
} else {
this._hidePanelAndRemoveMarker();
this._hideUIAndRemoveMarker();
}
} );
} );

watcher.on( 'unmatched', () => {
this._hidePanelAndRemoveMarker();
this._hideUIAndRemoveMarker();
} );

return watcher;
Expand All @@ -357,31 +360,44 @@ export default class MentionUI extends Plugin {
}

/**
* Shows the {@link #panelView}. If the panel is already visible, it will reposition it.
* Shows the mentions balloon. If the panel is already visible, it will reposition it.
*
* @private
*/
_showPanel( markerMarker ) {
this.panelView.pin( this._getBalloonPanelPositionData( markerMarker, this.panelView.position ) );
this.panelView.show();
_showUI( markerMarker ) {
if ( this._isUIVisible ) {
// Update balloon position as the mention list view may change its size.
this._balloon.updatePosition( this._getBalloonPanelPositionData( markerMarker, this._mentionsView.position ) );
} else {
this._balloon.add( {
view: this._mentionsView,
position: this._getBalloonPanelPositionData( markerMarker, this._mentionsView.position ),
withArrow: false
} );
}

this._mentionsView.position = this._balloon.view.position;

this._mentionsView.selectFirst();
}

/**
* Hides the {@link #panelView} and removes the 'mention' marker from the markers collection.
* Hides the mentions balloon and removes the 'mention' marker from the markers collection.
*
* @private
*/
_hidePanelAndRemoveMarker() {
_hideUIAndRemoveMarker() {
if ( this.editor.model.markers.has( 'mention' ) ) {
this.editor.model.change( writer => writer.removeMarker( 'mention' ) );
}

this.panelView.unpin();
if ( this._isUIVisible ) {
this._balloon.remove( this._mentionsView );
}

// Make the last matched position on panel view undefined so the #_getBalloonPanelPositionData() method will return all positions
// on the next call.
this.panelView.position = undefined;
this.panelView.hide();
this._mentionsView.position = undefined;
}

/**
Expand Down Expand Up @@ -426,11 +442,11 @@ export default class MentionUI extends Plugin {
* Creates a position options object used to position the balloon panel.
*
* @param {module:engine/model/markercollection~Marker} mentionMarker
* @param {String|undefined} positionName The name of the last matched position name.
* @param {String|undefined} preferredPosition The name of the last matched position name.
* @returns {module:utils/dom/position~Options}
* @private
*/
_getBalloonPanelPositionData( mentionMarker, positionName ) {
_getBalloonPanelPositionData( mentionMarker, preferredPosition ) {
const editing = this.editor.editing;
const domConverter = editing.view.domConverter;
const mapper = editing.mapper;
Expand All @@ -454,15 +470,16 @@ export default class MentionUI extends Plugin {

return null;
},
positions: getBalloonPanelPositions( positionName )
positions: getBalloonPanelPositions( preferredPosition )
};
}
}

// Returns the balloon positions data callbacks.
//
// @param {String} preferredPosition
// @returns {Array.<module:utils/dom/position~Position>}
function getBalloonPanelPositions( positionName ) {
function getBalloonPanelPositions( preferredPosition ) {
const positions = {
// Positions the panel to the southeast of the caret rectangle.
'caret_se': targetRect => {
Expand Down Expand Up @@ -502,9 +519,9 @@ function getBalloonPanelPositions( positionName ) {
};

// Returns only the last position if it was matched to prevent the panel from jumping after the first match.
if ( positions.hasOwnProperty( positionName ) ) {
if ( positions.hasOwnProperty( preferredPosition ) ) {
return [
positions[ positionName ]
positions[ preferredPosition ]
];
}

Expand Down

0 comments on commit 51b59c8

Please sign in to comment.