-
Notifications
You must be signed in to change notification settings - Fork 18
Added keepAttachedTo
method to the BalloonPanelView.
#172
Conversation
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 } ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same should be for resize
event.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that's right.
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 } ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This useCapture
that you put in here makes the listener very generic. Because of that, events fired in the document
will trigger the callback in the capture phase. And since the listener is attached to document
, every single scroll event coming from whatever element with overflow: scroll
will trigger it. Such element doesn't even need to have anything in common with CKEditor. document
aggregates all events with useCapture
because it's a root.
For one thing, it's OK. Because the balloon will re–position when elements with overflow: scroll
will scroll. But still, it's too much. We need to filter out the events that have no impact on balloon panel, which are events comming from elements that are neither:
- the ancestor of the ck-body (or wherever the balloon is located in DOM),
- nor the ancestor of the target in
attachTo()
.
Node.contains()
will help a lot.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I limited updating position to scroll events from elements containing target
and limiter
elements.
@@ -409,6 +409,55 @@ describe( 'BalloonPanelView', () => { | |||
} ); | |||
} ); | |||
} ); | |||
|
|||
describe( 'stickTo()', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
We need a test to verify that use of
useCapture
makes sense and actually works. -
We need a manual test for
BalloonPanel
because it's getting quite complex. I think we could develop it on top of http://localhost:8125/ckeditor5-ui/tests/manual/tickets/126/1.html.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prepared dedicated test for this ticket: http://localhost:8125/ckeditor5-ui/tests/manual/tickets/170/1.html this test compares attachTo
vs keepAttachedTo
.
* {@link module:utils/dom/position~getOptimalPosition}. Default `positions` array is | ||
* {@link module:ui/panel/balloon/balloonpanelview~BalloonPanelView.defaultPositions}. | ||
*/ | ||
stickTo( options ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we should reference the attachTo
method in this name because it's essentially the same thing. Like keepAttachedTo
albo attachPermanentlyTo
.
This could even become a parameter of attachTo
options. I wonder which naming/grouping strategy is the best /cc @Reinmar.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed to keepAttachedTo
.
}, { useCapture: true } ); | ||
|
||
// We need to listen on window resize event and update position. | ||
this.listenTo( window, 'resize', () => this.attachTo( options ) ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use https://github.com/ckeditor/ckeditor5-utils/blob/master/src/dom/global.js#L1-L26 instead. It helps a lot stubbing things when writing tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
this.once( 'change:isVisible', () => this.stopListening( document, 'scroll' ) ); | ||
this.once( 'change:isVisible', () => { | ||
this.stopListening( document, 'scroll' ); | ||
this.stopListening( window, 'resize' ); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use https://github.com/ckeditor/ckeditor5-utils/blob/master/src/dom/global.js#L1-L26 instead. It helps a lot stubbing things when writing tests.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor fixes needed.
The more important question is: does the new method get the work done for you @oskarwrobel?
Also: I wonder if method renaming would make sense: attachTo()
=> setPosition()
, keepAttachedTo()
=> attachTo()
?
this.attachTo( options ); | ||
|
||
const target = options.target; | ||
const limiter = options.limiter || defaultLimiterElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This line lacks test coverage.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
tests/manual/tickets/170/1.html
Outdated
<p></p> | ||
<p></p> | ||
<p></p> | ||
<p>Balloon is attached to the <strong>TARGET</strong> element.</p> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Please use position: absolute
or simply large margin
and drop these paragraphs. It just looks weird :D
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
tests/manual/tickets/170/1.js
Outdated
import Template from '@ckeditor/ckeditor5-ui/src/template'; | ||
|
||
// Content of the balloon panel. | ||
class BalloonContentView extends View { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
KISS. Add simple styles
.ck-balloon-panel {
padding: 2em;
}
and then balloonPanel.innerHTML = 'Balloon'
. It should be about what is important in that particular test case, not about balloon content, view nesting and the such. It's just a noise.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
expect( attachToSpy.lastCall.args[ 0 ] ).to.deep.equal( { target, limiter } ); | ||
} ); | ||
|
||
it( 'should stop attach when balloon is hidden', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this test could be merged with 'should stop attach when balloon is hidden'
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
expect( attachToSpy.lastCall.args[ 0 ] ).to.deep.equal( { target, limiter } ); | ||
} ); | ||
|
||
it( 'should stop attach when balloon is hidden', () => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
s/attach/attaching,
s/balloon/the balloon,
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
/** | ||
* 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 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. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Full link to the issue would be safer. We had code moving between repos and such hashes became outdated more than once already.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Afterthought: Scroll/resize listeners should be killed on component |
I was thinking about one |
// Then we need to listen on scroll event of eny element in the document. | ||
this.listenTo( global.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 ) ) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would happen if options.target
or options.limiter
are Range
or ClientRect
? I suppose it's not gonna work and it may throw errors.
For the DOM Range
we can do it by obtaining range ancestor Node
. For ClientRect
, there's nothing we can do because it's an abstract geometric entity, I guess. Right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done
stickTo
method to the BalloonPanelView.keepAttachedTo
method to the BalloonPanelView.
…om DOM "scroll" listener.
OK. It's R+ but since the master is locked we postpone the merge. |
Suggested merge commit message (convention)
Feature: Added
keepAttachedTo()
method to theBalloonPanelView
. Closes ckeditor/ckeditor5#5320.Follow-ups: