Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Widget inside jQuery UI Dialog issues #147

Closed
yanickrochon opened this issue Apr 10, 2013 · 11 comments
Closed

Widget inside jQuery UI Dialog issues #147

yanickrochon opened this issue Apr 10, 2013 · 11 comments
Assignees
Labels

Comments

@yanickrochon
Copy link

When we use the widget inside a jQuery UI Dialog and the dropdown is longer than the dialog's height, the dialog creates scrollbars. Scrolling the dialog makes the popup disappear. Also, if we manage to keep the dropdown open and scrolling the dialog, selecting an option item with the mouse selects a different option (mouse offset seems wrong).

The solution to this would be to make the dropdown attached to the body, giving it big z-index value and positionning it underneath the select widget.

I'll try to come up with a fix because we need this solved today as it causes problems on our production line (someone pushed the changes by mistake into production without proper testing).

@ghost ghost assigned gfranko Apr 10, 2013
@yanickrochon
Copy link
Author

Just to let you know, I fixed it. That is, I put self.list absolute to the document body, so it does not interfere with jQuery UI dialogs and other containments. It's a quick fix, of course and I would not recommend it as a PR (it works for our immediate problem). Plus, we are using jQuery UI, so I made use of the extended .position() functionality, which would fail with Bootstrap (without jQuery UI).

If you want some help, I can assist with the resolution of this issue.

@yanickrochon
Copy link
Author

Here is the complete diff of the changes I made so it works. I still need to check when the window is scrolling and it fails to bubble when elements stop propagation (so the dropdown does not close) :

line 169

-- "open": "selectboxit-open"
++ "open": "selectboxit-open ui-state-active"

lines 529 - 533

++ // FIX : drop down not attached to body
// Stores the dropdown list options list inside of the `list` instance variable
-- self.list = createdList;
++ self.list = createdList.appendTo("body");
--
// Append the dropdown list options list to the dropdown container element
-- self.dropdownContainer.append(self.list);
++ //self.dropdownContainer.append(self.list);

line 632

-- "max-width": self.dropdownContainer.width() - (self.downArrowContainer.outerWidth(true) + self.dropdownImage.outerWidth(true))
++ "max-width": self.element.innerWidth() - (self.downArrowContainer.outerWidth(true) + self.dropdownImage.outerWidth(true))

lines 1572 - 1577

-- self.dropdown.removeClass(hoverClass).addClass(focusClass);
++ self.dropdown.find("a").removeClass(hoverClass).addClass(focusClass);
-- self.listItems.removeClass(self.selectedClass);
++ self.listItems.find("a").removeClass(self.selectedClass);
-- self.listItems.removeAttr("data-active").not(activeElem).removeClass(focusClass);
++ self.listItems.removeAttr("data-active").not(activeElem).find("a").removeClass(focusClass);
-- activeElem.addClass(focusClass).addClass(self.selectedClass);
++ activeElem.find("a").addClass(focusClass).addClass(self.selectedClass);

lines 1523 - 1529

-- $(this).addClass(focusClass).attr("data-active", "");
++ $(this).attr("data-active", "").find("a").addClass(focusClass);
// Sets the dropdown list indropdownidual options back to the default state and sets the focus CSS class on the currently hovered option
-- self.listItems.not($(this)).removeClass(focusClass);
++ self.listItems.not($(this)).find("a").removeClass(focusClass);
-- $(this).addClass(focusClass);
++ $(this).find("a").addClass(focusClass);

lines 1591 - 1593

-- self.listItems.not($(this)).removeClass(focusClass).removeAttr("data-active");
++ self.listItems.not($(this)).removeAttr("data-active").find("a").removeClass(focusClass);
-- $(this).addClass(focusClass);
++ $(this).find("a").addClass(focusClass);

lines 2066 - 2141

