Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TinyMCE color picker dropdown appears off-screen

This is an issue on Firefox and IE so far that I've tested; the problem does not exist on Chrome.

I'm including two TinyMCE editors on a page with one partially off-screen to start. When I select the color picker dropdown option from the toolbar on the first TinyMCE instance, the dropdown appears where it should. But if I scroll down and select the color picker dropdown in the second instance, that dropdown appears way below the editor and typically off the page.

You can see this in action here: http://jsfiddle.net/nm6wtca3/

Without removing the html, body CSS, what can I do to have the color picker always appear in the correct position?

I've traced the problem down to setting CSS on the html, body elements.

html, body {
    width: 100%;
    height: 100%;
    overflow-x: hidden;
}

The dropdown div has CSS applied to it that is auto-calculated by TinyMCE. It looks something like this:

z-index: 65535; 
left: 641.467px; 
top: 633px; 
width: 162px; 
height: 105px;

How it appears in FF (sometimes way worse): How it appears in FF

How it appears in Chrome (how it should look): How it appears in Chrome (how it should look)

like image 804
Luke Shaheen Avatar asked Apr 07 '15 14:04

Luke Shaheen


3 Answers

You did say you don't want to remove any CSS from the html,body, but you didn't say anything about adding to it! This solution is based on the assumption that you can add to the html,body

Solution

html, body {
    width: 100%;
    height: 100%;
    overflow-x: hidden;
    position: relative; /* Line added */
}

JSFiddle Example

I hope this helps. In all reality, you really only need to apply position: relative; to the body like so body { position: relative; }

like image 167
HandyDan Avatar answered Nov 05 '22 05:11

HandyDan


I'm not super familiar with tinymce's colorpicker, but I can see the issue, and I can replicate it reliably: your problem occurs when you have a picker open, and then you scroll. I can replicate this in chrome too. Here's a video.

When I look at the DOM, I see that tinyMCE has created two absolute-positioned divs at the end of document.body, one for each picker. When you open one, their position is updated to reflect the location of the toolbar-button at the time you clicked it, but it never gets updated when you scroll!

So, how to solve this? Well, there are a few possibilities:

Option 1: it looks like tinyMCE provides a method to bind a control to an event (here). With this, you could bind a callback to 'scroll' that repositions the box...

Huh, now that I think of it, you could simply close any open colorpickers whenever a user scrolls ... kinda feels like a cop-out but there's no denying it has the best R.O.I. ;) We'll call that Option 2!

Option 3: depending on the implementation of the colorpicker, you may be able to override where in the DOM those divs get rendered. The API method I saw that looked the most promising is here. Once you have the div inside a relative-positioned parent, you'd also have to make the colorpicker's positioning algorithm smart enough to look in the right place for x and y offset ...when I tried this by just moving the element and mashing in some css by hand in chrome-console, the algorithm still computed x and y offsets based on doc.body, so depending on where you were scrolled at click-time, everything would be out of position

It looks like this issue might be troubling other people as well... maybe they've found a solution but haven't posted anything about it?

I hope this is enough info to get you past the problem... Let me know if you have any questions!

like image 31
MattE_WI Avatar answered Nov 05 '22 07:11

MattE_WI


It looks like the problem is caused by overflow-x: hidden;

It may not be the answer you want but removing that or moving it to a page wrapper will solve your problem.

Working Example

html, body {
    width: 100%;
    height: 100%;
    padding:0;
    margin:0;
}
#pagewrapper{
    overflow-x: hidden;
}

Another option would be to force repositioning on scroll, but honestly this is overkill... I strongly recommend fixing the css instead.

Another working example

$('body').scroll(posfix); // when the body scrolls 
$('#mceu_10').click(posfix); // when you click the top font color button
$('#mceu_35').click(posfix); // when you click the bottom font color button

function posfix() {
    setTimeout(function () { // hack way to ensure it fires after the menu is shown
        $('#mceu_51').css({
            top: $('#mceu_10').offset().top + $('#mceu_10').height(), // set top/left based on button's position
            left: $('#mceu_10').offset().left + $('#mceu_10').width() / 2
        });
        $('#mceu_52').css({
            top: $('#mceu_35').offset().top + $('#mceu_35').height(),
            left: $('#mceu_35').offset().left + $('#mceu_35').width() / 2
        });
    }, 1);
}
like image 4
apaul Avatar answered Nov 05 '22 06:11

apaul