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 namespace WebCore {
34
setSelectedState(OptionElementData & data,Element * element,bool selected)35 void OptionElement::setSelectedState(OptionElementData& data, Element* element, bool selected)
36 {
37 if (data.selected() == selected)
38 return;
39
40 data.setSelected(selected);
41 element->setNeedsStyleRecalc();
42 }
43
optionIndex(SelectElement * selectElement,const Element * element)44 int OptionElement::optionIndex(SelectElement* selectElement, const Element* element)
45 {
46 if (!selectElement)
47 return 0;
48
49 // Let's do this dynamically. Might be a bit slow, but we're sure
50 // we won't forget to update a member variable in some cases...
51 const Vector<Element*>& items = selectElement->listItems();
52 int length = items.size();
53 int optionIndex = 0;
54 for (int i = 0; i < length; ++i) {
55 if (!isOptionElement(items[i]))
56 continue;
57 if (items[i] == element)
58 return optionIndex;
59 ++optionIndex;
60 }
61
62 return 0;
63 }
64
collectOptionLabelOrText(const OptionElementData & data,const Element * element)65 String OptionElement::collectOptionLabelOrText(const OptionElementData& data, const Element* element)
66 {
67 Document* document = element->document();
68 String text;
69
70 // WinIE does not use the label attribute, so as a quirk, we ignore it.
71 if (!document->inQuirksMode())
72 text = data.label();
73 if (text.isEmpty())
74 text = collectOptionInnerText(element);
75 return normalizeText(document, text);
76 }
77
collectOptionInnerText(const Element * element)78 String OptionElement::collectOptionInnerText(const Element* element)
79 {
80 String text;
81 Node* n = element->firstChild();
82 while (n) {
83 if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SECTION_NODE)
84 text += n->nodeValue();
85
86 // skip script content
87 if (n->isElementNode() && toScriptElement(static_cast<Element*>(n)))
88 n = n->traverseNextSibling(element);
89 else
90 n = n->traverseNextNode(element);
91 }
92 return text;
93 }
94
normalizeText(const Document * document,const String & src)95 String OptionElement::normalizeText(const Document* document, const String& src)
96 {
97 String text = document->displayStringModifiedByEncoding(src);
98
99 // In WinIE, leading and trailing whitespace is ignored in options and optgroups. We match this behavior.
100 text = text.stripWhiteSpace();
101
102 // We want to collapse our whitespace too. This will match other browsers.
103 text = text.simplifyWhiteSpace();
104 return text;
105 }
106
collectOptionTextRespectingGroupLabel(const OptionElementData & data,const Element * element)107 String OptionElement::collectOptionTextRespectingGroupLabel(const OptionElementData& data, const Element* element)
108 {
109 Element* parentElement = static_cast<Element*>(element->parentNode());
110 if (parentElement && toOptionGroupElement(parentElement))
111 return " " + collectOptionLabelOrText(data, element);
112
113 return collectOptionLabelOrText(data, element);
114 }
115
collectOptionValue(const OptionElementData & data,const Element * element)116 String OptionElement::collectOptionValue(const OptionElementData& data, const Element* element)
117 {
118 String value = data.value();
119 if (!value.isNull())
120 return value;
121
122 // Use the text if the value wasn't set.
123 return collectOptionInnerText(element).stripWhiteSpace();
124 }
125
126 // OptionElementData
OptionElementData()127 OptionElementData::OptionElementData()
128 : m_selected(false)
129 {
130 }
131
~OptionElementData()132 OptionElementData::~OptionElementData()
133 {
134 }
135
toOptionElement(Element * element)136 OptionElement* toOptionElement(Element* element)
137 {
138 if (element->isHTMLElement() && element->hasTagName(HTMLNames::optionTag))
139 return static_cast<HTMLOptionElement*>(element);
140 return 0;
141 }
142
isOptionElement(Element * element)143 bool isOptionElement(Element* element)
144 {
145 return element->hasLocalName(HTMLNames::optionTag);
146 }
147
148 }
149