52a25818853599746dd078e4b40345aecca305e9
[WebKit-https.git] / WebCore / dom / Attr.cpp
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 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
31 namespace WebCore {
32
33 Attr::Attr(Element* element, Document* docPtr, PassRefPtr<Attribute> a)
34     : ContainerNode(docPtr),
35       m_element(element),
36       m_attribute(a),
37       m_ignoreChildrenChanged(0)
38 {
39     ASSERT(!m_attribute->attr());
40     m_attribute->m_impl = this;
41     m_attrWasSpecifiedOrElementHasRareData = true;
42 }
43
44 Attr::~Attr()
45 {
46     ASSERT(m_attribute->attr() == this);
47     m_attribute->m_impl = 0;
48 }
49
50 void Attr::createTextChild()
51 {
52     ASSERT(refCount());
53     if (!m_attribute->value().isEmpty()) {
54         RefPtr<Text> textNode = document()->createTextNode(m_attribute->value().string());
55
56         // This does everything appendChild() would do in this situation (assuming m_ignoreChildrenChanged was set),
57         // but much more efficiently.
58         textNode->setParent(this);
59         setFirstChild(textNode.get());
60         setLastChild(textNode.get());
61     }
62 }
63
64 String Attr::nodeName() const
65 {
66     return name();
67 }
68
69 Node::NodeType Attr::nodeType() const
70 {
71     return ATTRIBUTE_NODE;
72 }
73
74 const AtomicString& Attr::localName() const
75 {
76     return m_attribute->localName();
77 }
78
79 const AtomicString& Attr::namespaceURI() const
80 {
81     return m_attribute->namespaceURI();
82 }
83
84 const AtomicString& Attr::prefix() const
85 {
86     return m_attribute->prefix();
87 }
88
89 void Attr::setPrefix(const AtomicString &_prefix, ExceptionCode& ec)
90 {
91     ec = 0;
92     checkSetPrefix(_prefix, ec);
93     if (ec)
94         return;
95
96     m_attribute->setPrefix(_prefix);
97 }
98
99 String Attr::nodeValue() const
100 {
101     return value();
102 }
103
104 void Attr::setValue( const String& v, ExceptionCode& ec)
105 {
106     ec = 0;
107
108     // do not interprete entities in the string, its literal!
109
110     // NO_MODIFICATION_ALLOWED_ERR: Raised when the node is readonly
111     if (isReadOnlyNode()) {
112         ec = NO_MODIFICATION_ALLOWED_ERR;
113         return;
114     }
115
116     int e = 0;
117     m_ignoreChildrenChanged++;
118     removeChildren();
119     appendChild(document()->createTextNode(v), e);
120     m_ignoreChildrenChanged--;
121     
122     m_attribute->setValue(v.impl());
123     if (m_element)
124         m_element->attributeChanged(m_attribute.get());
125 }
126
127 void Attr::setNodeValue(const String& v, ExceptionCode& ec)
128 {
129     // NO_MODIFICATION_ALLOWED_ERR: taken care of by setValue()
130     setValue(v, ec);
131 }
132
133 PassRefPtr<Node> Attr::cloneNode(bool /*deep*/)
134 {
135     RefPtr<Attr> clone = new Attr(0, document(), m_attribute->clone());
136     cloneChildNodes(clone.get());
137     return clone.release();
138 }
139
140 // DOM Section 1.1.1
141 bool Attr::childTypeAllowed(NodeType type)
142 {
143     switch (type) {
144         case TEXT_NODE:
145         case ENTITY_REFERENCE_NODE:
146             return true;
147         default:
148             return false;
149     }
150 }
151
152 void Attr::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
153 {
154     if (m_ignoreChildrenChanged > 0)
155         return;
156  
157     Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
158
159     // FIXME: We should include entity references in the value
160     
161     String val = "";
162     for (Node *n = firstChild(); n; n = n->nextSibling()) {
163         if (n->isTextNode())
164             val += static_cast<Text *>(n)->data();
165     }
166     
167     m_attribute->setValue(val.impl());
168     if (m_element)
169         m_element->attributeChanged(m_attribute.get());
170 }
171
172 String Attr::toString() const
173 {
174     String result;
175
176     result += nodeName();
177
178     // FIXME: substitute entities for any instances of " or ' --
179     // maybe easier to just use text value and ignore existing
180     // entity refs?
181
182     if (firstChild() != NULL) {
183         result += "=\"";
184
185         for (Node *child = firstChild(); child != NULL; child = child->nextSibling()) {
186             result += child->toString();
187         }
188         
189         result += "\"";
190     }
191
192     return result;
193 }
194
195 }