selectBoxIt._dynamicPositioning = function () {

    var self = this,

        // Returns the x and y coordinates of the dropdown list options list relative to the document
        listOffsetTop = self.dropdown.offset().top,

        // The height of the dropdown list options list
        listHeight = self.list.data("real-height") || self.list.outerHeight(),

        // The height of the dropdown list DOM element
        selectBoxHeight = self.dropdown.outerHeight(),

        viewport = self.options["viewport"],

        viewportHeight = viewport.height(),

        viewportScrollTop = $.isWindow(viewport.get(0)) ? viewport.scrollTop() : viewport.offset().top,

        listHeightMax = Math.max((viewportScrollTop + viewportHeight) - (listOffsetTop + selectBoxHeight) - 8, 150),

        topToBottom = (listOffsetTop + selectBoxHeight + listHeightMax <= viewportHeight + viewportScrollTop),

        bottomReached = !topToBottom,

        myPosition = bottomReached ? "left bottom" : "left top",

        atPosition = bottomReached ? "left top" : "left bottom"
    ;

    if (!self.list.data("real-height")) {
        self.list.data("real-height", listHeight);
    }

    if (bottomReached) {
        listHeightMax = Math.max(listOffsetTop - viewportScrollTop - 8, 150);
    }

    if (!self.list.data("max-height")) {

        self.list.data("max-height", self.list.outerHeight());

    }

    // FIX : drop down not attached to body (element needs to be visible to be repositioned)
    self.list.show()
        .css("max-height", listHeightMax)
        .position({ my: myPosition, at: atPosition, of: self.dropdownContainer })
        .width(self.dropdownContainer.innerWidth() - 2)
        .hide();        
    self.listItems.width(self.dropdownContainer.innerWidth() - 2);

    // Maintains chainability
    return self;
};

The CSS was modified accordingly also. It is better to just dump it, so There are a lot of commented lines, as we don't use Bootsrap, they were stripped to ensure full compat with jQuery UI Themes as described in issue #148 )

/*
 * jquery.selectBoxIt.css 3.3.0
 * Author: @gregfranko
 */

/*
  Common CSS Properties
  ---------------------
  These properties will be applied to any themes that you use
*/

/* SelectBoxIt container */
.selectboxit-container {
  position: relative;
  display: inline-block;
  vertical-align: middle;
}

/* Styles that apply to all SelectBoxIt elements */
.selectboxit-container * {
  font: 12px Helvetica, Arial;
  /* Prevents text selection */
  -webkit-touch-callout: none;
  -webkit-user-select: none;
  -khtml-user-select: none;
  -moz-user-select: -moz-none;
  ms-user-select: none;
  -o-user-select: none;
  user-select: none;
  outline: none;
  white-space: nowrap;
}

/* Button */
.selectboxit-container .selectboxit {
  width: 220px; /* Width of the dropdown button */
  cursor: pointer;
  margin: 0;
  padding: 1px 0px;
  overflow: hidden;
  display: block;
  position: relative;
}

/* Height and Vertical Alignment of Text */
/*.selectboxit-container span, .selectboxit-container*/
 .selectboxit-options a {
  height: 20px; /* Height of the drop down */
  line-height: 20px; /* Vertically positions the drop down text */
  display: block;
}

    /*.selectboxit-container span, .selectboxit-container */
    .selectboxit-options .ui-state-focus a {
        margin-top: -1px;
        margin-left: -1px;
        height:18px;
        line-height:18px;
    }

/* Focus pseudo selector */
.selectboxit-container .selectboxit:focus {
  outline: 0;
}

/* Disabled Mouse Interaction */
.selectboxit-disabled {
  cursor: default;
  opacity: 0.65;
  filter: alpha(opacity=65);
  -webkit-box-shadow: none;
  -moz-box-shadow: none;
  box-shadow: none;
}

/* Button Text */
.selectboxit-text {
  text-indent: 5px;
  overflow: hidden;
  text-overflow: ellipsis;
  float: left;
}

.selectboxit .selectboxit-option-icon-container {
  margin-left: 5px;
}

/* Options List */
/*.selectboxit-container */
.selectboxit-options {
  -moz-box-sizing: border-box;
  box-sizing: border-box;
  /* min-width: 100%; */  /* Minimum Width of the dropdown list box options */
  *width: 100%;
  margin: 0;
  padding: 0;
  list-style: none;
  position: absolute;
  overflow-x: hidden;
  overflow-y: auto;
  cursor: pointer;
  display: none;
  z-index: 9999999999999;
  /*border-radius: 6px;*/
  text-align: left;
  -webkit-box-shadow: none;
  -moz-box-shadow: none;
  box-shadow: none;
}

    .selectboxit-options li {
        display:block;
        /*border-radius: 6px;*/
        white-space: nowrap;
        overflow: hidden;
        text-overflow: ellipsis;
    }

/* Individual options */
 .selectboxit-option .selectboxit-option-anchor{
  padding: 0 2px;
}

