blob: bf990a3aa22f46677fe0ffb861c39a491175c871 [file] [log] [blame]
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +01001/*
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, 2010, 2012 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 "core/dom/Attr.h"
25
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010026#include "XMLNSNames.h"
Ben Murdochdf957042013-08-06 11:01:27 +010027#include "bindings/v8/ExceptionState.h"
28#include "bindings/v8/ExceptionStatePlaceholder.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010029#include "core/dom/Element.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010030#include "core/dom/ExceptionCode.h"
31#include "core/dom/ScopedEventQueue.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010032#include "core/dom/Text.h"
Ben Murdoch591b9582013-07-10 11:41:44 +010033#include "wtf/text/AtomicString.h"
34#include "wtf/text/StringBuilder.h"
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010035
36namespace WebCore {
37
38using namespace HTMLNames;
39
40Attr::Attr(Element* element, const QualifiedName& name)
41 : ContainerNode(element->document())
42 , m_element(element)
43 , m_name(name)
44 , m_ignoreChildrenChanged(0)
45 , m_specified(true)
46{
47 ScriptWrappable::init(this);
48}
49
50Attr::Attr(Document* document, const QualifiedName& name, const AtomicString& standaloneValue)
51 : ContainerNode(document)
52 , m_element(0)
53 , m_name(name)
54 , m_standaloneValue(standaloneValue)
55 , m_ignoreChildrenChanged(0)
56 , m_specified(true)
57{
58 ScriptWrappable::init(this);
59}
60
61PassRefPtr<Attr> Attr::create(Element* element, const QualifiedName& name)
62{
63 RefPtr<Attr> attr = adoptRef(new Attr(element, name));
64 attr->createTextChild();
65 return attr.release();
66}
67
68PassRefPtr<Attr> Attr::create(Document* document, const QualifiedName& name, const AtomicString& value)
69{
70 RefPtr<Attr> attr = adoptRef(new Attr(document, name, value));
71 attr->createTextChild();
72 return attr.release();
73}
74
75Attr::~Attr()
76{
77}
78
79void Attr::createTextChild()
80{
81 ASSERT(refCount());
82 if (!value().isEmpty()) {
83 RefPtr<Text> textNode = document()->createTextNode(value().string());
84
85 // This does everything appendChild() would do in this situation (assuming m_ignoreChildrenChanged was set),
86 // but much more efficiently.
87 textNode->setParentOrShadowHostNode(this);
Torne (Richard Coles)e5249552013-05-15 11:35:13 +010088 treeScope()->adoptIfNeeded(textNode.get());
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010089 setFirstChild(textNode.get());
90 setLastChild(textNode.get());
91 }
92}
93
Ben Murdochdf957042013-08-06 11:01:27 +010094void Attr::setPrefix(const AtomicString& prefix, ExceptionState& es)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010095{
Ben Murdochdf957042013-08-06 11:01:27 +010096 checkSetPrefix(prefix, es);
97 if (es.hadException())
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +010098 return;
99
100 if ((prefix == xmlnsAtom && namespaceURI() != XMLNSNames::xmlnsNamespaceURI)
101 || static_cast<Attr*>(this)->qualifiedName() == xmlnsAtom) {
Ben Murdochdf957042013-08-06 11:01:27 +0100102 es.throwDOMException(NamespaceError);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100103 return;
104 }
105
106 const AtomicString& newPrefix = prefix.isEmpty() ? nullAtom : prefix;
107
108 if (m_element)
109 elementAttribute().setPrefix(newPrefix);
110 m_name.setPrefix(newPrefix);
111}
112
113void Attr::setValue(const AtomicString& value)
114{
115 EventQueueScope scope;
116 m_ignoreChildrenChanged++;
117 removeChildren();
118 if (m_element)
119 elementAttribute().setValue(value);
120 else
121 m_standaloneValue = value;
122 createTextChild();
123 m_ignoreChildrenChanged--;
124
125 invalidateNodeListCachesInAncestors(&m_name, m_element);
126}
127
Ben Murdochdf957042013-08-06 11:01:27 +0100128void Attr::setValue(const AtomicString& value, ExceptionState&)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100129{
130 if (m_element)
131 m_element->willModifyAttribute(qualifiedName(), this->value(), value);
132
133 setValue(value);
134
135 if (m_element)
136 m_element->didModifyAttribute(qualifiedName(), value);
137}
138
Ben Murdoche69819b2013-07-17 14:56:49 +0100139void Attr::setNodeValue(const String& v)
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100140{
Ben Murdoch1fad5ca2013-08-07 11:05:11 +0100141 setValue(v, IGNORE_EXCEPTION);
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100142}
143
144PassRefPtr<Node> Attr::cloneNode(bool /*deep*/)
145{
146 RefPtr<Attr> clone = adoptRef(new Attr(document(), qualifiedName(), value()));
147 cloneChildNodes(clone.get());
148 return clone.release();
149}
150
151// DOM Section 1.1.1
152bool Attr::childTypeAllowed(NodeType type) const
153{
Torne (Richard Coles)81a51572013-05-13 16:52:28 +0100154 return TEXT_NODE == type;
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100155}
156
157void Attr::childrenChanged(bool, Node*, Node*, int)
158{
159 if (m_ignoreChildrenChanged > 0)
160 return;
161
162 invalidateNodeListCachesInAncestors(&qualifiedName(), m_element);
163
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100164 StringBuilder valueBuilder;
165 for (Node *n = firstChild(); n; n = n->nextSibling()) {
166 if (n->isTextNode())
167 valueBuilder.append(toText(n)->data());
168 }
169
170 AtomicString newValue = valueBuilder.toAtomicString();
171 if (m_element)
172 m_element->willModifyAttribute(qualifiedName(), value(), newValue);
173
174 if (m_element)
175 elementAttribute().setValue(newValue);
176 else
177 m_standaloneValue = newValue;
178
179 if (m_element)
180 m_element->attributeChanged(qualifiedName(), newValue);
181}
182
183bool Attr::isId() const
184{
185 return qualifiedName().matches(document()->idAttributeName());
186}
187
Torne (Richard Coles)53e740f2013-05-09 18:38:43 +0100188const AtomicString& Attr::value() const
189{
190 if (m_element)
191 return m_element->getAttribute(qualifiedName());
192 return m_standaloneValue;
193}
194
195Attribute& Attr::elementAttribute()
196{
197 ASSERT(m_element);
198 ASSERT(m_element->elementData());
199 return *m_element->ensureUniqueElementData()->getAttributeItem(qualifiedName());
200}
201
202void Attr::detachFromElementWithValue(const AtomicString& value)
203{
204 ASSERT(m_element);
205 ASSERT(m_standaloneValue.isNull());
206 m_standaloneValue = value;
207 m_element = 0;
208}
209
210void Attr::attachToElement(Element* element)
211{
212 ASSERT(!m_element);
213 m_element = element;
214 m_standaloneValue = nullAtom;
215}
216
217}