Skip to content

Commit

Permalink
feat: multi elements support for fallback
Browse files Browse the repository at this point in the history
  • Loading branch information
fczbkk committed Aug 15, 2021
1 parent 81f96a7 commit 991531d
Show file tree
Hide file tree
Showing 6 changed files with 49 additions and 13 deletions.
1 change: 1 addition & 0 deletions src/constants.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
export const DESCENDANT_OPERATOR = ' > '
export const CHILD_OPERATOR = ' '
export const SELECTOR_SEPARATOR = ', '

// RegExp that will match invalid patterns that can be used in ID attribute.
export const INVALID_ID_RE = new RegExp([
Expand Down
18 changes: 12 additions & 6 deletions src/selector-fallback.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,20 @@
import {getParents} from './utilities-dom'
import {getNthChildSelector} from './selector-nth-child'
import {DESCENDANT_OPERATOR} from './constants'
import {CssSelector} from './types'
import {DESCENDANT_OPERATOR, SELECTOR_SEPARATOR} from './constants';
import {CssSelector, SelectorNeedle} from './types';
import {sanitizeSelectorNeedle} from './utilities-selectors';

/**
* Creates chain if :nth-child selectors from root to the element.
*/
export function getFallbackSelector (element: Element): CssSelector {
export function constructFallbackSelector (element: Element): CssSelector {
const selectors = getParents(element)
.map((element) => getNthChildSelector(element)[0])
.reverse()
return [':root', ...selectors].join(DESCENDANT_OPERATOR)
}

/**
* Creates chain if :nth-child selectors from root to the element.
*/
export function getFallbackSelector (needle: SelectorNeedle): CssSelector {
const elements = sanitizeSelectorNeedle(needle)
return elements.map(constructFallbackSelector).join(SELECTOR_SEPARATOR)
}
2 changes: 2 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,5 @@ export type CssSelectorGeneratorOptions = {
export type IdentifiableParent =
null
| { foundElement: Element, selector: CssSelector }

export type SelectorNeedle = Element | Array<Element>
9 changes: 9 additions & 0 deletions src/utilities-dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,15 @@ export function testSelector (
return (result.length === 1 && result[0] === element)
}

export function testMultiSelector (
element: Element,
selector: CssSelector,
root: ParentNode = document
): boolean {
const result = [...root.querySelectorAll(selector)]
return result.includes(element)
}

/**
* Find all parent elements of the element.
*/
Expand Down
8 changes: 6 additions & 2 deletions src/utilities-selectors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ import {
CssSelectorData,
CssSelectorGeneratorOptions,
CssSelectorType,
IdentifiableParent
} from './types'
IdentifiableParent, SelectorNeedle
} from './types';

export const ESCAPED_COLON = ':'
.charCodeAt(0)
Expand Down Expand Up @@ -327,3 +327,7 @@ export function getClosestIdentifiableParent (
}
return null
}

export function sanitizeSelectorNeedle (needle: SelectorNeedle) {
return Array.isArray(needle) ? needle : [needle]
}
24 changes: 19 additions & 5 deletions test/selector-fallback.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import {assert} from 'chai'
import {getFallbackSelector} from '../src/selector-fallback.ts'
import {testSelector} from '../src/utilities-dom.ts'
import {testMultiSelector, testSelector} from '../src/utilities-dom.ts'

describe('selector - fallback', function () {

Expand All @@ -17,7 +17,7 @@ describe('selector - fallback', function () {
it('should produce simple selector', () => {
root.innerHTML = '<div></div>'
const needleElement = root.firstChild
const result = getFallbackSelector(needleElement, root)
const result = getFallbackSelector(needleElement)
assert.ok(testSelector(needleElement, result, root))
})

Expand All @@ -27,14 +27,14 @@ describe('selector - fallback', function () {
.firstElementChild
.firstElementChild
.firstElementChild
const result = getFallbackSelector(needleElement, root)
const result = getFallbackSelector(needleElement)
assert.ok(testSelector(needleElement, result, root))
})

it('should produce selector beside similar elements', () => {
root.innerHTML = '<div><div><div></div></div></div>'
const needleElement = root.firstElementChild
const result = getFallbackSelector(needleElement, root)
const result = getFallbackSelector(needleElement)
assert.ok(testSelector(needleElement, result, root))
})

Expand All @@ -57,7 +57,21 @@ describe('selector - fallback', function () {
.firstElementChild
.firstElementChild
.firstElementChild
const result = getFallbackSelector(needleElement, haystackElement)
const result = getFallbackSelector(needleElement)
assert.ok(testSelector(needleElement, result, haystackElement))
})

it('should produce selector for multiple elements', () => {
root.innerHTML = `
<div></div>
<div></div>
<div></div>
`
const needleElements = [...root.querySelectorAll('div')]
const result = getFallbackSelector(needleElements)
console.log('x', result)
needleElements.forEach((element) => {
assert.ok(testMultiSelector(element, result, root))
})
})
})

0 comments on commit 991531d

Please sign in to comment.