/* Individual Option Hover Action */
.selectboxit-option .selectboxit-option-anchor:hover {
  text-decoration: none;
}

/* Individual Option Optgroup Header */
.selectboxit-option, .selectboxit-optgroup-header {
  text-indent: 5px; /* Horizontal Positioning of the select box option text */
  margin: 0;
}

/* The first Drop Down option */
.selectboxit-option-first {
  /*border-top-right-radius: 6px;*/
  /*border-top-left-radius: 6px;*/
}

/* The first Drop Down option optgroup */
.selectboxit-optgroup-header + .selectboxit-option-first {
  /*border-top-right-radius: 0px;*/
  /*border-top-left-radius: 0px;*/
}

/* The last Drop Down option */
.selectboxit-option-last {
  /*border-bottom-right-radius: 6px;*/
  /*border-bottom-left-radius: 6px;*/
}

/* Drop Down optgroup headers */
.selectboxit-optgroup-header {
  font-weight: bold;
}

/* Drop Down optgroup header hover psuedo class */
.selectboxit-optgroup-header:hover {
  cursor: default;
}

/* Drop Down down arrow container */
.selectboxit-arrow-container {
  /* Positions the down arrow */
  width: 30px;
  position: absolute;
  right: 0;
}

/* Drop Down down arrow */
.selectboxit .selectboxit-arrow-container .selectboxit-arrow {
  /* Horizontally centers the down arrow */
  margin: 0 auto;
  position: absolute;
  top: 50%;
  right: 0;
  left: 0;
}

/* Drop Down down arrow for jQueryUI and jQuery Mobile */
.selectboxit .selectboxit-arrow-container .selectboxit-arrow.ui-icon {
  top: 0;
}

/* Drop Down individual option icon positioning */
.selectboxit-option-icon-container {
  float: left;
}

.selectboxit-container .selectboxit-option-icon {
  margin: 0;
  padding: 0;
  vertical-align: middle;
}

/* Drop Down individual option icon positioning */
.selectboxit-option-icon-url {
  width: 18px;
  background-size: 18px 18px;
  background-repeat: no-repeat;
  height: 100%;
  background-position: center;
  float: left;
}

/* jQueryUI and jQuery Mobile compatability fix - Feel free to remove this style if you are not using jQuery Mobile */
.jqueryui .ui-icon {
  background-color: inherit;
}

/* Another jQueryUI and jQuery Mobile compatability fix - Feel free to remove this style if you are not using jQuery Mobile */
.jqueryui .ui-icon-triangle-1-s {
  background-position: -64px -16px;
}

