Open piloos opened 4 years ago
With the assumption that the menuContainer
should be a close wrapper around the Tribute-attached element, I found the following issues in the two different code paths (the one for input
/textarea
and the one for contenteditable
)
input
/textarea
In this code path, the coordinates are calculated relative (menu vs. element) and then converted to absolute coordinates. When using a menuContainer
, the coordinates should remain relative. No need to take into account the position of the element relative to the viewport and the position of the viewport relative to the window:
diff --git a/src/TributeRange.js b/src/TributeRange.js
index e2756dc..c93ddf1 100644
--- a/src/TributeRange.js
+++ b/src/TributeRange.js
@@ -496,16 +497,16 @@ class TributeRange {
let windowLeft = (window.pageXOffset || doc.scrollLeft) - (doc.clientLeft || 0)
let windowTop = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0)
- let top = 0;
- let left = 0;
+ let top = 0
+ let left = 0
if (this.menuContainerIsBody) {
- top = rect.top;
- left = rect.left;
+ top = rect.top + windowTop
+ left = rect.left + windowLeft
}
let coordinates = {
- top: top + windowTop + span.offsetTop + parseInt(computed.borderTopWidth) + parseInt(computed.fontSize) - element.scrollTop,
- left: left + windowLeft + span.offsetLeft + parseInt(computed.borderLeftWidth)
+ top: top + span.offsetTop + parseInt(computed.borderTopWidth) + parseInt(computed.fontSize) - element.scrollTop,
+ left: left + span.offsetLeft + parseInt(computed.borderLeftWidth)
}
let windowWidth = window.innerWidth
In this code path, the coordinates are calculated relative to the current viewport.
In case of using menuContainer
, we need to change the reference to relative vs. menuConainer
by subtracting menuContainer
's position relative to the viewport.
In case of not using menuContainer
we need to adjust for the viewport not being at the top-left of the windown (adding windowLeft
/windowTop
):
diff --git a/src/TributeRange.js b/src/TributeRange.js
index e2756dc..c93ddf1 100644
--- a/src/TributeRange.js
+++ b/src/TributeRange.js
@@ -569,10 +570,25 @@ class TributeRange {
let left = rect.left
let top = rect.top
+ if (!this.menuContainerIsBody) {
+ // coordinates are referenced absolutely to the viewport position
+ // we need to make them relative by subtracting the menuContainers viewport position
+ let menuContainerRect = this.tribute.menuContainer.getBoundingClientRect()
+ left = left - menuContainerRect.left
+ top = top - menuContainerRect.top
+ }
+ else {
+ // coordinates are referenced absolutely to the viewport position
+ // we need to take the viewport position into account
+ left = left + windowLeft
+ top = top + windowTop
+ }
+
let coordinates = {
- left: left + windowLeft,
- top: top + rect.height + windowTop
+ left: left,
+ top: top + rect.height
}
+
let windowWidth = window.innerWidth
let windowHeight = window.innerHeight
@@ -612,11 +628,6 @@ class TributeRange {
delete coordinates.bottom
}
- if (!this.menuContainerIsBody) {
- coordinates.left = coordinates.left ? coordinates.left - this.tribute.menuContainer.offsetLeft : coordinates.left
- coordinates.top = coordinates.top ? coordinates.top - this.tribute.menuContainer.offsetTop : coordinates.top
- }
-
return coordinates
}
With these calculations and with isMenuOffScreen
disabled, I get correct positioning in scrollable div
s.
@mrsweaters , can you confirm my assumptions and my possible fix. If this is the correct way forward, I can check what is going wrong with the isMenuOffScreen
check.
I can confirm that I'm experiencing the same issues described at 3 and 4. Thank you @piloos for the detailed research into the problem, and the proposed solutions. I hope they'll be incorporated into the library.
Meanwhile I'll give your branch a try. Hope that's all right. Thank you!
@piloos This looks like it would be an improvement to me. Would you mind making a PR for this?
@mrsweaters , sure. Can you just quickly confirm or reject my assumptions:
The menuContainer
should be a close wrapper around the tribute-attached element? Eg. in a modal, it should be a div
directly around the the tribute-attached element. It should not be the complete modal-body. OR should this not matter? We could make it resilient enough. In this case the menuContainer
should just be in the same scrolling group.
What is the idea/algorithm behind the isMenuOffScreen
check and possible repositioning?
I have this exact same issue. @piloos, did you ever solve this issue apart from your recommended changes?
I have this exact same issue. @piloos, did you ever solve this issue apart from your recommended changes?
@ivanbozic I am currently still using my personal branch https://github.com/piloos/tribute/tree/issue-430. This branch hasn't been updated with changes on master (if any?), but is still working...
Did you think about making a PR for this? I see there hasn't been any new releases since March. @mrsweaters, are you still interested in taking a look at this and merging into a new release?
@piloos @ivanbozic Sure thing! If you submit a PR i'll review it and get it merged. Sorry I've been a bit distracted recently.
No problem @mrsweaters, life does tend to get in the way of things. 😊
@piloos, I'll pull your personal branch and test out whether it solves my use case and get back to you here. Are you fine with submitting the PR / need any help on that?
@mrsweaters @ivanbozic , in my branch the complete heuristic to determine if the popup is placed correctly is commented out completely. Since I just started a new business, I can't really work on it now.
How can we reproduce this bug?
Use Tribute on a
contenteditable
div which is present in a scrollable divTribute version 5.1.2
What did you expect to happen?
Using
menuContainer
I should be able to get thetribute-container
correctly positioned somewhere inside the scrollable div so that it scrolls together with thecontenteditable
element where it was attached to.What happened instead?
The
tribute-container
did appear inside the scrollable div, but does not appear at the right location when typing '@'.Link jsfiddle https://jsfiddle.net/piloos/t70szjv4/
More info and questions
I have made a comparison between 4 situations:
Tribute attached to textarea within a scrollable div. The complete scrollable div is used as
menuContainer
tribute-container
is positioned reliably, but at the wrong position (top of the scrollable div).Tribute attached to textarea within a scrollable div, but a wrapper around the textarea is used as
menuContainer
Tribute attached to contenteditable within a scrollable div. The complete scrollable div is used as
menuContainer
tribute-container
is positioned reliably, but at the wrong position (top of the scrollable div).Tribute attached to contenteditable within a scrollable div, but a wrapper around the
contenteditable
is used asmenuContainer
tribute-container
From these tests I have the following findings:
When using the
menuContainer
option, it should be a reference to an element as close to the Tribute-attached item as possible to ensure correct positioning of the absolute positionedtribute-container
. Correct assumption?The Tribute library tries to do its best to find a suitable spot to place the
tribute-container
within the viewable area of the DOM. Correct? When I add some logging to the Tribute library, I see that in the bug-case, the library constantly recalculates the location...