6 var Drupal
= Drupal
|| {};
8 (function ($, Drupal
, Bootstrap
) {
11 var $document
= $(document
);
14 * Extend the Bootstrap Popover plugin constructor class.
16 Bootstrap
.extendPlugin('popover', function (settings
) {
19 animation
: !!settings
.popover_animation
,
20 autoClose
: !!settings
.popover_auto_close
,
21 enabled
: settings
.popover_enabled
,
22 html
: !!settings
.popover_html
,
23 placement
: settings
.popover_placement
,
24 selector
: settings
.popover_selector
,
25 trigger
: settings
.popover_trigger
,
26 title
: settings
.popover_title
,
27 content
: settings
.popover_content
,
28 delay
: parseInt(settings
.popover_delay
, 10),
29 container
: settings
.popover_container
37 * @todo This should really be properly delegated if selector option is set.
39 Drupal
.behaviors
.bootstrapPopovers
= {
41 attach: function (context
) {
42 // Immediately return if popovers are not available.
43 if (!$.fn
.popover
|| !$.fn
.popover
.Constructor
.DEFAULTS
.enabled
) {
50 .on('show.bs.popover', '[data-toggle=popover]', function () {
51 var $trigger
= $(this);
52 var popover
= $trigger
.data('bs.popover');
54 // Only keep track of clicked triggers that we're manually handling.
55 if (popover
.options
.originalTrigger
=== 'click') {
56 if (_this
.$activePopover
&& _this
.getOption('autoClose') && !_this
.$activePopover
.is($trigger
)) {
57 _this
.$activePopover
.popover('hide');
59 _this
.$activePopover
= $trigger
;
62 // Unfortunately, :focusable is only made available when using jQuery
63 // UI. While this would be the most semantic pseudo selector to use
64 // here, jQuery UI may not always be loaded. Instead, just use :visible
65 // here as this just needs some sort of selector here. This activates
66 // delegate binding to elements in jQuery so it can work it's bubbling
67 // focus magic since elements don't really propagate their focus events.
68 // @see https://www.drupal.org/project/bootstrap/issues/3013236
69 .on('focus.bs.popover', ':visible', function (e
) {
70 var $target
= $(e
.target
);
71 if (_this
.$activePopover
&& _this
.getOption('autoClose') && !_this
.$activePopover
.is($target
) && !$target
.closest('.popover.in')[0]) {
72 _this
.$activePopover
.popover('hide');
73 _this
.$activePopover
= null;
76 .on('click.bs.popover', function (e
) {
77 var $target
= $(e
.target
);
78 if (_this
.$activePopover
&& _this
.getOption('autoClose') && !$target
.is('[data-toggle=popover]') && !$target
.closest('.popover.in')[0]) {
79 _this
.$activePopover
.popover('hide');
80 _this
.$activePopover
= null;
83 .on('keyup.bs.popover', function (e
) {
84 if (_this
.$activePopover
&& _this
.getOption('autoClose') && e
.which
=== 27) {
85 _this
.$activePopover
.popover('hide');
86 _this
.$activePopover
= null;
91 var elements
= $(context
).find('[data-toggle=popover]').toArray();
92 for (var i
= 0; i
< elements
.length
; i
++) {
93 var $element
= $(elements
[i
]);
94 var options
= $.extend({}, $.fn
.popover
.Constructor
.DEFAULTS
, $element
.data());
96 // Store the original trigger.
97 options
.originalTrigger
= options
.trigger
;
99 // If the trigger is "click", then we'll handle it manually here.
100 if (options
.trigger
=== 'click') {
101 options
.trigger
= 'manual';
104 // Retrieve content from a target element.
105 var target
= options
.target
|| $element
.is('a[href^="#"]') && $element
.attr('href');
106 var $target
= $document
.find(target
).clone();
107 if (!options
.content
&& $target
[0]) {
108 $target
.removeClass('visually-hidden hidden').removeAttr('aria-hidden');
109 options
.content
= $target
.wrap('<div/>').parent()[options
.html
? 'html' : 'text']() || '';
112 // Initialize the popover.
113 $element
.popover(options
);
115 // Handle clicks manually.
116 if (options
.originalTrigger
=== 'click') {
117 // To ensure the element is bound multiple times, remove any
118 // previously set event handler before adding another one.
120 .off('click.drupal.bootstrap.popover')
121 .on('click.drupal.bootstrap.popover', function (e
) {
122 $(this).popover('toggle');
130 detach: function (context
) {
131 // Immediately return if popovers are not available.
132 if (!$.fn
.popover
|| !$.fn
.popover
.Constructor
.DEFAULTS
.enabled
) {
136 // Destroy all popovers.
137 $(context
).find('[data-toggle="popover"]')
138 .off('click.drupal.bootstrap.popover')
142 getOption: function(name
, defaultValue
, element
) {
143 var $element
= element
? $(element
) : this.$activePopover
;
144 var options
= $.extend(true, {}, $.fn
.popover
.Constructor
.DEFAULTS
, ($element
&& $element
.data('bs.popover') || {}).options
);
145 if (options
[name
] !== void 0) {
146 return options
[name
];
148 return defaultValue
!== void 0 ? defaultValue
: void 0;
152 })(window
.jQuery
, window
.Drupal
, window
.Drupal
.bootstrap
);