1 /*
2 * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public License
15 * along with this library; see the file COPYING.LIB. If not, write to
16 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 *
19 */
20
21 #include "config.h"
22 #include "OptionElement.h"
23
24 #include "Document.h"
25 #include "Element.h"
26 #include "HTMLNames.h"
27 #include "HTMLOptionElement.h"
28 #include "OptionGroupElement.h"
29 #include "ScriptElement.h"
30 #include "SelectElement.h"
31 #include <wtf/Assertions.h>
32
33 #if ENABLE(WML)
34 #include "WMLOptionElement.h"
35 #include "WMLNames.h"
36 #endif
37
38 namespace WebCore {
39
setSelectedState(OptionElementData & data,Element * element,bool selected)40 void OptionElement::setSelectedState(OptionElementData& data, Element* element, bool selected)
41 {
42 if (data.selected() == selected)
43 return;
44
45 data.setSelected(selected);
46 element->setNeedsStyleRecalc();
47 }
48
optionIndex(SelectElement * selectElement,const Element * element)49 int OptionElement::optionIndex(SelectElement* selectElement, const Element* element)
50 {
51 if (!selectElement)
52 return 0;
53
54 // Let's do this dynamically. Might be a bit slow, but we're sure
55 // we won't forget to update a member variable in some cases...
56 const Vector<Element*>& items = selectElement->listItems();
57 int length = items.size();
58 int optionIndex = 0;
59 for (int i = 0; i < length; ++i) {
60 if (!isOptionElement(items[i]))
61 continue;
62 if (items[i] == element)
63 return optionIndex;
64 ++optionIndex;
65 }
66
67 return 0;
68 }
69
collectOptionLabelOrText(const OptionElementData & data,const Element * element)70 String OptionElement::collectOptionLabelOrText(const OptionElementData& data, const Element* element)
71 {
72 Document* document = element->document();
73 String text;
74
75 // WinIE does not use the label attribute, so as a quirk, we ignore it.
76 if (!document->inCompatMode())
77 text = data.label();
78 if (text.isEmpty())
79 text = collectOptionInnerText(element);
80 return normalizeText(document, text);
81 }
82
collectOptionInnerText(const Element * element)83 String OptionElement::collectOptionInnerText(const Element* element)
84 {
85 String text;
86 Node* n = element->firstChild();
87 while (n) {
88 if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SECTION_NODE)
89 text += n->nodeValue();
90
91 // skip script content
92 if (n->isElementNode() && toScriptElement(static_cast<Element*>(n)))
93 n = n->traverseNextSibling(element);
94 else
95 n = n->traverseNextNode(element);
96 }
97 return text;
98 }
99
normalizeText(const Document * document,const String & src)100 String OptionElement::normalizeText(const Document* document, const String& src)
101 {
102 String text = document->displayStringModifiedByEncoding(src);
103
104 // In WinIE, leading and trailing whitespace is ignored in options and optgroups. We match this behavior.
105 text = text.stripWhiteSpace();
106
107 // We want to collapse our whitespace too. This will match other browsers.
108 text = text.simplifyWhiteSpace();
109 return text;
110 }
111
collectOptionTextRespectingGroupLabel(const OptionElementData & data,const Element * element)112 String OptionElement::collectOptionTextRespectingGroupLabel(const OptionElementData& data, const Element* element)
113 {
114 Element* parentElement = static_cast<Element*>(element->parentNode());
115 if (parentElement && toOptionGroupElement(parentElement))
116 return " " + collectOptionLabelOrText(data, element);
117
118 return collectOptionLabelOrText(data, element);
119 }
120
collectOptionValue(const OptionElementData & data,const Element * element)121 String OptionElement::collectOptionValue(const OptionElementData& data, const Element* element)
122 {
123 String value = data.value();
124 if (!value.isNull())
125 return value;
126
127 // Use the text if the value wasn't set.
128 return collectOptionInnerText(element).stripWhiteSpace();
129 }
130
131 // OptionElementData
OptionElementData()132 OptionElementData::OptionElementData()
133 : m_selected(false)
134 {
135 }
136
toOptionElement(Element * element)137 OptionElement* toOptionElement(Element* element)
138 {
139 if (element->isHTMLElement() && element->hasTagName(HTMLNames::optionTag))
140 return static_cast<HTMLOptionElement*>(element);
141
142 #if ENABLE(WML)
143 if (element->isWMLElement() && element->hasTagName(WMLNames::optionTag))
144 return static_cast<WMLOptionElement*>(element);
145 #endif
146
147 return 0;
148 }
149
isOptionElement(Element * element)150 bool isOptionElement(Element* element)
151 {
152 return element->hasLocalName(HTMLNames::optionTag)
153 #if ENABLE(WML)
154 || element->hasLocalName(WMLNames::optionTag)
155 #endif
156 ;
157 }
158
159 }
160