Skip to content

Commit 1c12e2a

Browse files
committed
Implement :enabled/:disabled per the HTML5 spec. (Almost, see #6)
1 parent 3d8fd09 commit 1c12e2a

File tree

2 files changed

+39
-26
lines changed

2 files changed

+39
-26
lines changed

cssselect/tests.py

+18-16
Original file line numberDiff line numberDiff line change
@@ -426,7 +426,6 @@ def pcss(main, *selectors, **kwargs):
426426
return result
427427

428428
all_ids = pcss('*')
429-
assert len(all_ids) == 32
430429
assert all_ids[:6] == [
431430
'html', 'nil', 'link-href', 'link-nohref', 'nil', 'outer-div']
432431
assert all_ids[-1:] == ['foobar-span']
@@ -472,8 +471,7 @@ def pcss(main, *selectors, **kwargs):
472471
assert pcss('ol:nth-last-of-type(1)') == ['first-ol']
473472
assert pcss('span:only-child') == ['foobar-span']
474473
assert pcss('li div:only-child') == ['li-div']
475-
assert pcss('div *:only-child') == [
476-
'li-div', 'checkbox-disabled', 'foobar-span']
474+
assert pcss('div *:only-child') == ['li-div', 'foobar-span']
477475
self.assertRaises(ExpressionError, pcss, 'p *:only-of-type')
478476
self.assertRaises(ExpressionError, pcss, 'p:lang(fr)')
479477
assert pcss('p:only-of-type') == ['paragraph']
@@ -504,25 +502,25 @@ def pcss(main, *selectors, **kwargs):
504502
assert pcss('ol#first-ol *:last-child') == ['li-div', 'seventh-li']
505503
assert pcss('#outer-div:first-child') == ['outer-div']
506504
assert pcss('#outer-div :first-child') == [
507-
'name-anchor', 'first-li', 'li-div', 'p-b', 'checkbox-disabled',
508-
'area-href']
505+
'name-anchor', 'first-li', 'li-div', 'p-b',
506+
'checkbox-fieldset-disabled', 'area-href']
509507
assert pcss('a[href]') == ['tag-anchor', 'nofollow-anchor']
508+
assert pcss('a:not([href])') == ['name-anchor']
509+
assert pcss('ol :Not(li[class])') == [
510+
'first-li', 'second-li', 'li-div',
511+
'fifth-li', 'sixth-li', 'seventh-li']
510512

511-
513+
# HTML-specific
512514
assert pcss(':link', html_only=True) == [
513515
'link-href', 'tag-anchor', 'nofollow-anchor', 'area-href']
514516
assert pcss(':visited', html_only=True) == []
515-
517+
assert pcss(':enabled', html_only=True) == [
518+
'link-href', 'tag-anchor', 'nofollow-anchor',
519+
'checkbox-unchecked', 'checkbox-checked', 'area-href']
520+
assert pcss(':disabled', html_only=True) == [
521+
'checkbox-disabled', 'fieldset', 'checkbox-fieldset-disabled']
516522

517523
assert pcss(':checked', html_only=True) == ['checkbox-checked']
518-
assert pcss(':disabled', html_only=True) == [
519-
'fieldset', 'checkbox-disabled']
520-
assert pcss(':enabled', html_only=True) == [
521-
'checkbox-unchecked', 'checkbox-checked']
522-
assert pcss('a:not([href])') == ['name-anchor']
523-
assert pcss('ol :Not(li[class])') == [
524-
'first-li', 'second-li', 'li-div',
525-
'fifth-li', 'sixth-li', 'seventh-li']
526524

527525
def test_select_shakespeare(self):
528526
document = html.document_fromstring(HTML_SHAKESPEARE)
@@ -624,9 +622,13 @@ def count(selector):
624622
<b id="p-b">hi</b> <em id="p-em">there</em>
625623
<b id="p-b2">guy</b>
626624
<input type="checkbox" id="checkbox-unchecked" />
625+
<input type="checkbox" id="checkbox-disabled" disabled="disabled" />
626+
<input type="hidden" />
627+
<input type="hidden" disabled="disabled" />
627628
<input type="checkbox" id="checkbox-checked" checked="checked" />
628629
<fieldset id="fieldset" disabled="disabled">
629-
<input type="checkbox" id="checkbox-disabled" />
630+
<input type="checkbox" id="checkbox-fieldset-disabled" />
631+
<input type="hidden" />
630632
</fieldset>
631633
</p>
632634
<ol id="second-ol">

cssselect/xpath.py

+21-10
Original file line numberDiff line numberDiff line change
@@ -529,23 +529,21 @@ def xpath_disabled_pseudo(self, xpath):
529529
(
530530
@disabled and
531531
(
532-
name(.) = 'input' or
532+
(name(.) = 'input' and @type != 'hidden') or
533533
name(.) = 'button' or
534534
name(.) = 'select' or
535535
name(.) = 'textarea' or
536-
name(.) = 'keygen' or
537536
name(.) = 'command' or
538537
name(.) = 'fieldset' or
539538
name(.) = 'optgroup' or
540539
name(.) = 'option'
541540
)
542541
) or (
543542
(
544-
name(.) = 'input' or
543+
(name(.) = 'input' and @type != 'hidden') or
545544
name(.) = 'button' or
546545
name(.) = 'select' or
547-
name(.) = 'textarea' or
548-
name(.) = 'keygen'
546+
name(.) = 'textarea'
549547
)
550548
and ancestor::fieldset[@disabled]
551549
)
@@ -557,23 +555,36 @@ def xpath_enabled_pseudo(self, xpath):
557555
# http://www.w3.org/TR/html5/section-index.html#attributes-1
558556
return xpath.add_condition('''
559557
(
558+
@href and (
559+
name(.) = 'a' or
560+
name(.) = 'link' or
561+
name(.) = 'area'
562+
)
563+
) or (
560564
(
561565
name(.) = 'command' or
562566
name(.) = 'fieldset' or
563-
name(.) = 'optgroup' or
564-
name(.) = 'option'
567+
name(.) = 'optgroup'
565568
)
566569
and not(@disabled)
567570
) or (
568571
(
569-
name(.) = 'input' or
572+
(name(.) = 'input' and @type != 'hidden') or
570573
name(.) = 'button' or
571574
name(.) = 'select' or
572575
name(.) = 'textarea' or
573576
name(.) = 'keygen'
574577
)
575578
and not (@disabled or ancestor::fieldset[@disabled])
579+
) or (
580+
name(.) = 'option' and not(
581+
@disabled or ancestor::optgroup[@disabled]
582+
)
576583
)
577584
''')
578-
# FIXME: in the second half, add "and is not a descendant of that
579-
# fieldset element's first legend element child, if any."
585+
# FIXME: ... or "li elements that are children of menu elements,
586+
# and that have a child element that defines a command, if the first
587+
# such element's Disabled State facet is false (not disabled)".
588+
# FIXME: after ancestor::fieldset[@disabled], add "and is not a
589+
# descendant of that fieldset element's first legend element child,
590+
# if any."

0 commit comments

Comments
 (0)