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