2008-05-14 Michael A. Puls II <shadow2531@gmail.com>
[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 interpret entities in the string, it's 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     m_ignoreChildrenChanged++;
117     removeChildren();
118     m_attribute->setValue(v.impl());
119     createTextChild();
120     m_ignoreChildrenChanged--;
121
122     if (m_element)
123         m_element->attributeChanged(m_attribute.get());
124 }
125
126 void Attr::setNodeValue(const String& v, ExceptionCode& ec)
127 {
128     // NO_MODIFICATION_ALLOWED_ERR: taken care of by setValue()
129     setValue(v, ec);
130 }
131
132 PassRefPtr<Node> Attr::cloneNode(bool /*deep*/)
133 {
134     RefPtr<Attr> clone = new Attr(0, document(), m_attribute->clone());
135     cloneChildNodes(clone.get());
136     return clone.release();
137 }
138
139 // DOM Section 1.1.1
140 bool Attr::childTypeAllowed(NodeType type)
141 {
142     switch (type) {
143         case TEXT_NODE:
144         case ENTITY_REFERENCE_NODE:
145             return true;
146         default:
147             return false;
148     }
149 }
150
151 void Attr::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta)
152 {
153     if (m_ignoreChildrenChanged > 0)
154         return;
155  
156     Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta);
157
158     // FIXME: We should include entity references in the value
159     
160     String val = "";
161     for (Node *n = firstChild(); n; n = n->nextSibling()) {
162         if (n->isTextNode())
163             val += static_cast<Text *>(n)->data();
164     }
165     
166     m_attribute->setValue(val.impl());
167     if (m_element)
168         m_element->attributeChanged(m_attribute.get());
169 }
170
171 String Attr::toString() const
172 {
173     String result;
174
175     result += nodeName();
176
177     // FIXME: substitute entities for any instances of " or ' --
178     // maybe easier to just use text value and ignore existing
179     // entity refs?
180
181     if (firstChild() != NULL) {
182         result += "=\"";
183
184         for (Node *child = firstChild(); child != NULL; child = child->nextSibling()) {
185             result += child->toString();
186         }
187         
188         result += "\"";
189     }
190
191     return result;
192 }
193
194 }