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

Commit

Permalink
Feature: Added keepAttachedTo() method to the BalloonPanelView. Close…
Browse files Browse the repository at this point in the history
…s #170.
  • Loading branch information
oskarwrobel committed Apr 5, 2017
2 parents 248cfb5 + 3c55902 commit 101b465
Show file tree
Hide file tree
Showing 5 changed files with 321 additions and 22 deletions.
64 changes: 61 additions & 3 deletions src/panel/balloon/balloonpanelview.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,16 @@
* @module ui/panel/balloon/balloonpanelview
*/

/* globals document */

import View from '../../view';
import Template from '../../template';
import { getOptimalPosition } from '@ckeditor/ckeditor5-utils/src/dom/position';
import isRange from '@ckeditor/ckeditor5-utils/src/dom/isrange';
import isElement from '@ckeditor/ckeditor5-utils/src/lib/lodash/isElement';
import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';
import global from '@ckeditor/ckeditor5-utils/src/dom/global';

const toPx = toUnit( 'px' );
const defaultLimiterElement = global.document.body;

/**
* The balloon panel view class.
Expand Down Expand Up @@ -151,14 +153,70 @@ export default class BalloonPanelView extends View {
defaultPositions.ne,
defaultPositions.nw
],
limiter: document.body,
limiter: defaultLimiterElement,
fitInViewport: true
}, options );

const { top, left, name: position } = getOptimalPosition( positionOptions );

Object.assign( this, { top, left, position } );
}

/**
* Works the same way as {module:ui/panel/balloon/balloonpanelview~BalloonPanelView.attachTo}
* except that the position of the panel is continuously updated when any ancestor of the
* {@link module:utils/dom/position~Options#target} or {@link module:utils/dom/position~Options#limiter}
* is being scrolled or when the browser window is being resized.
*
* Thanks to this, the panel always sticks to the {@link module:utils/dom/position~Options#target}.
*
* See https://github.com/ckeditor/ckeditor5-ui/issues/170.
*
* @param {module:utils/dom/position~Options} options Positioning options compatible with
* {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is
* {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.
*/
keepAttachedTo( options ) {
// First we need to attach the balloon panel to the target element.
this.attachTo( options );

const limiter = options.limiter || defaultLimiterElement;
let target = null;

// We need to take HTMLElement related to the target if it is possible.
if ( isElement( options.target ) ) {
target = options.target;
} else if ( isRange( options.target ) ) {
target = options.target.commonAncestorContainer;
}

// Then we need to listen on scroll event of eny element in the document.
this.listenTo( global.document, 'scroll', ( evt, domEvt ) => {
// We need to update position if scrolled element contains related to the balloon elements.
if ( ( target && domEvt.target.contains( target ) ) || domEvt.target.contains( limiter ) ) {
this.attachTo( options );
}
}, { useCapture: true } );

// We need to listen on window resize event and update position.
this.listenTo( global.window, 'resize', () => this.attachTo( options ) );

// After all we need to clean up the listeners.
this.once( 'change:isVisible', () => {
this.stopListening( global.document, 'scroll' );
this.stopListening( global.window, 'resize' );
} );
}

/**
* @inheritDoc
*/
destroy() {
this.stopListening( global.document, 'scroll' );
this.stopListening( global.window, 'resize' );

return super.destroy();
}
}

/**
Expand Down
51 changes: 51 additions & 0 deletions tests/manual/tickets/170/1.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<div class="container-outer">
<div class="container-inner">
<div>
<div id="editor-attach">
<p>Balloon is attached to the <strong>TARGET</strong> element.</p>
</div>
</div>

<div>
<div id="editor-stick">
<p>Balloon sticks to the <strong>TARGET</strong> element.</p>
</div>
</div>
</div>
</div>

<style>
body {
height: 100%;
}

.ck-balloon-panel {
padding: 2em;
}

.ck-editor__editable {
max-height: 300px;
}

.ck-editor__editable p {
margin: 470px 0;
}

.container-outer {
height: 500px;
width: 750px;
overflow: scroll;
}

.container-inner {
padding: 500px 30px 30px;
display: flex;
width: 1000px;
height: 2000px;
background: #e1e1e1;
}

.container-inner > div {
margin: 0 20px;
}
</style>
65 changes: 65 additions & 0 deletions tests/manual/tickets/170/1.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/**
* @license Copyright (c) 2003-2017, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

/* globals window, document, console:false */

import ClassicEditor from '@ckeditor/ckeditor5-editor-classic/src/classic';
import ArticlePresets from '@ckeditor/ckeditor5-presets/src/article';
import BalloonPanelView from '@ckeditor/ckeditor5-ui/src/panel/balloon/balloonpanelview';

// Set initial scroll for the outer container element.
document.querySelector( '.container-outer' ).scrollTop = 450;

// Init editor with balloon attached to the target element.
ClassicEditor.create( document.querySelector( '#editor-attach' ), {
plugins: [ ArticlePresets ],
toolbar: [ 'bold', 'italic', 'undo', 'redo' ]
} )
.then( editor => {
const panel = new BalloonPanelView();

panel.element.innerHTML = 'Balloon content.';
editor.ui.view.body.add( panel );

editor.ui.view.element.querySelector( '.ck-editor__editable' ).scrollTop = 360;

panel.init().then( () => {
panel.attachTo( {
target: editor.ui.view.element.querySelector( '.ck-editor__editable p strong' ),
limiter: editor.ui.view.editableElement
} );
} );

window.attachEditor = editor;
} )
.catch( err => {
console.error( err.stack );
} );

// Init editor with balloon sticked to the target element.
ClassicEditor.create( document.querySelector( '#editor-stick' ), {
plugins: [ ArticlePresets ],
toolbar: [ 'bold', 'italic', 'undo', 'redo' ]
} )
.then( editor => {
const panel = new BalloonPanelView();

panel.element.innerHTML = 'Balloon content.';
editor.ui.view.body.add( panel );

editor.ui.view.element.querySelector( '.ck-editor__editable' ).scrollTop = 360;

panel.init().then( () => {
panel.keepAttachedTo( {
target: editor.ui.view.element.querySelector( '.ck-editor__editable p strong' ),
limiter: editor.ui.view.editableElement
} );
} );

window.stickEditor = editor;
} )
.catch( err => {
console.error( err.stack );
} );
4 changes: 4 additions & 0 deletions tests/manual/tickets/170/1.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
## BalloonPanelView `attachTo` vs `keepAttachedTo`

Scroll editable elements and container (horizontally as well). Balloon in the left editor should float but balloon in the
right editor should stick to the target element.
Loading

0 comments on commit 101b465

Please sign in to comment.