/** * @file * Bootstrap Popovers. */ var Drupal = Drupal || {}; (function ($, Drupal, Bootstrap) { "use strict"; var $document = $(document); /** * Extend the Bootstrap Popover plugin constructor class. */ Bootstrap.extendPlugin('popover', function (settings) { return { DEFAULTS: { animation: !!settings.popover_animation, autoClose: !!settings.popover_auto_close, enabled: settings.popover_enabled, html: !!settings.popover_html, placement: settings.popover_placement, selector: settings.popover_selector, trigger: settings.popover_trigger, title: settings.popover_title, content: settings.popover_content, delay: parseInt(settings.popover_delay, 10), container: settings.popover_container } }; }); /** * Bootstrap Popovers. * * @todo This should really be properly delegated if selector option is set. */ Drupal.behaviors.bootstrapPopovers = { $activePopover: null, attach: function (context) { // Immediately return if popovers are not available. if (!$.fn.popover || !$.fn.popover.Constructor.DEFAULTS.enabled) { return; } var _this = this; $document .on('show.bs.popover', '[data-toggle=popover]', function () { var $trigger = $(this); var popover = $trigger.data('bs.popover'); // Only keep track of clicked triggers that we're manually handling. if (popover.options.originalTrigger === 'click') { if (_this.$activePopover && _this.getOption('autoClose') && !_this.$activePopover.is($trigger)) { _this.$activePopover.popover('hide'); } _this.$activePopover = $trigger; } }) // Unfortunately, :focusable is only made available when using jQuery // UI. While this would be the most semantic pseudo selector to use // here, jQuery UI may not always be loaded. Instead, just use :visible // here as this just needs some sort of selector here. This activates // delegate binding to elements in jQuery so it can work it's bubbling // focus magic since elements don't really propagate their focus events. // @see https://www.drupal.org/project/bootstrap/issues/3013236 .on('focus.bs.popover', ':visible', function (e) { var $target = $(e.target); if (_this.$activePopover && _this.getOption('autoClose') && !_this.$activePopover.is($target) && !$target.closest('.popover.in')[0]) { _this.$activePopover.popover('hide'); _this.$activePopover = null; } }) .on('click.bs.popover', function (e) { var $target = $(e.target); if (_this.$activePopover && _this.getOption('autoClose') && !$target.is('[data-toggle=popover]') && !$target.closest('.popover.in')[0]) { _this.$activePopover.popover('hide'); _this.$activePopover = null; } }) .on('keyup.bs.popover', function (e) { if (_this.$activePopover && _this.getOption('autoClose') && e.which === 27) { _this.$activePopover.popover('hide'); _this.$activePopover = null; } }) ; var elements = $(context).find('[data-toggle=popover]').toArray(); for (var i = 0; i < elements.length; i++) { var $element = $(elements[i]); var options = $.extend({}, $.fn.popover.Constructor.DEFAULTS, $element.data()); // Store the original trigger. options.originalTrigger = options.trigger; // If the trigger is "click", then we'll handle it manually here. if (options.trigger === 'click') { options.trigger = 'manual'; } // Retrieve content from a target element. var target = options.target || $element.is('a[href^="#"]') && $element.attr('href'); var $target = $document.find(target).clone(); if (!options.content && $target[0]) { $target.removeClass('visually-hidden hidden').removeAttr('aria-hidden'); options.content = $target.wrap('
').parent()[options.html ? 'html' : 'text']() || ''; } // Initialize the popover. $element.popover(options); // Handle clicks manually. if (options.originalTrigger === 'click') { // To ensure the element is bound multiple times, remove any // previously set event handler before adding another one. $element .off('click.drupal.bootstrap.popover') .on('click.drupal.bootstrap.popover', function (e) { $(this).popover('toggle'); e.preventDefault(); e.stopPropagation(); }) ; } } }, detach: function (context) { // Immediately return if popovers are not available. if (!$.fn.popover || !$.fn.popover.Constructor.DEFAULTS.enabled) { return; } // Destroy all popovers. $(context).find('[data-toggle="popover"]') .off('click.drupal.bootstrap.popover') .popover('destroy') ; }, getOption: function(name, defaultValue, element) { var $element = element ? $(element) : this.$activePopover; var options = $.extend(true, {}, $.fn.popover.Constructor.DEFAULTS, ($element && $element.data('bs.popover') || {}).options); if (options[name] !== void 0) { return options[name]; } return defaultValue !== void 0 ? defaultValue : void 0; } }; })(window.jQuery, window.Drupal, window.Drupal.bootstrap);