1 /*
2 * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
3 * (C) 1999 Antti Koivisto (koivisto@kde.org)
4 * (C) 2001 Peter Kelly (pmk@post.com)
5 * (C) 2001 Dirk Mueller (mueller@kde.org)
6 * Copyright (C) 2004, 2005, 2006, 2007, 2009 Apple Inc. All rights reserved.
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Library General Public
10 * License as published by the Free Software Foundation; either
11 * version 2 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Library General Public License for more details.
17 *
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
20 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
21 * Boston, MA 02110-1301, USA.
22 */
23 #include "config.h"
24 #include "Attr.h"
25
26 #include "Document.h"
27 #include "Element.h"
28 #include "ExceptionCode.h"
29 #include "Text.h"
30 #include "XMLNSNames.h"
31
32 namespace WebCore {
33
34 using namespace HTMLNames;
35
Attr(Element * element,Document * document,PassRefPtr<Attribute> attribute)36 inline Attr::Attr(Element* element, Document* document, PassRefPtr<Attribute> attribute)
37 : ContainerNode(document)
38 , m_element(element)
39 , m_attribute(attribute)
40 , m_ignoreChildrenChanged(0)
41 , m_specified(true)
42 {
43 ASSERT(!m_attribute->attr());
44 m_attribute->m_impl = this;
45 }
46
create(Element * element,Document * document,PassRefPtr<Attribute> attribute)47 PassRefPtr<Attr> Attr::create(Element* element, Document* document, PassRefPtr<Attribute> attribute)
48 {
49 RefPtr<Attr> attr = adoptRef(new Attr(element, document, attribute));
50 attr->createTextChild();
51 return attr.release();
52 }
53
~Attr()54 Attr::~Attr()
55 {
56 ASSERT(m_attribute->attr() == this);
57 m_attribute->m_impl = 0;
58 }
59
createTextChild()60 void Attr::createTextChild()
61 {
62 ASSERT(refCount());
63 if (!m_attribute->value().isEmpty()) {
64 RefPtr<Text> textNode = document()->createTextNode(m_attribute->value().string());
65
66 // This does everything appendChild() would do in this situation (assuming m_ignoreChildrenChanged was set),
67 // but much more efficiently.
68 textNode->setParent(this);
69 setFirstChild(textNode.get());
70 setLastChild(textNode.get());
71 }
72 }
73
nodeName() const74 String Attr::nodeName() const
75 {
76 return name();
77 }
78
nodeType() const79 Node::NodeType Attr::nodeType() const
80 {
81 return ATTRIBUTE_NODE;
82 }
83
localName() const84 const AtomicString& Attr::localName() const
85 {
86 return m_attribute->localName();
87 }
88
namespaceURI() const89 const AtomicString& Attr::namespaceURI() const
90 {
91 return m_attribute->namespaceURI();
92 }
93
prefix() const94 const AtomicString& Attr::prefix() const
95 {
96 return m_attribute->prefix();
97 }
98
setPrefix(const AtomicString & prefix,ExceptionCode & ec)99 void Attr::setPrefix(const AtomicString& prefix, ExceptionCode& ec)
100 {
101 ec = 0;
102 checkSetPrefix(prefix, ec);
103 if (ec)
104 return;
105
106 if ((prefix == xmlnsAtom && namespaceURI() != XMLNSNames::xmlnsNamespaceURI)
107 || static_cast<Attr*>(this)->qualifiedName() == xmlnsAtom) {
108 ec = NAMESPACE_ERR;
109 return;
110 }
111
112 m_attribute->setPrefix(prefix.isEmpty() ? AtomicString() : prefix);
113 }
114
nodeValue() const115 String Attr::nodeValue() const
116 {
117 return value();
118 }
119
setValue(const AtomicString & value)120 void Attr::setValue(const AtomicString& value)
121 {
122 m_ignoreChildrenChanged++;
123 removeChildren();
124 m_attribute->setValue(value);
125 createTextChild();
126 m_ignoreChildrenChanged--;
127 }
128
setValue(const AtomicString & value,ExceptionCode &)129 void Attr::setValue(const AtomicString& value, ExceptionCode&)
130 {
131 if (m_element && m_attribute->name() == m_element->idAttributeName())
132 m_element->updateId(m_element->getIDAttribute(), value);
133
134 setValue(value);
135
136 if (m_element)
137 m_element->attributeChanged(m_attribute.get());
138 }
139
setNodeValue(const String & v,ExceptionCode & ec)140 void Attr::setNodeValue(const String& v, ExceptionCode& ec)
141 {
142 setValue(v, ec);
143 }
144
cloneNode(bool)145 PassRefPtr<Node> Attr::cloneNode(bool /*deep*/)
146 {
147 RefPtr<Attr> clone = adoptRef(new Attr(0, document(), m_attribute->clone()));
148 cloneChildNodes(clone.get());
149 return clone.release();
150 }
151
152 // DOM Section 1.1.1
childTypeAllowed(NodeType type)153 bool Attr::childTypeAllowed(NodeType type)
154 {
155 switch (type) {
156 case TEXT_NODE:
157 case ENTITY_REFERENCE_NODE:
158 return true;
159 default:
160 return false;
161 }
162 }
163
childrenChanged(bool changedByParser,Node * beforeChange,Node * afterChange,int childCountDelta)164 void Attr::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
165 {
166 if (m_ignoreChildrenChanged > 0)
167 return;
168
169 Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
170
171 // FIXME: We should include entity references in the value
172
173 String val = "";
174 for (Node *n = firstChild(); n; n = n->nextSibling()) {
175 if (n->isTextNode())
176 val += static_cast<Text *>(n)->data();
177 }
178
179 if (m_element && m_attribute->name() == m_element->idAttributeName())
180 m_element->updateId(m_attribute->value(), val);
181
182 m_attribute->setValue(val.impl());
183 if (m_element)
184 m_element->attributeChanged(m_attribute.get());
185 }
186
isId() const187 bool Attr::isId() const
188 {
189 return qualifiedName().matches(m_element ? m_element->idAttributeName() : idAttr);
190 }
191
192 }
193