From f751c983f3b0f400720a8bca935369f4e24ef2f6 Mon Sep 17 00:00:00 2001
From: Johann-S
Date: Thu, 30 Nov 2017 10:54:27 +0100
Subject: [PATCH] Allow Tooltips/Popovers to work in shadow DOM
---
js/src/tooltip.js | 3 ++-
js/src/util.js | 23 ++++++++++++++++++++++
js/tests/unit/util.js | 38 ++++++++++++++++++++++++++++++++++++
js/tests/visual/tooltip.html | 22 ++++++++++++++++++++-
4 files changed, 84 insertions(+), 2 deletions(-)
diff --git a/js/src/tooltip.js b/js/src/tooltip.js
index f428a79ebdc7..5f24b53a766f 100644
--- a/js/src/tooltip.js
+++ b/js/src/tooltip.js
@@ -244,8 +244,9 @@ class Tooltip {
if (this.isWithContent() && this._isEnabled) {
$(this.element).trigger(showEvent)
+ const shadowRoot = Util.findShadowRoot(this.element)
const isInTheDom = $.contains(
- this.element.ownerDocument.documentElement,
+ shadowRoot !== null ? shadowRoot : this.element.ownerDocument.documentElement,
this.element
)
diff --git a/js/src/util.js b/js/src/util.js
index e9665d24fdef..1d804cf9da9a 100644
--- a/js/src/util.js
+++ b/js/src/util.js
@@ -142,6 +142,29 @@ const Util = {
}
}
}
+ },
+
+ findShadowRoot(element) {
+ if (!document.documentElement.attachShadow) {
+ return null
+ }
+
+ // Can find the shadow root otherwise it'll return the document
+ if (typeof element.getRootNode === 'function') {
+ const root = element.getRootNode()
+ return root instanceof ShadowRoot ? root : null
+ }
+
+ if (element instanceof ShadowRoot) {
+ return element
+ }
+
+ // when we don't find a shadow root
+ if (!element.parentNode) {
+ return null
+ }
+
+ return Util.findShadowRoot(element.parentNode)
}
}
diff --git a/js/tests/unit/util.js b/js/tests/unit/util.js
index 61727304d420..2fd6f6b7cb52 100644
--- a/js/tests/unit/util.js
+++ b/js/tests/unit/util.js
@@ -124,4 +124,42 @@ $(function () {
assert.expect(1)
assert.ok(Util.supportsTransitionEnd())
})
+
+ QUnit.test('Util.findShadowRoot should find the shadow DOM root', function (assert) {
+ // Only for newer browsers
+ if (!document.documentElement.attachShadow) {
+ assert.expect(0)
+ return
+ }
+
+ assert.expect(2)
+ var $div = $('').appendTo($('#qunit-fixture'))
+ var shadowRoot = $div[0].attachShadow({
+ mode: 'open'
+ })
+ console.warn($div[0].attachShadow, shadowRoot)
+
+ assert.equal(shadowRoot, Util.findShadowRoot(shadowRoot))
+ shadowRoot.innerHTML = ''
+ assert.equal(shadowRoot, Util.findShadowRoot(shadowRoot.firstChild))
+ })
+
+ QUnit.test('Util.findShadowRoot should return null when attachShadow is not available', function (assert) {
+ assert.expect(1)
+
+ var $div = $('').appendTo($('#qunit-fixture'))
+ if (!document.documentElement.attachShadow) {
+ assert.equal(null, Util.findShadowRoot($div[0]))
+ } else {
+ var sandbox = sinon.createSandbox()
+
+ sandbox.replace(document.documentElement, 'attachShadow', function () {
+ // to avoid empty function
+ return $div
+ })
+
+ assert.equal(null, Util.findShadowRoot($div[0]))
+ sandbox.restore()
+ }
+ })
})
diff --git a/js/tests/visual/tooltip.html b/js/tests/visual/tooltip.html
index 8759f3dcda8f..ca65d37220a0 100644
--- a/js/tests/visual/tooltip.html
+++ b/js/tests/visual/tooltip.html
@@ -59,7 +59,12 @@ Tooltip Bootstrap Visual Test
-
+
@@ -69,6 +74,21 @@ Tooltip Bootstrap Visual Test