OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) | 2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org) |
3 * (C) 1999 Antti Koivisto (koivisto@kde.org) | 3 * (C) 1999 Antti Koivisto (koivisto@kde.org) |
4 * (C) 2001 Dirk Mueller (mueller@kde.org) | 4 * (C) 2001 Dirk Mueller (mueller@kde.org) |
5 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) | 5 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) |
6 * Copyright (C) 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. | 6 * Copyright (C) 2004, 2005, 2006, 2010 Apple Inc. All rights reserved. |
7 * Copyright (C) 2010 Google Inc. All rights reserved. | 7 * Copyright (C) 2010 Google Inc. All rights reserved. |
8 * Copyright (C) 2011 Motorola Mobility, Inc. All rights reserved. | 8 * Copyright (C) 2011 Motorola Mobility, Inc. All rights reserved. |
9 * | 9 * |
10 * This library is free software; you can redistribute it and/or | 10 * This library is free software; you can redistribute it and/or |
(...skipping 16 matching lines...) Expand all Loading... |
27 #include "config.h" | 27 #include "config.h" |
28 #include "core/html/HTMLOptionElement.h" | 28 #include "core/html/HTMLOptionElement.h" |
29 | 29 |
30 #include "bindings/core/v8/ExceptionState.h" | 30 #include "bindings/core/v8/ExceptionState.h" |
31 #include "core/HTMLNames.h" | 31 #include "core/HTMLNames.h" |
32 #include "core/dom/Document.h" | 32 #include "core/dom/Document.h" |
33 #include "core/dom/NodeRenderStyle.h" | 33 #include "core/dom/NodeRenderStyle.h" |
34 #include "core/dom/NodeTraversal.h" | 34 #include "core/dom/NodeTraversal.h" |
35 #include "core/dom/ScriptLoader.h" | 35 #include "core/dom/ScriptLoader.h" |
36 #include "core/dom/Text.h" | 36 #include "core/dom/Text.h" |
| 37 #include "core/dom/shadow/ShadowRoot.h" |
37 #include "core/html/HTMLDataListElement.h" | 38 #include "core/html/HTMLDataListElement.h" |
| 39 #include "core/html/HTMLOptGroupElement.h" |
38 #include "core/html/HTMLSelectElement.h" | 40 #include "core/html/HTMLSelectElement.h" |
39 #include "core/html/parser/HTMLParserIdioms.h" | 41 #include "core/html/parser/HTMLParserIdioms.h" |
40 #include "core/rendering/RenderTheme.h" | 42 #include "core/rendering/RenderTheme.h" |
41 #include "wtf/Vector.h" | 43 #include "wtf/Vector.h" |
42 #include "wtf/text/StringBuilder.h" | 44 #include "wtf/text/StringBuilder.h" |
43 | 45 |
44 namespace WebCore { | 46 namespace WebCore { |
45 | 47 |
46 using namespace HTMLNames; | 48 using namespace HTMLNames; |
47 | 49 |
48 HTMLOptionElement::HTMLOptionElement(Document& document) | 50 HTMLOptionElement::HTMLOptionElement(Document& document) |
49 : HTMLElement(optionTag, document) | 51 : HTMLElement(optionTag, document) |
50 , m_disabled(false) | 52 , m_disabled(false) |
51 , m_isSelected(false) | 53 , m_isSelected(false) |
52 { | 54 { |
53 setHasCustomStyleCallbacks(); | 55 setHasCustomStyleCallbacks(); |
54 ScriptWrappable::init(this); | 56 ScriptWrappable::init(this); |
55 } | 57 } |
56 | 58 |
57 PassRefPtrWillBeRawPtr<HTMLOptionElement> HTMLOptionElement::create(Document& do
cument) | 59 PassRefPtrWillBeRawPtr<HTMLOptionElement> HTMLOptionElement::create(Document& do
cument) |
58 { | 60 { |
59 return adoptRefWillBeNoop(new HTMLOptionElement(document)); | 61 RefPtrWillBeRawPtr<HTMLOptionElement> option = adoptRefWillBeNoop(new HTMLOp
tionElement(document)); |
| 62 option->ensureUserAgentShadowRoot(); |
| 63 return option.release(); |
60 } | 64 } |
61 | 65 |
62 PassRefPtrWillBeRawPtr<HTMLOptionElement> HTMLOptionElement::createForJSConstruc
tor(Document& document, const String& data, const AtomicString& value, | 66 PassRefPtrWillBeRawPtr<HTMLOptionElement> HTMLOptionElement::createForJSConstruc
tor(Document& document, const String& data, const AtomicString& value, |
63 bool defaultSelected, bool selected, ExceptionState& exceptionState) | 67 bool defaultSelected, bool selected, ExceptionState& exceptionState) |
64 { | 68 { |
65 RefPtrWillBeRawPtr<HTMLOptionElement> element = adoptRefWillBeNoop(new HTMLO
ptionElement(document)); | 69 RefPtrWillBeRawPtr<HTMLOptionElement> element = adoptRefWillBeNoop(new HTMLO
ptionElement(document)); |
| 70 element->ensureUserAgentShadowRoot(); |
66 element->appendChild(Text::create(document, data.isNull() ? "" : data), exce
ptionState); | 71 element->appendChild(Text::create(document, data.isNull() ? "" : data), exce
ptionState); |
67 if (exceptionState.hadException()) | 72 if (exceptionState.hadException()) |
68 return nullptr; | 73 return nullptr; |
69 | 74 |
70 if (!value.isNull()) | 75 if (!value.isNull()) |
71 element->setValue(value); | 76 element->setValue(value); |
72 if (defaultSelected) | 77 if (defaultSelected) |
73 element->setAttribute(selectedAttr, emptyAtom); | 78 element->setAttribute(selectedAttr, emptyAtom); |
74 element->setSelected(selected); | 79 element->setSelected(selected); |
75 | 80 |
(...skipping 12 matching lines...) Expand all Loading... |
88 } | 93 } |
89 HTMLElement::attach(optionContext); | 94 HTMLElement::attach(optionContext); |
90 } | 95 } |
91 | 96 |
92 void HTMLOptionElement::detach(const AttachContext& context) | 97 void HTMLOptionElement::detach(const AttachContext& context) |
93 { | 98 { |
94 m_style.clear(); | 99 m_style.clear(); |
95 HTMLElement::detach(context); | 100 HTMLElement::detach(context); |
96 } | 101 } |
97 | 102 |
98 bool HTMLOptionElement::rendererIsFocusable() const | |
99 { | |
100 // Option elements do not have a renderer so we check the renderStyle instea
d. | |
101 return renderStyle() && renderStyle()->display() != NONE; | |
102 } | |
103 | |
104 String HTMLOptionElement::text() const | 103 String HTMLOptionElement::text() const |
105 { | 104 { |
106 Document& document = this->document(); | 105 Document& document = this->document(); |
107 String text; | 106 String text; |
108 | 107 |
109 // WinIE does not use the label attribute, so as a quirk, we ignore it. | 108 // WinIE does not use the label attribute, so as a quirk, we ignore it. |
110 if (!document.inQuirksMode()) | 109 if (!document.inQuirksMode()) |
111 text = fastGetAttribute(labelAttr); | 110 text = fastGetAttribute(labelAttr); |
112 | 111 |
113 // FIXME: The following treats an element with the label attribute set to | 112 // FIXME: The following treats an element with the label attribute set to |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
181 bool oldDisabled = m_disabled; | 180 bool oldDisabled = m_disabled; |
182 m_disabled = !value.isNull(); | 181 m_disabled = !value.isNull(); |
183 if (oldDisabled != m_disabled) { | 182 if (oldDisabled != m_disabled) { |
184 didAffectSelector(AffectedSelectorDisabled | AffectedSelectorEnabled
); | 183 didAffectSelector(AffectedSelectorDisabled | AffectedSelectorEnabled
); |
185 if (renderer() && renderer()->style()->hasAppearance()) | 184 if (renderer() && renderer()->style()->hasAppearance()) |
186 RenderTheme::theme().stateChanged(renderer(), EnabledControlStat
e); | 185 RenderTheme::theme().stateChanged(renderer(), EnabledControlStat
e); |
187 } | 186 } |
188 } else if (name == selectedAttr) { | 187 } else if (name == selectedAttr) { |
189 if (bool willBeSelected = !value.isNull()) | 188 if (bool willBeSelected = !value.isNull()) |
190 setSelected(willBeSelected); | 189 setSelected(willBeSelected); |
| 190 } else if (name == labelAttr) { |
| 191 updateLabel(); |
191 } else | 192 } else |
192 HTMLElement::parseAttribute(name, value); | 193 HTMLElement::parseAttribute(name, value); |
193 } | 194 } |
194 | 195 |
195 String HTMLOptionElement::value() const | 196 String HTMLOptionElement::value() const |
196 { | 197 { |
197 const AtomicString& value = fastGetAttribute(valueAttr); | 198 const AtomicString& value = fastGetAttribute(valueAttr); |
198 if (!value.isNull()) | 199 if (!value.isNull()) |
199 return value; | 200 return value; |
200 return collectOptionInnerText().stripWhiteSpace(isHTMLSpace<UChar>).simplify
WhiteSpace(isHTMLSpace<UChar>); | 201 return collectOptionInnerText().stripWhiteSpace(isHTMLSpace<UChar>).simplify
WhiteSpace(isHTMLSpace<UChar>); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 if (HTMLSelectElement* select = ownerSelectElement()) | 245 if (HTMLSelectElement* select = ownerSelectElement()) |
245 select->invalidateSelectedItems(); | 246 select->invalidateSelectedItems(); |
246 } | 247 } |
247 | 248 |
248 void HTMLOptionElement::childrenChanged(const ChildrenChange& change) | 249 void HTMLOptionElement::childrenChanged(const ChildrenChange& change) |
249 { | 250 { |
250 if (HTMLDataListElement* dataList = ownerDataListElement()) | 251 if (HTMLDataListElement* dataList = ownerDataListElement()) |
251 dataList->optionElementChildrenChanged(); | 252 dataList->optionElementChildrenChanged(); |
252 else if (HTMLSelectElement* select = ownerSelectElement()) | 253 else if (HTMLSelectElement* select = ownerSelectElement()) |
253 select->optionElementChildrenChanged(); | 254 select->optionElementChildrenChanged(); |
| 255 updateLabel(); |
254 HTMLElement::childrenChanged(change); | 256 HTMLElement::childrenChanged(change); |
255 } | 257 } |
256 | 258 |
257 HTMLDataListElement* HTMLOptionElement::ownerDataListElement() const | 259 HTMLDataListElement* HTMLOptionElement::ownerDataListElement() const |
258 { | 260 { |
259 return Traversal<HTMLDataListElement>::firstAncestor(*this); | 261 return Traversal<HTMLDataListElement>::firstAncestor(*this); |
260 } | 262 } |
261 | 263 |
262 HTMLSelectElement* HTMLOptionElement::ownerSelectElement() const | 264 HTMLSelectElement* HTMLOptionElement::ownerSelectElement() const |
263 { | 265 { |
264 return Traversal<HTMLSelectElement>::firstAncestor(*this); | 266 return Traversal<HTMLSelectElement>::firstAncestor(*this); |
265 } | 267 } |
266 | 268 |
267 String HTMLOptionElement::label() const | 269 String HTMLOptionElement::label() const |
268 { | 270 { |
269 const AtomicString& label = fastGetAttribute(labelAttr); | 271 const AtomicString& label = fastGetAttribute(labelAttr); |
270 if (!label.isNull()) | 272 if (!label.isNull()) |
271 return label; | 273 return label; |
272 return collectOptionInnerText().stripWhiteSpace(isHTMLSpace<UChar>).simplify
WhiteSpace(isHTMLSpace<UChar>); | 274 return collectOptionInnerText().stripWhiteSpace(isHTMLSpace<UChar>).simplify
WhiteSpace(isHTMLSpace<UChar>); |
273 } | 275 } |
274 | 276 |
275 void HTMLOptionElement::setLabel(const AtomicString& label) | 277 void HTMLOptionElement::setLabel(const AtomicString& label) |
276 { | 278 { |
277 setAttribute(labelAttr, label); | 279 setAttribute(labelAttr, label); |
278 } | 280 } |
279 | 281 |
280 void HTMLOptionElement::updateNonRenderStyle() | 282 void HTMLOptionElement::updateNonRenderStyle() |
281 { | 283 { |
282 bool oldDisplayNoneStatus = isDisplayNone(); | |
283 m_style = originalStyleForRenderer(); | 284 m_style = originalStyleForRenderer(); |
284 if (oldDisplayNoneStatus != isDisplayNone()) { | 285 if (HTMLSelectElement* select = ownerSelectElement()) |
285 if (HTMLSelectElement* select = ownerSelectElement()) | 286 select->updateListOnRenderer(); |
286 select->updateListOnRenderer(); | |
287 } | |
288 } | 287 } |
289 | 288 |
290 RenderStyle* HTMLOptionElement::nonRendererStyle() const | 289 RenderStyle* HTMLOptionElement::nonRendererStyle() const |
291 { | 290 { |
292 return m_style.get(); | 291 return m_style.get(); |
293 } | 292 } |
294 | 293 |
295 PassRefPtr<RenderStyle> HTMLOptionElement::customStyleForRenderer() | 294 PassRefPtr<RenderStyle> HTMLOptionElement::customStyleForRenderer() |
296 { | 295 { |
297 updateNonRenderStyle(); | 296 updateNonRenderStyle(); |
(...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
336 // FIXME: Might be better to call this unconditionally, always passing m
_isSelected, | 335 // FIXME: Might be better to call this unconditionally, always passing m
_isSelected, |
337 // rather than only calling it if we are selected. | 336 // rather than only calling it if we are selected. |
338 if (m_isSelected) | 337 if (m_isSelected) |
339 select->optionSelectionStateChanged(this, true); | 338 select->optionSelectionStateChanged(this, true); |
340 select->scrollToSelection(); | 339 select->scrollToSelection(); |
341 } | 340 } |
342 | 341 |
343 return HTMLElement::insertedInto(insertionPoint); | 342 return HTMLElement::insertedInto(insertionPoint); |
344 } | 343 } |
345 | 344 |
| 345 void HTMLOptionElement::removedFrom(ContainerNode* insertionPoint) |
| 346 { |
| 347 if (HTMLSelectElement* select = Traversal<HTMLSelectElement>::firstAncestorO
rSelf(*insertionPoint)) |
| 348 select->optionRemoved(*this); |
| 349 HTMLElement::removedFrom(insertionPoint); |
| 350 } |
| 351 |
346 String HTMLOptionElement::collectOptionInnerText() const | 352 String HTMLOptionElement::collectOptionInnerText() const |
347 { | 353 { |
348 StringBuilder text; | 354 StringBuilder text; |
349 for (Node* node = firstChild(); node; ) { | 355 for (Node* node = firstChild(); node; ) { |
350 if (node->isTextNode()) | 356 if (node->isTextNode()) |
351 text.append(node->nodeValue()); | 357 text.append(node->nodeValue()); |
352 // Text nodes inside script elements are not part of the option text. | 358 // Text nodes inside script elements are not part of the option text. |
353 if (node->isElementNode() && toScriptLoaderIfPossible(toElement(node))) | 359 if (node->isElementNode() && toScriptLoaderIfPossible(toElement(node))) |
354 node = NodeTraversal::nextSkippingChildren(*node, this); | 360 node = NodeTraversal::nextSkippingChildren(*node, this); |
355 else | 361 else |
356 node = NodeTraversal::next(*node, this); | 362 node = NodeTraversal::next(*node, this); |
357 } | 363 } |
358 return text.toString(); | 364 return text.toString(); |
359 } | 365 } |
360 | 366 |
361 HTMLFormElement* HTMLOptionElement::form() const | 367 HTMLFormElement* HTMLOptionElement::form() const |
362 { | 368 { |
363 if (HTMLSelectElement* selectElement = ownerSelectElement()) | 369 if (HTMLSelectElement* selectElement = ownerSelectElement()) |
364 return selectElement->formOwner(); | 370 return selectElement->formOwner(); |
365 | 371 |
366 return 0; | 372 return 0; |
367 } | 373 } |
368 | 374 |
369 bool HTMLOptionElement::isDisplayNone() const | 375 void HTMLOptionElement::didAddUserAgentShadowRoot(ShadowRoot& root) |
370 { | 376 { |
371 ContainerNode* parent = parentNode(); | 377 updateLabel(); |
372 // Check for parent optgroup having display NONE | 378 } |
373 if (parent && isHTMLOptGroupElement(*parent)) { | 379 |
374 if (toHTMLOptGroupElement(*parent).isDisplayNone()) | 380 void HTMLOptionElement::updateLabel() |
375 return true; | 381 { |
376 } | 382 if (ShadowRoot* root = userAgentShadowRoot()) |
377 RenderStyle* style = nonRendererStyle(); | 383 root->setTextContent(textIndentedToRespectGroupLabel()); |
378 return style && style->display() == NONE; | 384 } |
| 385 |
| 386 bool HTMLOptionElement::spatialNavigationFocused() const |
| 387 { |
| 388 HTMLSelectElement* select = ownerSelectElement(); |
| 389 if (!select || !select->focused()) |
| 390 return false; |
| 391 return select->spatialNavigationFocusedOption() == this; |
379 } | 392 } |
380 | 393 |
381 } // namespace WebCore | 394 } // namespace WebCore |
OLD | NEW |