Skip to content

Commit 1fc35e3

Browse files
committed
Implement :open for <input>
https://bugs.webkit.org/show_bug.cgi?id=307798 Reviewed by Aditya Keerthi. Re-implement isPresentingAttachedView() in terms of m_popupIsVisible tracked by TextFieldInputType, ColorInputType, and BaseDateAndTimeInputType as the original approach did not work correctly. For instance, <input type=color> has two pickers. An initial picker and a platform picker. When the initial picker is closed endColorChooser() is called. When the platform picker is closed, didEndChooser(). But never both. The code however assumed the latter would always be called. There's also an issue with the existing test-only showPicker() implementation, which is that it does not focus the elements. This means that they can also not be blurred and the picker ends up being hard to close. For this reason we add new web-platform-tests coverage for the non-showPicker() case so :open can be adequately tested. We also clean up these classes a tiny bit while here. Tests: web-platform-tests/wpt#57990 Canonical link: https://commits.webkit.org/308148@main
1 parent 1bb4aac commit 1fc35e3

15 files changed

+187
-98
lines changed
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
reset
2+
3+
4+
5+
PASS CSS :open for <input type=date>
6+
PASS CSS :open for <input type=datetime-local>
7+
FAIL CSS :open for <input type=week> assert_true: Should match :open after opening the picker. expected true got false
8+
FAIL CSS :open for <input type=month> assert_true: Should match :open after opening the picker. expected true got false
9+
FAIL CSS :open for <input type=time> assert_true: Should match :open after opening the picker. expected true got false
10+
PASS CSS :open for <input type=color>
11+
PASS CSS :open for <input type=text list=datalist>
12+
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
<!DOCTYPE html>
2+
<link rel=help href="https://drafts.csswg.org/css-pseudo-4/#open-pseudo">
3+
<script src="/resources/testharness.js"></script>
4+
<script src="/resources/testharnessreport.js"></script>
5+
<script src="/resources/testdriver.js"></script>
6+
<script src="/resources/testdriver-vendor.js"></script>
7+
8+
<!-- Like input-element-pseudo-open.optional.html but uses clicking to open
9+
pickers rather than showPicker(). -->
10+
11+
<button>reset</button>
12+
13+
<div class=supported>
14+
<input type=date>
15+
<input type=datetime-local>
16+
<input type=week>
17+
<input type=month>
18+
<input type=time>
19+
<input type=color>
20+
</div>
21+
22+
<input type=text list=datalist>
23+
<datalist id=datalist>
24+
<option>one</option>
25+
<option>two</option>
26+
</datalist>
27+
28+
<script>
29+
document.querySelectorAll('.supported > input').forEach(input => {
30+
const inputType = input.getAttribute('type');
31+
promise_test(async () => {
32+
assert_false(input.matches(':open'),
33+
'Should not match :open at the start of the test.');
34+
35+
await test_driver.click(input);
36+
assert_true(input.matches(':open'),
37+
'Should match :open after opening the picker.');
38+
39+
await test_driver.click(document.querySelector('button'));
40+
assert_false(input.matches(':open'),
41+
'Should not match :open after closing the picker.');
42+
}, `CSS :open for <input type=${inputType}>`);
43+
});
44+
45+
promise_test(async () => {
46+
const input = document.querySelector('input[list]');
47+
await test_driver.click(input);
48+
assert_true(input.matches(':open'),
49+
'Should match :open after opening the list.');
50+
51+
await test_driver.click(document.querySelector('button'));
52+
assert_false(input.matches(':open'),
53+
'Should not match :open after closing the list.');
54+
55+
}, 'CSS :open for <input type=text list=datalist>');
56+
</script>

LayoutTests/imported/w3c/web-platform-tests/css/css-pseudo/input-element-pseudo-open.optional-expected.txt

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@ reset
22

33

44

5-
FAIL CSS :open for <input type=date> assert_true: Should match :open after opening the picker. expected true got false
6-
FAIL CSS :open for <input type=datetime-local> assert_true: Should match :open after opening the picker. expected true got false
5+
FAIL CSS :open for <input type=date> assert_false: Should not match :open after closing the picker. expected false got true
6+
FAIL CSS :open for <input type=datetime-local> assert_false: Should not match :open after closing the picker. expected false got true
77
FAIL CSS :open for <input type=week> assert_true: Should match :open after opening the picker. expected true got false
88
FAIL CSS :open for <input type=month> assert_true: Should match :open after opening the picker. expected true got false
99
FAIL CSS :open for <input type=time> assert_true: Should match :open after opening the picker. expected true got false
10-
FAIL CSS :open for <input type=color> assert_true: Should match :open after opening the picker. expected true got false
11-
PASS CSS :open for <input type=text list=datalist>
10+
FAIL CSS :open for <input type=color> assert_false: Should not match :open after closing the picker. expected false got true
11+
FAIL CSS :open for <input type=text list=datalist> assert_true: Should match :open after opening the list. expected true got false
1212

