ソースを参照

Limited balloon panel updaing on scroll.

Oskar Wróbel 8 年 前
コミット
28724204b6

+ 19 - 8
packages/ckeditor5-ui/src/panel/balloon/balloonpanelview.js

@@ -15,6 +15,7 @@ import { getOptimalPosition } from '@ckeditor/ckeditor5-utils/src/dom/position';
 import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';
 import toUnit from '@ckeditor/ckeditor5-utils/src/dom/tounit';
 
 
 const toPx = toUnit( 'px' );
 const toPx = toUnit( 'px' );
+const defaultLimiterElement = document.body;
 
 
 /**
 /**
  * The balloon panel view class.
  * The balloon panel view class.
@@ -151,7 +152,7 @@ export default class BalloonPanelView extends View {
 				defaultPositions.ne,
 				defaultPositions.ne,
 				defaultPositions.nw
 				defaultPositions.nw
 			],
 			],
-			limiter: document.body,
+			limiter: defaultLimiterElement,
 			fitInViewport: true
 			fitInViewport: true
 		}, options );
 		}, options );
 
 
@@ -162,22 +163,32 @@ export default class BalloonPanelView extends View {
 
 
 	/**
 	/**
 	 * Works exactly the same as {module:ui/panel/balloon/balloonpanelview~BalloonPanelView.attachTo} with one exception.
 	 * Works exactly the same as {module:ui/panel/balloon/balloonpanelview~BalloonPanelView.attachTo} with one exception.
-	 * Position of attached panel is constantly updated when any of element in document is scrolled. Thanks to this
-	 * panel always sticks to the target element. See #170.
+	 * Position of attached panel is constantly updated when any of parents of the target or limiter elements are scrolled
+	 * or when browser window is resized. Thanks to this panel always sticks to the target element. See #170.
 	 *
 	 *
 	 * @param {module:utils/dom/position~Options} options Positioning options compatible with
 	 * @param {module:utils/dom/position~Options} options Positioning options compatible with
 	 * {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is
 	 * {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is
 	 * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.
 	 * {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}.
 	 */
 	 */
-	stickTo( options ) {
-		// First we need to attach the balloon panel to target element.
+	keepAttachedTo( options ) {
+		// First we need to attach the balloon panel to the target element.
 		this.attachTo( options );
 		this.attachTo( options );
 
 
-		// Then we need to listen to scroll of eny element in the document and update position of the balloon panel.
-		this.listenTo( document, 'scroll', () => this.attachTo( options ), { useCapture: true } );
+		const target = options.target;
+		const limiter = options.limiter || defaultLimiterElement;
+
+		// Then we need to listen on scroll event of eny element in the document.
+		this.listenTo( document, 'scroll', ( evt, domEvt ) => {
+			// And update position if scrolled element contains related to the balloon elements.
+			if ( domEvt.target.contains( target ) || domEvt.target.contains( limiter ) ) {
+				this.attachTo( options );
+			}
+		}, { useCapture: true } );
 
 
 		// After all we need to clean up the listener.
 		// After all we need to clean up the listener.
-		this.once( 'change:isVisible', () => this.stopListening( document, 'scroll' ) );
+		this.once( 'change:isVisible', () => {
+			this.stopListening( document, 'scroll' );
+		} );
 	}
 	}
 }
 }
 
 

+ 14 - 7
packages/ckeditor5-ui/tests/panel/balloon/balloonpanelview.js

@@ -410,26 +410,27 @@ describe( 'BalloonPanelView', () => {
 		} );
 		} );
 	} );
 	} );
 
 
-	describe( 'stickTo()', () => {
-		let attachToSpy, target, limiter;
+	describe( 'keepAttachedTo()', () => {
+		let attachToSpy, target, limiter, notRelatedElement;
 
 
 		beforeEach( () => {
 		beforeEach( () => {
 			attachToSpy = testUtils.sinon.spy( view, 'attachTo' );
 			attachToSpy = testUtils.sinon.spy( view, 'attachTo' );
 			limiter = document.createElement( 'div' );
 			limiter = document.createElement( 'div' );
 			target = document.createElement( 'div' );
 			target = document.createElement( 'div' );
+			notRelatedElement = document.createElement( 'div' );
 
 
 			document.body.appendChild( limiter );
 			document.body.appendChild( limiter );
-			document.body.appendChild( target );
+			document.body.appendChild( notRelatedElement );
 		} );
 		} );
 
 
 		afterEach( () => {
 		afterEach( () => {
 			attachToSpy.restore();
 			attachToSpy.restore();
 			limiter.remove();
 			limiter.remove();
-			target.remove();
+			notRelatedElement.remove();
 		} );
 		} );
 
 
-		it( 'should attach balloon to the target constantly when any of element in document is scrolled', () => {
-			view.stickTo( { target, limiter } );
+		it( 'should attach balloon to the target constantly when any of element containing target element is scrolled', () => {
+			view.keepAttachedTo( { target, limiter } );
 
 
 			expect( attachToSpy.calledOnce ).to.true;
 			expect( attachToSpy.calledOnce ).to.true;
 			expect( attachToSpy.lastCall.args[ 0 ] ).to.deep.equal( { target, limiter } );
 			expect( attachToSpy.lastCall.args[ 0 ] ).to.deep.equal( { target, limiter } );
@@ -443,10 +444,16 @@ describe( 'BalloonPanelView', () => {
 
 
 			expect( attachToSpy.calledThrice ).to.true;
 			expect( attachToSpy.calledThrice ).to.true;
 			expect( attachToSpy.lastCall.args[ 0 ] ).to.deep.equal( { target, limiter } );
 			expect( attachToSpy.lastCall.args[ 0 ] ).to.deep.equal( { target, limiter } );
+
+			notRelatedElement.dispatchEvent( new Event( 'scroll' ) );
+
+			// Nothing's changed.
+			expect( attachToSpy.calledThrice ).to.true;
+			expect( attachToSpy.lastCall.args[ 0 ] ).to.deep.equal( { target, limiter } );
 		} );
 		} );
 
 
 		it( 'should stop attach when balloon is hidden', () => {
 		it( 'should stop attach when balloon is hidden', () => {
-			view.stickTo( { target, limiter } );
+			view.keepAttachedTo( { target, limiter } );
 
 
 			expect( attachToSpy.calledOnce ).to.true;
 			expect( attachToSpy.calledOnce ).to.true;