Reviewed by Darin.
[WebKit-https.git] / WebCore / dom / Attr.cpp
1 /**
2  * This file is part of the DOM implementation for KDE.
3  *
4  * Copyright (C) 1999 Lars Knoll (knoll@kde.org)
5  *           (C) 1999 Antti Koivisto (koivisto@kde.org)
6  *           (C) 2001 Peter Kelly (pmk@post.com)
7  *           (C) 2001 Dirk Mueller (mueller@kde.org)
8  * Copyright (C) 2004, 2005, 2006 Apple Computer, Inc.
9  *
10  * This library is free software; you can redistribute it and/or
11  * modify it under the terms of the GNU Library General Public
12  * License as published by the Free Software Foundation; either
13  * version 2 of the License, or (at your option) any later version.
14  *
15  * This library is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
18  * Library General Public License for more details.
19  *
20  * You should have received a copy of the GNU Library General Public License
21  * along with this library; see the file COPYING.LIB.  If not, write to
22  * the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23  * Boston, MA 02111-1307, USA.
24  */
25 #include "config.h"
26 #include "Attr.h"
27
28 #include "Document.h"
29 #include "Element.h"
30 #include "ExceptionCode.h"
31 #include "Text.h"
32
33 namespace WebCore {
34
35 Attr::Attr(Element* element, Document* docPtr, Attribute* a)
36     : ContainerNode(docPtr),
37       m_element(element),
38       m_attribute(a),
39       m_ignoreChildrenChanged(0)
40 {
41     assert(!m_attribute->attr());
42     m_attribute->m_impl = this;
43     m_specified = true;
44 }
45
46 Attr::~Attr()
47 {
48     assert(m_attribute->attr() == this);
49     m_attribute->m_impl = 0;
50 }
51
52 void Attr::createTextChild()
53 {
54     ASSERT(refCount());
55     if (!m_attribute->value().isEmpty()) {
56         RefPtr<Text> textNode = document()->createTextNode(m_attribute->value().impl());
57
58         // This does everything appendChild() would do in this situation (assuming m_ignoreChildrenChanged was set),
59         // but much more efficiently.
60         textNode->setParent(this);
61         fastSetFirstChild(textNode.get());
62         fastSetLastChild(textNode.get());
63     }
64 }
65
66 String Attr::nodeName() const
67 {
68     return name();
69 }
70
71 Node::NodeType Attr::nodeType() const
72 {
73     return ATTRIBUTE_NODE;
74 }
75
76 const AtomicString& Attr::localName() const
77 {
78     return m_attribute->localName();
79 }
80
81 const AtomicString& Attr::namespaceURI() const
82 {
83     return m_attribute->namespaceURI();
84 }
85
86 const AtomicString& Attr::prefix() const
87 {
88     return m_attribute->prefix();
89 }
90
91 void Attr::setPrefix(const AtomicString &_prefix, ExceptionCode& ec)
92 {
93     checkSetPrefix(_prefix, ec);
94     if (ec)
95         return;
96
97     m_attribute->setPrefix(_prefix);
98 }
99
100 String Attr::nodeValue() const
101 {
102     return value();
103 }
104
105 void Attr::setValue( const String& v, ExceptionCode& ec)
106 {
107     ec = 0;
108
109     // do not interprete entities in the string, its literal!
110
111     // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
112     if (isReadOnlyNode()) {
113         ec = NO_MODIFICATION_ALLOWED_ERR;
114         return;
115     }
116
117     // ### what to do on 0 ?
118     if (v.isNull()) {
119         ec = DOMSTRING_SIZE_ERR;
120         return;
121     }
122
123     int e = 0;
124     m_ignoreChildrenChanged++;
125     removeChildren();
126     appendChild(document()->createTextNode(v.impl()), e);
127     m_ignoreChildrenChanged--;
128     
129     m_attribute->setValue(v.impl());
130     if (m_element)
131         m_element->attributeChanged(m_attribute.get());
132 }
133
134 void Attr::setNodeValue(const String& v, ExceptionCode& ec)
135 {
136     // NO_MODIFICATION_ALLOWED_ERR: taken care of by setValue()
137     setValue(v, ec);
138 }
139
140 PassRefPtr<Node> Attr::cloneNode(bool /*deep*/)
141 {
142     RefPtr<Attr> clone = new Attr(0, document(), m_attribute->clone());
143     cloneChildNodes(clone.get());
144     return clone.release();
145 }
146
147 // DOM Section 1.1.1
148 bool Attr::childTypeAllowed(NodeType type)
149 {
150     switch (type) {
151         case TEXT_NODE:
152         case ENTITY_REFERENCE_NODE:
153             return true;
154         default:
155             return false;
156     }
157 }
158
159 void Attr::childrenChanged()
160 {
161     Node::childrenChanged();
162     
163     if (m_ignoreChildrenChanged > 0)
164         return;
165     
166     // FIXME: We should include entity references in the value
167     
168     String val = "";
169     for (Node *n = firstChild(); n; n = n->nextSibling()) {
170         if (n->isTextNode())
171             val += static_cast<Text *>(n)->data();
172     }
173     
174     m_attribute->setValue(val.impl());
175     if (m_element)
176         m_element->attributeChanged(m_attribute.get());
177 }
178
179 String Attr::toString() const
180 {
181     String result;
182
183     result += nodeName();
184
185     // FIXME: substitute entities for any instances of " or ' --
186     // maybe easier to just use text value and ignore existing
187     // entity refs?
188
189     if (firstChild() != NULL) {
190         result += "=\"";
191
192         for (Node *child = firstChild(); child != NULL; child = child->nextSibling()) {
193             result += child->toString();
194         }
195         
196         result += "\"";
197     }
198
199     return result;
200 }
201
202 }