1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package org.htmlunit.html;
16
17 import static org.htmlunit.util.StringUtils.toRootLowerCase;
18
19 import java.io.IOException;
20 import java.util.Map;
21
22 import org.htmlunit.Page;
23 import org.htmlunit.ScriptResult;
24 import org.htmlunit.SgmlPage;
25 import org.htmlunit.javascript.host.event.Event;
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42 public class HtmlRadioButtonInput extends HtmlInput implements LabelableElement {
43
44
45
46
47 private static final String DEFAULT_VALUE = "on";
48
49 private boolean defaultCheckedState_;
50 private boolean checkedState_;
51
52
53
54
55
56
57
58
59
60
61
62 HtmlRadioButtonInput(final String qualifiedName, final SgmlPage page,
63 final Map<String, DomAttr> attributes) {
64 super(qualifiedName, page, attributes);
65
66 if (getAttributeDirect(VALUE_ATTRIBUTE) == ATTRIBUTE_NOT_DEFINED) {
67 setRawValue(DEFAULT_VALUE);
68 }
69
70 defaultCheckedState_ = hasAttribute(ATTRIBUTE_CHECKED);
71 checkedState_ = defaultCheckedState_;
72 }
73
74
75
76
77
78 @Override
79 public boolean isChecked() {
80 return checkedState_;
81 }
82
83
84
85
86
87 @Override
88 public void reset() {
89 setChecked(defaultCheckedState_);
90 }
91
92 void setCheckedInternal(final boolean isChecked) {
93 checkedState_ = isChecked;
94 }
95
96
97
98
99
100
101
102
103 @Override
104 public Page setChecked(final boolean isChecked) {
105 Page page = getPage();
106
107 final boolean changed = isChecked() != isChecked;
108 checkedState_ = isChecked;
109 if (isChecked) {
110 updateRadioButtonSelection(page);
111 }
112
113 if (changed) {
114 final ScriptResult scriptResult = fireEvent(Event.TYPE_CHANGE);
115 if (scriptResult != null && page != null) {
116 page = page.getEnclosingWindow().getWebClient().getCurrentWindow().getEnclosedPage();
117 }
118 }
119 return page;
120 }
121
122
123
124
125
126
127
128
129 @Override
130 protected boolean doClickStateUpdate(final boolean shiftKey, final boolean ctrlKey) throws IOException {
131 final boolean changed = !isChecked();
132 updateRadioButtonSelection(getPage());
133
134 super.doClickStateUpdate(shiftKey, ctrlKey);
135 return changed;
136 }
137
138
139
140
141 private void updateRadioButtonSelection(final Page page) {
142 final HtmlForm form = getEnclosingForm();
143 if (form != null) {
144 form.setCheckedRadioButton(this);
145 }
146 else if (page != null && page.isHtmlPage()) {
147 setCheckedForPage((HtmlPage) page);
148 }
149 }
150
151
152
153
154 private void setCheckedForPage(final HtmlPage htmlPage) {
155 final String name = getNameAttribute();
156 for (final HtmlElement htmlElement : htmlPage.getHtmlElementDescendants()) {
157 if (htmlElement instanceof HtmlRadioButtonInput radioInput) {
158 if (name.equals(radioInput.getNameAttribute())
159 && radioInput.getEnclosingForm() == null) {
160 radioInput.setCheckedInternal(radioInput == this);
161 }
162 }
163 }
164 }
165
166
167
168
169 @Override
170 protected void doClickFireChangeEvent() {
171 executeOnChangeHandlerIfAppropriate(this);
172 }
173
174
175
176
177 @Override
178 protected void preventDefault() {
179 checkedState_ = !checkedState_;
180 }
181
182
183
184
185
186
187 @Override
188 public void setDefaultValue(final String defaultValue) {
189 super.setDefaultValue(defaultValue);
190 setValue(defaultValue);
191 }
192
193
194
195
196
197 @Override
198 public void setValue(final String newValue) {
199 super.setValue(newValue);
200 super.setDefaultValue(newValue);
201 }
202
203
204
205
206
207 @Override
208 public void setDefaultChecked(final boolean defaultChecked) {
209 defaultCheckedState_ = defaultChecked;
210 setChecked(isDefaultChecked());
211 }
212
213
214
215
216
217 @Override
218 public boolean isDefaultChecked() {
219 return defaultCheckedState_;
220 }
221
222
223
224
225 @Override
226 protected boolean isStateUpdateFirst() {
227 return true;
228 }
229
230
231
232
233 @Override
234 protected void onAddedToPage() {
235 super.onAddedToPage();
236 setChecked(isChecked());
237 }
238
239 @Override
240 protected Object getInternalValue() {
241 return isChecked();
242 }
243
244 @Override
245 void handleFocusLostValueChanged() {
246
247 }
248
249
250
251
252 @Override
253 protected void setAttributeNS(final String namespaceURI, final String qualifiedName, final String attributeValue,
254 final boolean notifyAttributeChangeListeners, final boolean notifyMutationObservers) {
255 final String qualifiedNameLC = toRootLowerCase(qualifiedName);
256
257 if (VALUE_ATTRIBUTE.equals(qualifiedNameLC)) {
258 super.setAttributeNS(namespaceURI, qualifiedNameLC, attributeValue, notifyAttributeChangeListeners,
259 notifyMutationObservers);
260 setRawValue(attributeValue);
261 return;
262 }
263
264 if (ATTRIBUTE_CHECKED.equals(qualifiedNameLC)) {
265 checkedState_ = true;
266 }
267 super.setAttributeNS(namespaceURI, qualifiedNameLC, attributeValue, notifyAttributeChangeListeners,
268 notifyMutationObservers);
269 }
270
271
272
273
274 @Override
275 protected boolean propagateClickStateUpdateToParent() {
276 return false;
277 }
278
279 @Override
280 public boolean isValueMissingValidityState() {
281 if (ATTRIBUTE_NOT_DEFINED == getAttributeDirect(ATTRIBUTE_REQUIRED)) {
282 return false;
283 }
284 final String name = getNameAttribute();
285 if (ATTRIBUTE_NOT_DEFINED == name) {
286 return false;
287 }
288
289 for (final HtmlElement htmlElement : getPage().getHtmlElementDescendants()) {
290 if (htmlElement instanceof HtmlRadioButtonInput radioInput) {
291 if (name.equals(radioInput.getNameAttribute()) && radioInput.isChecked()) {
292 return false;
293 }
294 }
295 }
296 return true;
297 }
298 }