LayoutTests/imported/w3c/web-platform-tests/css/css-pseudo/input-element-pseudo-open.optional.html

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,7 @@
88

99
<!-- This test is marked as optional because the specification does not mandate
1010
which particular elements support pickers or not. Picker support for elements
11-
varies across browsers and platforms. This test reflects picker support in
12-
desktop chromium. -->
11+
varies across browsers and platforms. -->
1312

1413
<button>reset</button>
1514

@@ -49,8 +48,16 @@
4948
// TODO(crbug.com/383306186): Support :open for <input type=text list=datalist>
5049
promise_test(async () => {
5150
const input = document.querySelector('input[list]');
52-
await test_driver.click(input);
5351
assert_false(input.matches(':open'),
54-
':open is not supported yet.');
52+
'Should not match :open at the start of the test.');
53+
54+
await test_driver.bless();
55+
input.showPicker();
56+
assert_true(input.matches(':open'),
57+
'Should match :open after opening the list.');
58+
59+
await test_driver.click(document.querySelector('button'));
60+
assert_false(input.matches(':open'),
61+
'Should not match :open after closing the list.');
5562
}, 'CSS :open for <input type=text list=datalist>');
5663
</script>

LayoutTests/platform/ios/TestExpectations

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3857,6 +3857,7 @@ imported/w3c/web-platform-tests/css/css-pseudo/highlight-cascade/highlight-casca
38573857
imported/w3c/web-platform-tests/css/css-pseudo/highlight-styling-001.html [ Pass ]
38583858
imported/w3c/web-platform-tests/css/css-pseudo/highlight-styling-004.html [ ImageOnlyFailure ]
38593859
imported/w3c/web-platform-tests/css/css-pseudo/highlight-custom-properties-dynamic-001.html [ Pass ]
3860+
imported/w3c/web-platform-tests/css/css-pseudo/input-element-pseudo-open-click.optional.html [ Skip ]
38603861

38613862
imported/w3c/web-platform-tests/css/css-transforms/ttwf-css-3d-polygon-cycle.html [ ImageOnlyFailure ]
38623863

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
reset
2+
3+
4+
5+
FAIL CSS :open for <input type=date> assert_true: Should match :open after opening the picker. expected true got false
6+
FAIL CSS :open for <input type=datetime-local> assert_true: Should match :open after opening the picker. expected true got false
7+
FAIL CSS :open for <input type=week> assert_true: Should match :open after opening the picker. expected true got false
8+
FAIL CSS :open for <input type=month> assert_true: Should match :open after opening the picker. expected true got false
9+
FAIL CSS :open for <input type=time> assert_true: Should match :open after opening the picker. expected true got false
10+
FAIL CSS :open for <input type=color> assert_false: Should not match :open after closing the picker. expected false got true
11+
FAIL CSS :open for <input type=text list=datalist> assert_true: Should match :open after opening the list. expected true got false
12+

Source/WebCore/SaferCPPExpectations/UncheckedCallArgsCheckerExpectations

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,6 @@ html/MediaElementSession.cpp
190190
html/ModelDocument.cpp
191191
[ Mac ] html/RangeInputType.cpp
192192
[ Mac ] html/ResetInputType.cpp
193-
[ Mac ] html/TextFieldInputType.cpp
194193
html/ValidatedFormListedElement.cpp
195194
html/ValidationMessage.cpp
196195
html/canvas/CanvasRenderingContext2D.cpp

Source/WebCore/SaferCPPExpectations/UncountedCallArgsCheckerExpectations

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,6 @@ html/ModelDocument.cpp
359359
html/OffscreenCanvas.cpp
360360
[ Mac ] html/RangeInputType.cpp
361361
[ Mac ] html/ResetInputType.cpp
362-
html/TextFieldInputType.cpp
363362
html/ValidatedFormListedElement.cpp
364363
html/ValidationMessage.cpp
365364
html/canvas/CanvasFilterContextSwitcher.cpp

Source/WebCore/css/SelectorCheckerTestFunctions.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -600,6 +600,8 @@ ALWAYS_INLINE bool matchesOpenPseudoClass(const Element& element)
600600
return details->isOpen();
601601
if (auto* select = dynamicDowncast<HTMLSelectElement>(element))
602602
return select->isOpen();
603+
if (auto* input = dynamicDowncast<HTMLInputElement>(element))
604+
return input->isPresentingAttachedView();
603605

604606
return false;
605607
}

