16

Using Angular and Angular UI-Bootstrap.

I have created a drop-down menu in textAngular. When you click on something other than the text-box or one of the menu options, it disables the menu. This is desired behavior.

HOWEVER, when using FireFox, opening a drop-down makes it appear as if the user left the menu (even though they are using drop-down from the menu). If it's any help, it looks like the drop-down opens BEHIND and to the side of the text-box.

A picture is worth a 1000 words in this case. Left is Chrome (desired behavior), right is Firefox (not desired behavior). Click me in case embedded image is too small.

enter image description here

Here is the code. This is the display part of the tool registration. For those unfamiliar with textangular - it's just the code that creates the button:

    display: '<span class="btn-group" dropdown dropdown-append-to-body style="padding: 0px 0px 0px 0px">' +
    '<button class="btn btn-default dropdown-toggle" dropdown-toggle type="button" ng-disabled="showHtml()">' +
    '   <span>Items Fields</span>' +
    '</button>' +
    '<ul class="dropdown-menu">' +
    '   <li ng-repeat="o in options">' +
    '       <a ng-click="action(o)">{{o.name}}</a>' +
    '   </li>' +
    '</ul>' +
    '</span>',

Edit:

  1. Plunker that replicates the issue is up: Clicky for plnkr (The focus of the issue is the "Item Fields" button - works in Chrome, doesn't work in firefox.
  2. Boom - bounty!

P.S. Please don't get intimidated by the amount of code. The only relevant html is in the app.js file, under taRegisterTool 'itemFields'.

taRegisterTool('itemFields', {
            display:
Dave Alperovich
  • 32,320
  • 8
  • 79
  • 101
VSO
  • 11,546
  • 25
  • 99
  • 187
  • 1
    can you write plunker? – Shohel Jul 16 '15 at 02:25
  • Yea, I will try. Not sure how well it will work with TA, but worth trying at this point. – VSO Jul 16 '15 at 02:27
  • @Shohel: It's taking a long time and I have to sleep. I will write it tomorrow and tag you again, if you fee like looking at it then. – VSO Jul 16 '15 at 02:37
  • Try adding a blank href attribute in the anchor element. – Rob J Jul 16 '15 at 11:20
  • @RobJ: Tried href = "" in the anchor. It didn't change anything. What does returning a blank href do? I tried to read up on SO, but I don't really get it. The problem is that the thing is out of focus on the initial button click (so the dropdown comes up, but it takes focus off of the first drop down button). – VSO Jul 16 '15 at 12:32
  • 1
    I believe the anchor element has trouble accepting focus without href attribute. – Rob J Jul 16 '15 at 23:39
  • @Rob J: I made the anchor a div to see if that would change anything, and the dropdown still works in Chrome, but the same issue occurs in Firefox. That doesn't tell me anything, posting on the off chance it tells you something. – VSO Jul 16 '15 at 23:46
  • @Shohel: Plnkr and bounty up. – VSO Jul 19 '15 at 18:11
  • 1
    Your dropdown now becomes the focus. It is not part of the element in FF, chrome treats dropdown as part of element. I found the difference by evaluating it's conditions. This is not an easy change. – Dave Alperovich Jul 19 '15 at 21:49
  • Thanks for checking Dave. Can you elaborate on what you mean by evaluating conditions, just for my knowledge. And by elaborate, I just mean what should I google. – VSO Jul 20 '15 at 00:27
  • 1
    @VSO, just saw this. Nothing you can Google. I expanded **textAngular.min.js**. On line 1481 is a watch condition on the element: `g.$watch("focussed", function() {`. I added `console.log(g.focussed);` inside the function. It now logs whether the **textAngular** is in focus or not `true`/`false`. If you play around with it, you will notice on FF, clicking the dropdown logs `false` for focus and in Chrome it logs `true`. Here is my Plunker. Hope it helps. http://plnkr.co/edit/6KOOr4f64OZoyXbXNelg?p=preview – Dave Alperovich Jul 20 '15 at 04:19
  • 1
    @DaveAlperovich: It does help, thanks again! – VSO Jul 20 '15 at 12:36
  • @VSO, this seems to be a very old bug in FF still unresolved. https://bugzilla.mozilla.org/show_bug.cgi?id=294910 I suspect Chrome had this bug too. If you watch the logs from my Plunker, you see that on Chrome, clicking the dropdown logs `false` and then `true`. I suspect has a patch with an event watching for dropdown actions and re-setting the focus to parent. I'm afraid this is a platform dead-end. – Dave Alperovich Jul 20 '15 at 15:37
  • @DaveAlperovich: I think I will just end up completely working around it - adding a button with each dropdown option, or some such solution. I really appreciate your input though. I am a newer developer, so I am always hesitant to say "This can't be done in a reasonable timeframe", since I am unsure if it's just something *I* don't know how to solve. – VSO Jul 20 '15 at 17:10

4 Answers4

8

In FireFox, your dropdown becomes the focus. It is not part of the parent element in FF. Chrome treats the dropdown as part of element.

There is a very old FireFox bug logged with status UNCONFIRMED

the drop-down box in a tag isn't treated as a child of the tag's parents


Check out my version of your Plunker: Here

I have expanded textAngular.min.js. On line 1481 there is a watch

    angular.extend(g, angular.copy(c)), i.taToolbar && (g.toolbar =
     g.$parent.$eval(i.taToolbar)), i.taToolbarClass && (g.classes.toolbar =
     i.taToolbarClass), i.taToolbarGroupClass && (g.classes.toolbarGroup = 
     i.taToolbarGroupClass), i.taToolbarButtonClass && 
     (g.classes.toolbarButton = i.taToolbarButtonClass), 
     i.taToolbarActiveButtonClass && (g.classes.toolbarButtonActive = 
     i.taToolbarActiveButtonClass), i.taFocussedClass && (g.classes.focussed =
      i.taFocussedClass), g.disabled = !0, g.focussed = !1, g._$element = h, h[0].innerHTML = "", h.addClass("ta-toolbar " + g.classes.toolbar), 
     g.$watch("focussed", function() {

I placed a log in the function to show the focus status of the element

console.log(g.focussed);

In FireFox, when the drop-down is clicked, you get

false

In Chrome, when the drop-down is clicked

false
true

Seems as though Chrome has a patch watching for just such a problem, setting the parent element to focus when a drop-down gains focus.

Dave Alperovich
  • 32,320
  • 8
  • 79
  • 101
  • I am going to give this a few more days just in case, but I was going to ask you to write an answer for me to accept if this was close to running out without one. – VSO Jul 20 '15 at 19:59
  • @VSO, Maybe my answer will help someone else find a fix. I've been playing around with some hacks myself. no dice yet. – Dave Alperovich Jul 20 '15 at 20:19
  • @VSO, I tried adding `this.$editor().wrapSelection('forecolor', 'green');` to the action for your drop-down, and it failed in **Chrome**. When focus is lost, so is selection. Drop-downs seem to fail regardless of browser. – Dave Alperovich Jul 27 '15 at 02:38
  • Thank you again Dave. Bounty goes to you because you did the most work on this by far and helped me understand the problem. Would have went to you by default on points anyway. – VSO Jul 27 '15 at 17:07
5

Simple solution

What you can do is remove the attribute disabled from the button group your trying to use. That seems to be causing this behavior in Firefox.

$('body').on('click', '.ta-toolbar.btn-toolbar .btn-group', function(){
    $(this).removeAttr('disabled');
});

See it in action for yourself. Updated plnkr: http://plnkr.co/edit/k7zI9G9078cAhShjz2l4?p=preview

Sceptic
  • 1,659
  • 2
  • 15
  • 25
  • I tried something similar and it appears to work because the drop-down retains focus. But, when I add an action inside `function (option) {` like `this.$editor().wrapSelection('forecolor', 'green');` it does not apply the styling on clicking an option (because `this` no longer applies to the editor). Notice, unlike with button clicks, the drop-down click removes focus from the editor and clears the selection. – Dave Alperovich Jul 26 '15 at 15:19
  • You could save the focused element and selected text in a var. Simply set that on blur of the appropriate element or another way before the click happens like mousenter. Then make your call inside dropdowns using that target. – Sceptic Jul 26 '15 at 19:30
  • But would you also save the position inside the editor? WYISWYG editors will change their elements the moment they lose focus. You would need to somehow reselect the data inside the editor. Your var would not be pointing to the same element. – Dave Alperovich Jul 26 '15 at 21:53
  • Yes that's also possible. In that case save which text element has the focus. Then save the selected text or only the element as a whole. Clone the P tag inside the saved text element and apply any changes from the dropdown function then replace cloned P with the old P to the correct text element. If your really need a fix this could be it. – Sceptic Jul 27 '15 at 03:30
  • Can you create a Plunker as example? – Dave Alperovich Jul 27 '15 at 04:37
  • Sure. Is it ok if I write an on click for the dropdown elements with a custom change text function or is there a specific place those functions have to start or be called? – Sceptic Jul 27 '15 at 07:01
  • Good question. Try using onclick. Hard to tell if this has to be done inside text angular directive or not. – Dave Alperovich Jul 27 '15 at 07:04
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/84354/discussion-between-reinout-van-kempen-and-dave-alperovich). – Sceptic Jul 27 '15 at 10:00
  • @Reinout van Kempen Thank you very much for the suggestion, I will continue messing with it to see if I can adapt it to work fully. – VSO Jul 27 '15 at 17:08
  • Your welcome. In suggest you use my other answer instead. – Sceptic Jul 28 '15 at 04:56
4

Working solution

I fully got it working now, thought of an even simpler solution. Check out the dropdown working with your green function. I go around the problem caused by the click by opening the dropdown. To make it safer you can disable the click function completely.

Add style:

<style>
    .dropdown-menu{
        margin-top: 0px;
    }
</style>

Add script:

<script>
    $('body').on('mouseenter', '.ta-toolbar.btn-toolbar .btn-group', function(){
        $(this).addClass('open');
        $(this).children('button').css('pointer-events', 'none');
    });

    $('body').on('mouseleave', '.ta-toolbar.btn-toolbar .btn-group', function(){
        $(this).removeClass('open');
    });
</script>

Working Plnkr: http://plnkr.co/edit/7itorLFtKaxEgekGZU1B?p=preview

Sceptic
  • 1,659
  • 2
  • 15
  • 25
  • Thanks, I will try it and accept answer after I do. – VSO Jul 28 '15 at 14:38
  • Just tested the Plnkr on a touch device and that worked fine too with the mouseenter in spite of what I expected. This seems a pretty solid solution. – Sceptic Jul 29 '15 at 18:52
  • Hey, sorry, I am insanely swamped with work right now, but I definitely won't forget to come back and accept once I implement it. I really appreciate it. – VSO Jul 29 '15 at 19:10
  • 1
    Yup, that did it. Good work. ReinoutvanKempen, I suggest you make another stackexchange account (like on Meta) and get the 100pnt bonus. – Dave Alperovich Jul 29 '15 at 22:52
  • 1
    Thanks but I'm good. The reputation points don't have any real value. Solving puzzles and helping everyone out in the process is fun though. Glad we could work together on this! – Sceptic Jul 30 '15 at 03:23
  • Thanks guys. Also, @Reinout - if you decide that the points *do* matter, even a little bit, let me know and we will make a question and I will make another bounty as you both deserve it. – VSO Aug 02 '15 at 19:37
1

It might be a long shot, but did you reset your CSS defaults? On my project, the browser specific CSS defaults caused variations in the margins, padding, etc. from browser to browser and moved elements around in unpredictable ways.

C1pher
  • 1,933
  • 6
  • 33
  • 52