1635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project/*
2635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Copyright (C) 2009 Torch Mobile Inc. All rights reserved. (http://www.torchmobile.com/)
3635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
4635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * This library is free software; you can redistribute it and/or
5635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * modify it under the terms of the GNU Library General Public
6635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * License as published by the Free Software Foundation; either
7635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * version 2 of the License, or (at your option) any later version.
8635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
9635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * This library is distributed in the hope that it will be useful,
10635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * but WITHOUT ANY WARRANTY; without even the implied warranty of
11635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Library General Public License for more details.
13635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
14635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * You should have received a copy of the GNU Library General Public License
15635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * along with this library; see the file COPYING.LIB.  If not, write to
16635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project * Boston, MA 02110-1301, USA.
18635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project *
19635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project */
20635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
21635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "config.h"
22635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "OptionElement.h"
23635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
24635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "Document.h"
25635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "Element.h"
26635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "HTMLNames.h"
27635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "HTMLOptionElement.h"
28635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "OptionGroupElement.h"
29635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "ScriptElement.h"
305f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#include "SelectElement.h"
31635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include <wtf/Assertions.h>
32635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
33635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#if ENABLE(WML)
34635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "WMLOptionElement.h"
35635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#include "WMLNames.h"
36635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
37635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
38635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Projectnamespace WebCore {
39635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
405f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianvoid OptionElement::setSelectedState(OptionElementData& data, Element* element, bool selected)
41635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
42635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (data.selected() == selected)
43635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return;
44635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
45635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    data.setSelected(selected);
465f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    element->setNeedsStyleRecalc();
47635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
48635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
495f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianint OptionElement::optionIndex(SelectElement* selectElement, const Element* element)
50635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
515f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    if (!selectElement)
525f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        return 0;
535f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // Let's do this dynamically. Might be a bit slow, but we're sure
555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    // we won't forget to update a member variable in some cases...
565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    const Vector<Element*>& items = selectElement->listItems();
575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int length = items.size();
585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    int optionIndex = 0;
595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    for (int i = 0; i < length; ++i) {
605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (!isOptionElement(items[i]))
615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            continue;
625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        if (items[i] == element)
635f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian            return optionIndex;
645f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        ++optionIndex;
655f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    }
665f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
675f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return 0;
685f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
695f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
700bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochString OptionElement::collectOptionLabelOrText(const OptionElementData& data, const Element* element)
715f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
725f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Document* document = element->document();
73635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    String text;
74635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
75635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // WinIE does not use the label attribute, so as a quirk, we ignore it.
765ddde30071f639962dd557c453f2ad01f8f0fd00Kristian Monsen    if (!document->inQuirksMode())
77635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        text = data.label();
780bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    if (text.isEmpty())
790bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        text = collectOptionInnerText(element);
800bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return normalizeText(document, text);
810bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
82635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
830bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochString OptionElement::collectOptionInnerText(const Element* element)
840bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
850bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    String text;
860bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    Node* n = element->firstChild();
870bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    while (n) {
880bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (n->nodeType() == Node::TEXT_NODE || n->nodeType() == Node::CDATA_SECTION_NODE)
890bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            text += n->nodeValue();
900bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch
910bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        // skip script content
920bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        if (n->isElementNode() && toScriptElement(static_cast<Element*>(n)))
930bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            n = n->traverseNextSibling(element);
940bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        else
950bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch            n = n->traverseNextNode(element);
96635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    }
970bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return text;
980bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch}
99635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1000bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben MurdochString OptionElement::normalizeText(const Document* document, const String& src)
1010bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch{
1020bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    String text = document->displayStringModifiedByEncoding(src);
103635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
104635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // In WinIE, leading and trailing whitespace is ignored in options and optgroups. We match this behavior.
105635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    text = text.stripWhiteSpace();
106635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
107635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // We want to collapse our whitespace too.  This will match other browsers.
108635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    text = text.simplifyWhiteSpace();
109635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return text;
110635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
111635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1125f1ab04193ad0130ca8204aadaceae083aca9881Feng QianString OptionElement::collectOptionTextRespectingGroupLabel(const OptionElementData& data, const Element* element)
113635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
1145f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    Element* parentElement = static_cast<Element*>(element->parentNode());
115635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (parentElement && toOptionGroupElement(parentElement))
1160bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch        return "    " + collectOptionLabelOrText(data, element);
117635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1180bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return collectOptionLabelOrText(data, element);
119635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
120635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1215f1ab04193ad0130ca8204aadaceae083aca9881Feng QianString OptionElement::collectOptionValue(const OptionElementData& data, const Element* element)
122635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
123635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    String value = data.value();
124635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (!value.isNull())
125635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return value;
126635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
127635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    // Use the text if the value wasn't set.
1280bf48ef3be53ddaa52bbead65dfd75bf90e7a2b5Ben Murdoch    return collectOptionInnerText(element).stripWhiteSpace();
129635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
130635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
131635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project// OptionElementData
1325f1ab04193ad0130ca8204aadaceae083aca9881Feng QianOptionElementData::OptionElementData()
1335f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    : m_selected(false)
134635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
135635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
136635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
137a94275402997c11dd2e778633dacf4b7e630a35dBen MurdochOptionElementData::~OptionElementData()
138a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch{
139a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch}
140a94275402997c11dd2e778633dacf4b7e630a35dBen Murdoch
141635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source ProjectOptionElement* toOptionElement(Element* element)
142635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project{
143635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (element->isHTMLElement() && element->hasTagName(HTMLNames::optionTag))
144635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return static_cast<HTMLOptionElement*>(element);
145635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
146635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#if ENABLE(WML)
147635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    if (element->isWMLElement() && element->hasTagName(WMLNames::optionTag))
148635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project        return static_cast<WMLOptionElement*>(element);
149635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project#endif
150635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
151635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project    return 0;
152635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
153635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project
1545f1ab04193ad0130ca8204aadaceae083aca9881Feng Qianbool isOptionElement(Element* element)
1555f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian{
1565f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian    return element->hasLocalName(HTMLNames::optionTag)
1575f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#if ENABLE(WML)
1585f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        || element->hasLocalName(WMLNames::optionTag)
1595f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian#endif
1605f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian        ;
1615f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian}
1625f1ab04193ad0130ca8204aadaceae083aca9881Feng Qian
163635860845790a19bf50bbc51ba8fb66a96dde068The Android Open Source Project}
164