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 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 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 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 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 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 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 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 132 OptionElementData::OptionElementData() 133 : m_selected(false) 134 { 135 } 136 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 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