1/*
2 * Copyright (C) 2012 Google Inc. All rights reserved.
3 * Copyright (C) 2018 Apple Inc. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24 * SUCH DAMAGE.
25 */
26
27#include "config.h"
28#include "BaseChooserOnlyDateAndTimeInputType.h"
29
30#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
31
32#include "HTMLDivElement.h"
33#include "HTMLInputElement.h"
34#include "Page.h"
35#include "RenderElement.h"
36#include "ShadowRoot.h"
37#include "UserGestureIndicator.h"
38#include <wtf/NeverDestroyed.h>
39
40namespace WebCore {
41
42BaseChooserOnlyDateAndTimeInputType::~BaseChooserOnlyDateAndTimeInputType()
43{
44 closeDateTimeChooser();
45}
46
47void BaseChooserOnlyDateAndTimeInputType::handleDOMActivateEvent(Event&)
48{
49 ASSERT(element());
50 if (element()->isDisabledOrReadOnly() || !element()->renderer() || !UserGestureIndicator::processingUserGesture())
51 return;
52
53 if (m_dateTimeChooser)
54 return;
55 if (!element()->document().page())
56 return;
57 DateTimeChooserParameters parameters;
58 if (!element()->setupDateTimeChooserParameters(parameters))
59 return;
60}
61
62void BaseChooserOnlyDateAndTimeInputType::createShadowSubtree()
63{
64 static NeverDestroyed<AtomicString> valueContainerPseudo("-webkit-date-and-time-value", AtomicString::ConstructFromLiteral);
65
66 ASSERT(element());
67 auto valueContainer = HTMLDivElement::create(element()->document());
68 valueContainer->setPseudo(valueContainerPseudo);
69 element()->userAgentShadowRoot()->appendChild(valueContainer);
70 updateInnerTextValue();
71}
72
73void BaseChooserOnlyDateAndTimeInputType::updateInnerTextValue()
74{
75 ASSERT(element());
76 RefPtr<Node> node = element()->userAgentShadowRoot()->firstChild();
77 if (!is<HTMLElement>(node))
78 return;
79 String displayValue = visibleValue();
80 if (displayValue.isEmpty()) {
81 // Need to put something to keep text baseline.
82 displayValue = " "_s;
83 }
84 downcast<HTMLElement>(*node).setInnerText(displayValue);
85}
86
87void BaseChooserOnlyDateAndTimeInputType::setValue(const String& value, bool valueChanged, TextFieldEventBehavior eventBehavior)
88{
89 BaseDateAndTimeInputType::setValue(value, valueChanged, eventBehavior);
90 if (valueChanged)
91 updateInnerTextValue();
92}
93
94void BaseChooserOnlyDateAndTimeInputType::detach()
95{
96 closeDateTimeChooser();
97}
98
99void BaseChooserOnlyDateAndTimeInputType::didChooseValue(const String& value)
100{
101 ASSERT(element());
102 element()->setValue(value, DispatchInputAndChangeEvent);
103}
104
105void BaseChooserOnlyDateAndTimeInputType::didEndChooser()
106{
107 m_dateTimeChooser = nullptr;
108}
109
110void BaseChooserOnlyDateAndTimeInputType::closeDateTimeChooser()
111{
112 if (m_dateTimeChooser)
113 m_dateTimeChooser->endChooser();
114}
115
116auto BaseChooserOnlyDateAndTimeInputType::handleKeydownEvent(KeyboardEvent& event) -> ShouldCallBaseEventHandler
117{
118 ASSERT(element());
119 return BaseClickableWithKeyInputType::handleKeydownEvent(*element(), event);
120}
121
122void BaseChooserOnlyDateAndTimeInputType::handleKeypressEvent(KeyboardEvent& event)
123{
124 ASSERT(element());
125 BaseClickableWithKeyInputType::handleKeypressEvent(*element(), event);
126}
127
128void BaseChooserOnlyDateAndTimeInputType::handleKeyupEvent(KeyboardEvent& event)
129{
130 BaseClickableWithKeyInputType::handleKeyupEvent(*this, event);
131}
132
133void BaseChooserOnlyDateAndTimeInputType::accessKeyAction(bool sendMouseEvents)
134{
135 BaseDateAndTimeInputType::accessKeyAction(sendMouseEvents);
136 ASSERT(element());
137 BaseClickableWithKeyInputType::accessKeyAction(*element(), sendMouseEvents);
138}
139
140bool BaseChooserOnlyDateAndTimeInputType::isMouseFocusable() const
141{
142 ASSERT(element());
143 return element()->isTextFormControlFocusable();
144}
145
146void BaseChooserOnlyDateAndTimeInputType::attributeChanged(const QualifiedName& name)
147{
148 if (name == valueAttr) {
149 if (auto* element = this->element()) {
150 if (!element->hasDirtyValue())
151 updateInnerTextValue();
152 }
153 }
154 BaseDateAndTimeInputType::attributeChanged(name);
155}
156
157}
158
159#endif
160