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 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserv
ed. | 5 * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2010 Apple Inc. All rights reserv
ed. |
6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) | 6 * (C) 2006 Alexey Proskuryakov (ap@nypop.com) |
7 * | 7 * |
8 * This library is free software; you can redistribute it and/or | 8 * This library is free software; you can redistribute it and/or |
9 * modify it under the terms of the GNU Library General Public | 9 * modify it under the terms of the GNU Library General Public |
10 * License as published by the Free Software Foundation; either | 10 * License as published by the Free Software Foundation; either |
11 * version 2 of the License, or (at your option) any later version. | 11 * version 2 of the License, or (at your option) any later version. |
12 * | 12 * |
13 * This library is distributed in the hope that it will be useful, | 13 * This library is distributed in the hope that it will be useful, |
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of | 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of |
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
16 * Library General Public License for more details. | 16 * Library General Public License for more details. |
17 * | 17 * |
18 * You should have received a copy of the GNU Library General Public License | 18 * You should have received a copy of the GNU Library General Public License |
19 * along with this library; see the file COPYING.LIB. If not, write to | 19 * along with this library; see the file COPYING.LIB. If not, write to |
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, | 20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
21 * Boston, MA 02110-1301, USA. | 21 * Boston, MA 02110-1301, USA. |
22 * | 22 * |
23 */ | 23 */ |
24 | 24 |
25 #include "config.h" | 25 #include "config.h" |
26 #include "HTMLOptGroupElement.h" | 26 #include "HTMLOptGroupElement.h" |
27 | 27 |
28 #include "Document.h" | 28 #include "Document.h" |
| 29 #include "HTMLContentElement.h" |
| 30 #include "HTMLDivElement.h" |
29 #include "HTMLNames.h" | 31 #include "HTMLNames.h" |
30 #include "HTMLSelectElement.h" | 32 #include "HTMLSelectElement.h" |
31 #include "RenderMenuList.h" | 33 #include "RenderMenuList.h" |
32 #include "NodeRenderStyle.h" | 34 #include "NodeRenderStyle.h" |
33 #include "NodeRenderingContext.h" | 35 #include "NodeRenderingContext.h" |
34 #include "StyleResolver.h" | 36 #include "StyleResolver.h" |
| 37 #include "Text.h" |
35 #include <wtf/StdLibExtras.h> | 38 #include <wtf/StdLibExtras.h> |
| 39 #include <wtf/unicode/CharacterNames.h> |
36 | 40 |
37 namespace WebCore { | 41 namespace WebCore { |
38 | 42 |
39 using namespace HTMLNames; | 43 using namespace HTMLNames; |
40 | 44 |
| 45 class GroupLabelElement : public HTMLDivElement { |
| 46 public: |
| 47 static PassRefPtr<GroupLabelElement> create(Document*); |
| 48 |
| 49 private: |
| 50 GroupLabelElement(Document* document) |
| 51 : HTMLDivElement(HTMLNames::divTag, document) |
| 52 { |
| 53 setHasCustomStyleCallbacks(); |
| 54 } |
| 55 virtual PassRefPtr<RenderStyle> customStyleForRenderer() OVERRIDE; |
| 56 }; |
| 57 |
| 58 PassRefPtr<GroupLabelElement> GroupLabelElement::create(Document* document) |
| 59 { |
| 60 return adoptRef(new GroupLabelElement(document)); |
| 61 } |
| 62 |
| 63 PassRefPtr<RenderStyle> GroupLabelElement::customStyleForRenderer() |
| 64 { |
| 65 RefPtr<RenderStyle> originalStyle = document()->styleResolver()->styleForEle
ment(this); |
| 66 RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get()); |
| 67 |
| 68 style->setPaddingRight(Length(2, Fixed)); |
| 69 style->setPaddingLeft(Length(2, Fixed)); |
| 70 |
| 71 int paddingBottom = 1; |
| 72 HTMLSelectElement* selectElement = toHTMLOptGroupElement(shadowHost())->owne
rSelectElement(); |
| 73 if (selectElement) { |
| 74 const Vector<HTMLElement*>& items = selectElement->listItems(); |
| 75 if (items[items.size() - 1] == this) |
| 76 paddingBottom = 0; |
| 77 } |
| 78 style->setPaddingBottom(Length(paddingBottom, Fixed)); |
| 79 |
| 80 return style.release(); |
| 81 } |
| 82 |
41 inline HTMLOptGroupElement::HTMLOptGroupElement(const QualifiedName& tagName, Do
cument* document) | 83 inline HTMLOptGroupElement::HTMLOptGroupElement(const QualifiedName& tagName, Do
cument* document) |
42 : HTMLElement(tagName, document) | 84 : HTMLElement(tagName, document) |
43 { | 85 { |
44 ASSERT(hasTagName(optgroupTag)); | 86 ASSERT(hasTagName(optgroupTag)); |
45 setHasCustomStyleCallbacks(); | 87 setHasCustomStyleCallbacks(); |
46 ScriptWrappable::init(this); | 88 ScriptWrappable::init(this); |
47 } | 89 } |
48 | 90 |
49 PassRefPtr<HTMLOptGroupElement> HTMLOptGroupElement::create(const QualifiedName&
tagName, Document* document) | 91 PassRefPtr<HTMLOptGroupElement> HTMLOptGroupElement::create(const QualifiedName&
tagName, Document* document) |
50 { | 92 { |
51 return adoptRef(new HTMLOptGroupElement(tagName, document)); | 93 RefPtr<HTMLOptGroupElement> optGroup = adoptRef(new HTMLOptGroupElement(tagN
ame, document)); |
| 94 optGroup->ensureUserAgentShadowRoot(); |
| 95 return optGroup.release(); |
52 } | 96 } |
53 | 97 |
54 bool HTMLOptGroupElement::isDisabledFormControl() const | 98 bool HTMLOptGroupElement::isDisabledFormControl() const |
55 { | 99 { |
56 return fastHasAttribute(disabledAttr); | 100 return fastHasAttribute(disabledAttr); |
57 } | 101 } |
58 | 102 |
59 bool HTMLOptGroupElement::supportsFocus() const | 103 bool HTMLOptGroupElement::supportsFocus() const |
60 { | 104 { |
61 return HTMLElement::supportsFocus(); | 105 return HTMLElement::supportsFocus(); |
(...skipping 17 matching lines...) Expand all Loading... |
79 HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, chi
ldCountDelta); | 123 HTMLElement::childrenChanged(changedByParser, beforeChange, afterChange, chi
ldCountDelta); |
80 } | 124 } |
81 | 125 |
82 void HTMLOptGroupElement::parseAttribute(const QualifiedName& name, const Atomic
String& value) | 126 void HTMLOptGroupElement::parseAttribute(const QualifiedName& name, const Atomic
String& value) |
83 { | 127 { |
84 HTMLElement::parseAttribute(name, value); | 128 HTMLElement::parseAttribute(name, value); |
85 recalcSelectOptions(); | 129 recalcSelectOptions(); |
86 | 130 |
87 if (name == disabledAttr) | 131 if (name == disabledAttr) |
88 didAffectSelector(AffectedSelectorDisabled | AffectedSelectorEnabled); | 132 didAffectSelector(AffectedSelectorDisabled | AffectedSelectorEnabled); |
| 133 else if (name == labelAttr) |
| 134 updateGroupLabel(); |
89 } | 135 } |
90 | 136 |
91 void HTMLOptGroupElement::recalcSelectOptions() | 137 void HTMLOptGroupElement::recalcSelectOptions() |
92 { | 138 { |
93 ContainerNode* select = parentNode(); | 139 ContainerNode* select = parentNode(); |
94 while (select && !select->hasTagName(selectTag)) | 140 while (select && !select->hasTagName(selectTag)) |
95 select = select->parentNode(); | 141 select = select->parentNode(); |
96 if (select) | 142 if (select) |
97 toHTMLSelectElement(select)->setRecalcListItems(); | 143 toHTMLSelectElement(select)->setRecalcListItems(); |
98 } | 144 } |
99 | 145 |
100 void HTMLOptGroupElement::attach() | |
101 { | |
102 HTMLElement::attach(); | |
103 // If after attaching nothing called styleForRenderer() on this node we | |
104 // manually cache the value. This happens if our parent doesn't have a | |
105 // renderer like <optgroup> or if it doesn't allow children like <select>. | |
106 if (!m_style && parentNode()->renderStyle()) | |
107 updateNonRenderStyle(); | |
108 } | |
109 | |
110 void HTMLOptGroupElement::detach() | |
111 { | |
112 m_style.clear(); | |
113 HTMLElement::detach(); | |
114 } | |
115 | |
116 void HTMLOptGroupElement::updateNonRenderStyle() | |
117 { | |
118 m_style = document()->styleResolver()->styleForElement(this); | |
119 } | |
120 | |
121 RenderStyle* HTMLOptGroupElement::nonRendererStyle() const | |
122 { | |
123 return m_style.get(); | |
124 } | |
125 | |
126 PassRefPtr<RenderStyle> HTMLOptGroupElement::customStyleForRenderer() | |
127 { | |
128 // styleForRenderer is called whenever a new style should be associated | |
129 // with an Element so now is a good time to update our cached style. | |
130 updateNonRenderStyle(); | |
131 return m_style; | |
132 } | |
133 | |
134 String HTMLOptGroupElement::groupLabelText() const | 146 String HTMLOptGroupElement::groupLabelText() const |
135 { | 147 { |
136 String itemText = document()->displayStringModifiedByEncoding(getAttribute(l
abelAttr)); | 148 String itemText = document()->displayStringModifiedByEncoding(getAttribute(l
abelAttr)); |
137 | 149 |
138 // In WinIE, leading and trailing whitespace is ignored in options and optgr
oups. We match this behavior. | 150 // In WinIE, leading and trailing whitespace is ignored in options and optgr
oups. We match this behavior. |
139 itemText = itemText.stripWhiteSpace(); | 151 itemText = itemText.stripWhiteSpace(); |
140 // We want to collapse our whitespace too. This will match other browsers. | 152 // We want to collapse our whitespace too. This will match other browsers. |
141 itemText = itemText.simplifyWhiteSpace(); | 153 itemText = itemText.simplifyWhiteSpace(); |
142 | 154 |
143 return itemText; | 155 return itemText; |
(...skipping 12 matching lines...) Expand all Loading... |
156 } | 168 } |
157 | 169 |
158 void HTMLOptGroupElement::accessKeyAction(bool) | 170 void HTMLOptGroupElement::accessKeyAction(bool) |
159 { | 171 { |
160 HTMLSelectElement* select = ownerSelectElement(); | 172 HTMLSelectElement* select = ownerSelectElement(); |
161 // send to the parent to bring focus to the list box | 173 // send to the parent to bring focus to the list box |
162 if (select && !select->focused()) | 174 if (select && !select->focused()) |
163 select->accessKeyAction(false); | 175 select->accessKeyAction(false); |
164 } | 176 } |
165 | 177 |
| 178 void HTMLOptGroupElement::didAddUserAgentShadowRoot(ShadowRoot* root) |
| 179 { |
| 180 RefPtr<GroupLabelElement> groupLabelElement = GroupLabelElement::create(docu
ment()); |
| 181 groupLabelElement->appendChild(Text::create(document(), "TEST"), ASSERT_NO_E
XCEPTION); |
| 182 root->appendChild(groupLabelElement); |
| 183 m_groupLabelElement = groupLabelElement.get(); |
| 184 |
| 185 RefPtr<HTMLContentElement> content = HTMLContentElement::create(document()); |
| 186 content->setAttribute(selectAttr, "option"); |
| 187 root->appendChild(content); |
| 188 |
| 189 updateGroupLabel(); |
| 190 } |
| 191 |
| 192 void HTMLOptGroupElement::updateGroupLabel() |
| 193 { |
| 194 DEFINE_STATIC_LOCAL(String, nonBreakingSpaceString, (&noBreakSpace, 1)); |
| 195 String labelText = groupLabelText(); |
| 196 if (labelText.isEmpty()) |
| 197 labelText = nonBreakingSpaceString; |
| 198 Text* const textNode = toText(userAgentShadowRoot()->firstChild()->firstChil
d()); |
| 199 ASSERT(textNode); |
| 200 if (!textNode) |
| 201 return; |
| 202 textNode->replaceWholeText(labelText, ASSERT_NO_EXCEPTION); |
| 203 } |
| 204 |
| 205 HTMLOptGroupElement* toHTMLOptGroupElement(Node* node) |
| 206 { |
| 207 ASSERT_WITH_SECURITY_IMPLICATION(!node || node->hasTagName(optgroupTag)); |
| 208 return static_cast<HTMLOptGroupElement*>(node); |
| 209 } |
| 210 |
166 } // namespace | 211 } // namespace |
OLD | NEW |