Source/WebCore/html/BaseDateAndTimeInputType.cpp

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#include "BaseClickableWithKeyInputType.h"
3737
#include "Chrome.h"
3838
#include "ContainerNodeInlines.h"
39+
#include "CSSSelector.h"
3940
#include "DateComponents.h"
4041
#include "DateTimeChooserParameters.h"
4142
#include "Decimal.h"
@@ -51,6 +52,7 @@
5152
#include "LocalFrameView.h"
5253
#include "NodeName.h"
5354
#include "PlatformLocale.h"
55+
#include "PseudoClassChangeInvalidation.h"
5456
#include "RenderElement.h"
5557
#include "ScriptDisallowedScope.h"
5658
#include "Settings.h"
@@ -269,16 +271,6 @@ ValueOrReference<String> BaseDateAndTimeInputType::sanitizeValue(const String& p
269271
return proposedValue;
270272
}
271273

272-
bool BaseDateAndTimeInputType::supportsReadOnly() const
273-
{
274-
return true;
275-
}
276-
277-
bool BaseDateAndTimeInputType::shouldRespectListAttribute()
278-
{
279-
return false;
280-
}
281-
282274
bool BaseDateAndTimeInputType::valueMissing(const String& value) const
283275
{
284276
ASSERT(element());
@@ -377,8 +369,7 @@ void BaseDateAndTimeInputType::showPicker()
377369

378370
if (auto* chrome = this->chrome()) {
379371
m_dateTimeChooser = chrome->createDateTimeChooser(*this);
380-
if (RefPtr dateTimeChooser = m_dateTimeChooser)
381-
dateTimeChooser->showChooser(parameters);
372+
showDateTimeChooser(parameters);
382373
}
383374
}
384375

@@ -496,9 +487,22 @@ void BaseDateAndTimeInputType::detach()
496487
closeDateTimeChooser();
497488
}
498489

499-
bool BaseDateAndTimeInputType::isPresentingAttachedView() const
490+
void BaseDateAndTimeInputType::setPopupIsVisible(bool visible)
500491
{
501-
return !!m_dateTimeChooser;
492+
if (m_popupIsVisible == visible || !element())
493+
return;
494+
Style::PseudoClassChangeInvalidation styleInvalidation(*protect(element()), CSSSelector::PseudoClass::Open, visible);
495+
m_popupIsVisible = visible;
496+
}
497+
498+
void BaseDateAndTimeInputType::showDateTimeChooser(const DateTimeChooserParameters& parameters)
499+
{
500+
RefPtr dateTimeChooser = m_dateTimeChooser;
501+
if (!dateTimeChooser)
502+
return;
503+
504+
setPopupIsVisible(true);
505+
dateTimeChooser->showChooser(parameters);
502506
}
503507

504508
auto BaseDateAndTimeInputType::handleKeydownEvent(KeyboardEvent& event) -> ShouldCallBaseEventHandler
@@ -591,8 +595,7 @@ void BaseDateAndTimeInputType::didChangeValueFromControl()
591595
if (!setupDateTimeChooserParameters(parameters))
592596
return;
593597

594-
if (RefPtr dateTimeChooser = m_dateTimeChooser)
595-
dateTimeChooser->showChooser(parameters);
598+
showDateTimeChooser(parameters);
596599
}
597600

598601
void BaseDateAndTimeInputType::didReceiveSpaceKeyFromControl()
@@ -605,15 +608,14 @@ void BaseDateAndTimeInputType::didReceiveSpaceKeyFromControl()
605608
m_pickerWasActivatedByKeyboard = true;
606609
m_didTransferFocusToPicker = true;
607610

608-
RefPtr chooser = m_dateTimeChooser;
609-
if (!chooser) {
611+
if (!m_dateTimeChooser) {
610612
showPicker();
611613
return;
612614
}
613615

614616
DateTimeChooserParameters parameters;
615617
if (setupDateTimeChooserParameters(parameters))
616-
chooser->showChooser(parameters);
618+
showDateTimeChooser(parameters);
617619
}
618620

619621
bool BaseDateAndTimeInputType::isEditControlOwnerDisabled() const
@@ -640,6 +642,12 @@ void BaseDateAndTimeInputType::didChooseValue(StringView value)
640642
protect(element())->setValue(value.toString(), DispatchInputAndChangeEvent);
641643
}
642644

645+
void BaseDateAndTimeInputType::didEndChooser()
646+
{
647+
m_dateTimeChooser = nullptr;
648+
setPopupIsVisible(false);
649+
}
650+
643651
bool BaseDateAndTimeInputType::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters)
644652
{
645653
ASSERT(element());
@@ -704,6 +712,7 @@ void BaseDateAndTimeInputType::closeDateTimeChooser()
704712
{
705713
if (RefPtr dateTimeChooser = m_dateTimeChooser)
706714
dateTimeChooser->endChooser();
715+
setPopupIsVisible(false);
707716

708717
m_didTransferFocusToPicker = false;
709718
m_pickerWasActivatedByKeyboard = false;

0 commit comments

Comments
 (0)