]> git.ipfire.org Git - thirdparty/bootstrap.git/commitdiff
`prev()` function fails when non-element nodes are present (#30117)
authorMartijn Cuppens <martijn.cuppens@gmail.com>
Mon, 9 Mar 2020 15:21:04 +0000 (16:21 +0100)
committerGitHub <noreply@github.com>
Mon, 9 Mar 2020 15:21:04 +0000 (17:21 +0200)
The `prev()` function doesn't take nodes other than elements into account. Also we could simplify things a lot using the `previousElementSibling` property. This property isn't fully supported in IE, it only works for elements, but since the `element` variable is an element, we can safely use it here.

I've also added an additional test.

I don't think we had this issue in v4, since we relied on jQuery back then.

Ref. https://developer.mozilla.org/en-US/docs/Web/API/NonDocumentTypeChildNode/nextElementSibling

js/src/dom/selector-engine.js
js/tests/unit/dom/selector-engine.spec.js

index d66d8acfc85b176ebeafa21d3a94d1264aa5e28c..c9d25f68cb5fe659758c1c599d426b9cb59d75e3 100644 (file)
@@ -56,19 +56,17 @@ const SelectorEngine = {
   },
 
   prev(element, selector) {
-    const siblings = []
+    let previous = element.previousElementSibling
 
-    let previous = element.previousSibling
-
-    while (previous && previous.nodeType === Node.ELEMENT_NODE && previous.nodeType !== NODE_TEXT) {
+    while (previous) {
       if (this.matches(previous, selector)) {
-        siblings.push(previous)
+        return [previous]
       }
 
-      previous = previous.previousSibling
+      previous = previous.previousElementSibling
     }
 
-    return siblings
+    return []
   }
 }
 
index e13438e6fdf3bdb9fb0d283b4450248d31872551..e140c6a3e8f960dc341e9c59e799944973dc825a 100644 (file)
@@ -110,6 +110,21 @@ describe('SelectorEngine', () => {
 
       expect(SelectorEngine.prev(btn, '.test')).toEqual([divTest])
     })
+
+    it('should return previous element with comments or text nodes between', () => {
+      fixtureEl.innerHTML = [
+        '<div class="test"></div>',
+        '<div class="test"></div>',
+        '<!-- Comment-->',
+        'Text',
+        '<button class="btn"></button>'
+      ].join('')
+
+      const btn = fixtureEl.querySelector('.btn')
+      const divTest = fixtureEl.querySelectorAll('.test')[1]
+
+      expect(SelectorEngine.prev(btn, '.test')).toEqual([divTest])
+    })
   })
 })