'Open Safari context menu BELOW text selection
I need to show a toolbar ABOVE a text selection in an editor. That's easy. Unfortunately Safari on iOS seems to prefer opening its copy/paste/formatting context menu above text selections as well. But Facebook seems to have figured out a way to avoid this:
But after spending almost two hours with a remote debugger trying to figure out how the heck they achieved this, I'm giving up. I just can't figure it out.
I have built a very barebone prototype which displays a toolbar above a text selection (attached below). This works fine on my MacBook (using Chrome in this case):
But as the next screenshot demonstrates, Safari's context menu on an iPad conflicts with my toolbar. They open in almost the same position, making it impossible to interact with my toolbar.
I'm really keen to know how Facebook solved it. Any help would be greatly appreciated. Thank you :-)
Barebone prototype:
var toolbar = document.querySelector("div.Toolbar");
toolbar.style.display = "none";
document.onselectionchange = function()
{
var sel = getSelection();
if (sel.rangeCount > 0)
{
var ran = sel.getRangeAt(0);
if (ran.collapsed === false)
{
var rect = ran.getBoundingClientRect();
var rectTop = rect.top;
var rectCenter = rect.left + (rect.width / 2);
toolbar.style.display = "";
toolbar.style.left = (rectCenter - (toolbar.offsetWidth / 2)) + "px";
toolbar.style.top = (rectTop - toolbar.offsetHeight) + "px";
if (parseFloat(toolbar.style.top) < 0)
{
toolbar.style.top = "0px";
}
if (parseFloat(toolbar.style.left) < 0)
{
toolbar.style.left = "0px";
}
}
else
{
toolbar.style.display = "none";
}
}
else
{
toolbar.style.display = "none";
}
}
body
{
padding: 2em;
}
div.Toolbar
{
display: inline-block;
position: fixed;
background: orange;
box-shadow: 0px 0px 0.2em #333;
padding: 0.3em;
}
div[contenteditable="true"]
{
width: 600px;
height: 300px;
border: 1px solid gray;
padding: 0.5em;
}
<div class="Toolbar">
Buttons go here
</div>
<div contenteditable="true">
Try selecting some of this text in the editor. The toolbar shows up above the text selection as intended. But on an iPad we also get Safari's context menu which opens on top of our custom toolbar. Facebook has successfully solved this somehow - but how the heck did they do it?
</div>
Solution 1:[1]
I found the solution.
Quick answer: Add a "button" with an onclick or onmousedown handler.
Expanding on the solution:
I decided to go ahead with my project and simply attach the toolbar at the top of the viewport instead. But as the project progressed, I wanted to take a second shot at this problem - and this time the Context Menu did not overlap with my custom toolbar. It turned out that the mere presence of an element (<div>
element representing a button in this case) with an onclick or onmousedown handler registered, was enough to make Safari realize that this is probably something where UI collisions should be avoided. Quite frankly I'm not a fan of this kind of "A.I", but at least there is an explaination now.
var button = document.createElement("div");
button.className = "ToolbarButton ToolbarButtonBold";
button.onmousedown = function() { /* ... */ }; // This saves the day
toolbar.appendChild(button);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Jimmy Thomsen |