EdouardTack / candlestick

jQuery plugin selector between three options
MIT License
11 stars 11 forks source link

Toggle positioned incorrectly when programmatically changing a hidden candlestick element #17

Open jcohen02 opened 6 years ago

jcohen02 commented 6 years ago

After making a programmatic change to a hidden candlestick element, the toggle seems to be incorrectly positioned when the candlestick element is made visible.

This seems to affect the on and default settings, off seems ok. When setting the hidden candlestick to on, the toggle ends up just outside the background to the far left of the element. When setting to default, the toggle ends up in a similar position, just to the left of where it would normally be in the off position.

Steps to reproduce: Given the following basic test case:

<!DOCTYPE html>
<html lang="en">
  <head>
    <!-- Load font awesome and candlestick CSS -->
    <link rel="stylesheet" href="/...css_path.../font-awesome.min.css">
    <link rel="stylesheet" href="/...css_path.../candlestick.min.css">
  </head>

  <body>
    <div id="candlestick-div" style="padding: 30px 30px;">
      <form>
        <input id="candlestick1" class="js-candlestick" type="checkbox" name="candlestick" value="">
      </form>
    </div>

    <!-- ... load jQuery and Candlestick libs ... -->
    <script src="/...js_path.../jquery.min.js"></script>
    <script src="/...js_path.../candlestick.js"></script>

    <script type="text/javascript">
      $(document).ready( function() {
        $('#candlestick1').candlestick({
                swipe:false, 
                size: 'sm',
                allowManualDefault: true,
        });
      });
    </script>
  </body>
</html>

Running the following (in the browser console) will demonstrate the issue:

$('#candlestick-div').hide();
$('#candlestick1').candlestick('on');
$('#candlestick-div').show();

If $('#candlestick1').candlestick('on') or $('#candlestick1').candlestick('default') is called again once the element is visible, the toggle returns to the correct position for the specified setting.

Thanks.

jcohen02 commented 6 years ago

It looks like the cause of this issue is the change to theouterWidth of the div.candlestick-bg when the candlestick is hidden, resulting in the calculated position of the toggle being incorrect.

Had a go at implementing a simple fix based on the approaches discussed at https://stackoverflow.com/questions/1472303/jquery-get-width-of-element-when-not-visible-display-none and https://forum.jquery.com/topic/best-approach-to-get-hidden-element-dimension-width-height-etc.

Maybe there's a better approach but I've added a function that calculates the outerWidth of a hidden div.candlestick-bg element:

    /**
     * Get the element bg width for a candlestick element that may be hidden
     * 
     * @param $candlestickBg a jquery object for a div.candlestick-bg element
     */
    function _getBgWidth($candlestickBg) {
        // If the node is already visible, return the outerWidth
        if($candlestickBg.is(':visible')) {
            return $candlestickBg.outerWidth();
        }

        // If the node is hidden, its necessary to clone the element and 
        // add the clone to the DOM with visibility: hidden set to get the 
        // actual element width when its not visible.
        var $clonedEl = $candlestickBg.parent().clone().css('visibility', 'hidden');
        $('body').append($clonedEl);
        var outerWidth = $clonedEl.find('.candlestick-bg').outerWidth();
        return outerWidth;

    }

This is then called as _getBgWidth(this.parent) in place of this.parent.outerWidth() at:

https://github.com/EdouardTack/candlestick/blob/da853a591355c5e911985cd234f86d04a6002d45/lib/js/candlestick.js#L343

and

https://github.com/EdouardTack/candlestick/blob/da853a591355c5e911985cd234f86d04a6002d45/lib/js/candlestick.js#L392

This seems to solve the problem for my use case. If this is a sufficiently general issue to warrant a fix and the approach described above seems reasonable, I can raise a PR.