From 855cdc8eda6ea73b2eeda44be321c002acc52503 Mon Sep 17 00:00:00 2001 From: Joe Cheng Date: Tue, 3 Feb 2015 14:01:36 -0800 Subject: [PATCH] Fix oversubscription of shown/hidden events Bootstrap 3 shown/hidden events look like "shown.bs.modal", "shown.bs.popover", etc. When subscribing to these events, you also automatically pick up "shown" and "hidden" events. This causes a 6X oversubscription of hidden and shown events. We fix this by filtering out these overbroad events. Also, don't do anything if the show/hide would be a no-op; this also helps cut down on extraneous events. --- inst/www/shared/shiny.js | 39 ++++++++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 13 deletions(-) diff --git a/inst/www/shared/shiny.js b/inst/www/shared/shiny.js index aae0484ae..09c19ce6e 100644 --- a/inst/www/shared/shiny.js +++ b/inst/www/shared/shiny.js @@ -783,9 +783,6 @@ var scope = {input: inputs, output: this.$values}; - var triggerShown = function() { $(this).trigger('shown'); }; - var triggerHidden = function() { $(this).trigger('hidden'); }; - var conditionals = $(document).find('[data-display-if]'); for (var i = 0; i < conditionals.length; i++) { var el = $(conditionals[i]); @@ -797,13 +794,19 @@ el.data('data-display-if-func', condFunc); } - if (condFunc(scope)) { - el.trigger('show'); - el.show(0, triggerShown); - } - else { - el.trigger('hide'); - el.hide(0, triggerHidden); + var show = condFunc(scope); + var showing = el.css("display") !== "none"; + if (show !== showing) { + if (show) { + el.trigger('show'); + el.show(); + el.trigger('shown'); + } + else { + el.trigger('hide'); + el.hide(); + el.trigger('hidden'); + } } } }; @@ -3296,6 +3299,14 @@ sendOutputHiddenStateDebouncer.immediateCall(); }); + function filterEventsByNamespace(namespace, handler) { + return function(e) { + if (e.namespace.indexOf(namespace) === 0) { + handler.apply(this, arguments); + } + }; + } + // The size of each image may change either because the browser window was // resized, or because a tab was shown/hidden (hidden elements report size // of 0x0). It's OK to over-report sizes because the input pipeline will @@ -3304,13 +3315,15 @@ // Need to register callbacks for each Bootstrap 3 class. var bs3classes = ['modal', 'dropdown', 'tab', 'tooltip', 'popover', 'collapse']; $.each(bs3classes, function(idx, classname) { - $('body').on('shown.bs.' + classname + '.sendImageSize', '*', sendImageSize); + $('body').on('shown.bs.' + classname + '.sendImageSize', '*', + filterEventsByNamespace('bs.', sendImageSize)); $('body').on('shown.bs.' + classname + '.sendOutputHiddenState ' + 'hidden.bs.' + classname + '.sendOutputHiddenState', - '*', sendOutputHiddenState); + '*', filterEventsByNamespace('bs.', sendOutputHiddenState)); }); - // This is needed for Bootstrap 2 compatibility + // This is needed for Bootstrap 2 compatibility and for non-Bootstrap + // related shown/hidden events (like conditionalPanel) $('body').on('shown.sendImageSize', '*', sendImageSize); $('body').on('shown.sendOutputHiddenState hidden.sendOutputHiddenState', '*', sendOutputHiddenState);