/*
  Default Theme
  -------------
  Note: Feel free to remove all of the CSS underneath this line if you are not using the default theme
*/
.selectboxit-btn {
  background-color: #f5f5f5;
  background-image: -moz-linear-gradient(top, #ffffff, #e6e6e6);
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#ffffff), to(#e6e6e6));
  background-image: -webkit-linear-gradient(top, #ffffff, #e6e6e6);
  background-image: -o-linear-gradient(top, #ffffff, #e6e6e6);
  background-image: linear-gradient(to bottom, #ffffff, #e6e6e6);
  background-repeat: repeat-x;
  border: 1px solid #cccccc;
  border-color: #e6e6e6 #e6e6e6 #bfbfbf;
  border-color: rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.1) rgba(0, 0, 0, 0.25);
  border-bottom-color: #b3b3b3;
}

.selectboxit-btn:hover,
.selectboxit-btn:focus,
.selectboxit-btn:active {
  color: #333333;
  background-color: #e6e6e6;
}

.selectboxit-btn:hover,
.selectboxit-btn:focus {
  color: #333333;
  text-decoration: none;
  background-position: 0 -15px;
}

.selectboxit-default-arrow {
  width: 0;
  height: 0;
  border-top: 4px solid #000000;
  border-right: 4px solid transparent;
  border-left: 4px solid transparent;
}

.selectboxit-list {
  background-color: #ffffff;
  border: 1px solid #ccc;
  border: 1px solid rgba(0, 0, 0, 0.2);
  -webkit-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
  -moz-box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
  box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
}

.selectboxit-list > li > a {
  /*color: #333333;*/
}

.selectboxit-list > .selectboxit-focus > a,
.selectboxit-list > .selectboxit-focus > a:hover,
.selectboxit-list > .selectboxit-focus > a:focus {
  /*color: #ffffff;*/
  /*background-color: #0081c2;*/
  background-image: -moz-linear-gradient(top, #0088cc, #0077b3);
  background-image: -webkit-gradient(linear, 0 0, 0 100%, from(#0088cc), to(#0077b3));
  background-image: -webkit-linear-gradient(top, #0088cc, #0077b3);
  background-image: -o-linear-gradient(top, #0088cc, #0077b3);
  background-image: linear-gradient(to bottom, #0088cc, #0077b3);
  background-repeat: repeat-x;
}

.selectboxit-list > .selectboxit-disabled > a {
  /*color: #999999;*/
}

.selectboxit-list > .selectboxit-disabled > a:hover,
.selectboxit-list > .selectboxit-disabled > a:focus {
  background-color: transparent;
  background-image: none;
}

@gfranko
Copy link
Owner

gfranko commented Apr 21, 2013

I've been mulling over this issue, and have ultimately decided to not support this jQueryUI dialog use case within SelectBoxIt. The use cases that you suggested above (listening to the scroll event to know when to close SelectBoxIt) are too performance intensive for my liking. I would suggest either complaining to the jQueryUI team about their overflow:auto CSS styles, or updating the jQueryUI CSS to make sure absolutely positioned elements are visible within the dialog.

@gfranko gfranko closed this as completed Apr 21, 2013
@yanickrochon
Copy link
Author

I understand. In our case, this is not a choice and I had to extensively modify the widget source code (as you can see in my previous comment) to make it work. I will try to come up with a better fix for this later on (perhaps with a special option to find the closest absolute position or overflow-able container and append the dropdown list appropriately...). I don't like that hack I implemented either, but I had to have a quick fix for production, and it is "functional" at the moment.

@gfranko
Copy link
Owner

gfranko commented Apr 21, 2013

Instead of adjusting the SelectBoxIt source, why don't you just adjust the jQueryUI CSS code to remove the overflow:auto; property?

@yanickrochon
Copy link
Author

Because if I do that, the jQuery UI dialog size will increase beyond the layout viewport and we are using a full height layout :) Plus, if I do that, the dialog height will jump whenever the selectBoxIt dropdown appears. Not ideal.

Note: my hack also replace the dropdown list above or below the selectBoxIt container whenever the page scroll, wherever there's more area to display it, and it's height is automatically adjusted to fill that area. It's pretty neat.

@gfranko
Copy link
Owner

gfranko commented Apr 21, 2013

Do you have a public url you could show of your solution?

@yanickrochon
Copy link
Author

Unfortunately not. But whenever I have some time (it might be only in June), I'll cleanup the code and perhaps even propose a PR. In my solution I am, however, using jQuery UI's position API, which reduces the _dynamicPositioning method's complexity a bit and I don't think your widget has the jQuery UI dependancy mandatory.

@Limos
Copy link

Limos commented Dec 3, 2013

Jumping in a bit late here, but... I had a similar problem with dropdown content being clipped in jQuery UI Dialogs and Accordions which I successfully worked around by adding the following to my selectBoxIt elements. I'd be interested in receiving feedback on the pros/cons of my solution.

.bind( 'open', function() { $(this).parents().each( function() { if( $(this).hasClass('ui-accordion-content') || $(this).hasClass('ui-dialog-content') ) $(this).css( 'overflow', 'visible' ); }); })
.bind( 'close', function() { $(this).parents().each( function() { if( $(this).hasClass('ui-accordion-content') || $(this).hasClass('ui-dialog-content') ) $(this).css( 'overflow', 'hidden' ); }); })

@gfranko
Copy link
Owner

gfranko commented Dec 3, 2013

@Limos Have you tried adding this CSS rule? @badulesia had told me that this worked.

.ui-dialog .selectboxit-options {
  position: static;
}

@badulesia
Copy link

Le 03/12/2013 19:03, Greg Franko a écrit :

@Limos https://github.com/Limos Have you tried adding this CSS rule?
@badulesia https://github.com/badulesia had told me that this worked.

.ui-dialog-content .selectboxit-container {
position: static
}

Hello.
Yes I confirm that such code works fine.
I didn't need to use .ui-dialog-content, just

.selectboxit-container {
position: static;
}

selectboxit is now displayed over sections in jquery UI accordions just
as default selectmenu. It also works fine inside a Jquery UI tab, but
not inside a Jquery UI dialog window. I have not investigate the case yet.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

4 participants