Skip to content

Commit

Permalink
feat: keep order of preferred selector types when generating selector
Browse files Browse the repository at this point in the history
  • Loading branch information
fczbkk committed Nov 18, 2015
1 parent a8ca47f commit db3149b
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 51 deletions.
74 changes: 41 additions & 33 deletions src/css-selector-generator.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ class CssSelectorGenerator

default_options:
# choose from 'tag', 'id', 'class', 'nthchild', 'attribute'
selectors: ['tag', 'id', 'class', 'nthchild']
selectors: ['id', 'class', 'tag', 'nthchild']

constructor: (options = {}) ->
@options = {}
Expand Down Expand Up @@ -132,64 +132,72 @@ class CssSelectorGenerator
found_elements.length is 1 and found_elements[0] is element


getUniqueSelector: (element) ->
# helper function that tests all combinations for uniqueness
testCombinations: (element, items, tag) ->
for item in @getCombinations items
return item if @testUniqueness element, item

###
for selector_type in @options.selectors
console.log 'selector type', selector_type
###
# if tag selector is enabled, try attaching it
if tag?
for item in (items.map (item) -> tag + item)
return item if @testUniqueness element, item


getUniqueSelector: (element) ->
selectors = @getAllSelectors element

# ID selector (no need to check for uniqueness)
return selectors.i if selectors.i?
for selector_type in @options.selectors

# tag selector (should return unique for BODY)
if selectors.t?
return selectors.t if @testUniqueness element, selectors.t
switch selector_type

# class selector
if selectors.c? and selectors.c.length isnt 0
for item in @getCombinations selectors.c
return item if @testUniqueness element, item
# ID selector (no need to check for uniqueness)
when 'id'
if selectors.i?
return selectors.i

# if tag selector is enabled, try attaching it
if selectors.t?
for item in @getCombinations selectors.c, selectors.t
return item if @testUniqueness element, item
# tag selector (should return unique for BODY)
when 'tag'
if selectors.t?
return selectors.t if @testUniqueness element, selectors.t

# attribute selector
if selectors.a? and selectors.a.length isnt 0
for item in @getCombinations selectors.a
return item if @testUniqueness element, item
# class selector
when 'class'
if selectors.c? and selectors.c.length isnt 0
found_selector = @testCombinations element, selectors.c, selectors.t
return found_selector if found_selector

# if tag selector is enabled, try attaching it
if selectors.t?
for item in @getCombinations selectors.a, selectors.t
return item if @testUniqueness element, item
# attribute selector
when 'attribute'
if selectors.a? and selectors.a.length isnt 0
found_selector = @testCombinations element, selectors.a, selectors.t
return found_selector if found_selector

# if anything else fails, return n-th child selector
when 'nthchild'
if selectors.n?
return selectors.n

# if anything else fails, return n-th child selector
return selectors.n
return '*'


getSelector: (element) ->
all_selectors = []

parents = @getParents element
for item in parents
selector = @getUniqueSelector item
all_selectors.push selector if selector?

selectors = []
for item in all_selectors
selectors.unshift item
result = selectors.join ' > '
return result if @testSelector element, result
null


return null


getCombinations: (items = [], prefix = '') ->
getCombinations: (items = []) ->
# first item must be empty (seed), it will be removed later
result = [[]]

Expand All @@ -204,7 +212,7 @@ class CssSelectorGenerator
result = result.sort (a, b) -> a.length - b.length

# collapse combinations and add prefix
result = result.map (item) -> prefix + item.join ''
result = result.map (item) -> item.join ''

result

Expand Down
36 changes: 18 additions & 18 deletions test/src/css-selector-generator.spec.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,8 @@ describe 'CSS Selector Generator', ->
describe 'options', ->

it 'should use default set of allowed selectors', ->
expect(x.options.selectors).toEqual ['tag', 'id', 'class', 'nthchild']
expectation = ['tag', 'id', 'class', 'nthchild']
expect(x.options.selectors).toEqual jasmine.arrayContaining expectation

it 'should allow to customize allowed selectors', ->
x.setOptions selectors: ['attribute']
Expand All @@ -97,6 +98,17 @@ describe 'CSS Selector Generator', ->
x.setOptions selectors: ['tag']
expect(x.getSelector root.firstChild).toEqual null

it 'should keep order of prefered selector types', ->
root.innerHTML = '<div id="aaa"></div>'

x.setOptions selectors: ['id', 'tag', 'nthchild']
result = (x.getSelector root.firstChild).split(' > ').pop()
expect(result).toEqual '#aaa'

x.setOptions selectors: ['tag', 'id', 'nthchild']
result = (x.getSelector root.firstChild).split(' > ').pop()
expect(result).toEqual 'div'


describe 'selectors', ->

Expand Down Expand Up @@ -204,7 +216,7 @@ describe 'CSS Selector Generator', ->
expect(x.getClassSelectors root).toEqual []

it 'should use attribute selector when enabled', ->
x.setOptions selectors: ['tag', 'id', 'class', 'nthchild', 'attribute']
x.setOptions selectors: ['tag', 'id', 'class', 'attribute', 'nthchild']
root.innerHTML = '<a rel="aaa"></a><a rel="bbb"></a>'
result = x.getSelector root.firstChild
expect(result).toEqual '[rel=aaa]'
Expand Down Expand Up @@ -299,22 +311,10 @@ describe 'CSS Selector Generator', ->

it 'should return all possible combinations of items', ->
result = x.getCombinations ['a', 'b', 'c']
expect(result).toContain 'a'
expect(result).toContain 'b'
expect(result).toContain 'c'
expect(result).toContain 'ab'
expect(result).toContain 'ac'
expect(result).toContain 'bc'
expect(result).toContain 'abc'
expect(result).not.toContain ''
expect(result).not.toContain 'aa'
expectation = ['a', 'b', 'c', 'ab', 'ac', 'bc', 'abc']
expect(result).toEqual jasmine.arrayContaining expectation
expect(result).not.toEqual jasmine.arrayContaining ['', 'aa']

it 'should sort results from shortest to longest', ->
result = x.getCombinations ['a', 'b', 'c']
expect(result[6]).toEqual 'abc'

it 'should add prefix to combinations', ->
result = x.getCombinations ['a', 'b'], 'x'
expect(result).toContain 'xa'
expect(result).toContain 'xb'
expect(result).toContain 'xab'
expect(result.pop()).toEqual 'abc'

0 comments on commit db3149b

Please sign in to comment.