1 /* 2 * Copyright (C) 1999 Lars Knoll (knoll (at) kde.org) 3 * (C) 1999 Antti Koivisto (koivisto (at) kde.org) 4 * (C) 2001 Peter Kelly (pmk (at) post.com) 5 * (C) 2001 Dirk Mueller (mueller (at) kde.org) 6 * Copyright (C) 2004, 2005, 2006, 2007, 2009, 2010 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 "Element.h" 27 #include "ExceptionCode.h" 28 #include "HTMLNames.h" 29 #include "ScopedEventQueue.h" 30 #include "Text.h" 31 #include "XMLNSNames.h" 32 33 namespace WebCore { 34 35 using namespace HTMLNames; 36 37 inline Attr::Attr(Element* element, Document* document, PassRefPtr<Attribute> attribute) 38 : ContainerNode(document) 39 , m_element(element) 40 , m_attribute(attribute) 41 , m_ignoreChildrenChanged(0) 42 , m_specified(true) 43 { 44 ASSERT(!m_attribute->attr()); 45 m_attribute->bindAttr(this); 46 } 47 48 PassRefPtr<Attr> Attr::create(Element* element, Document* document, PassRefPtr<Attribute> attribute) 49 { 50 RefPtr<Attr> attr = adoptRef(new Attr(element, document, attribute)); 51 attr->createTextChild(); 52 return attr.release(); 53 } 54 55 Attr::~Attr() 56 { 57 ASSERT(m_attribute->attr() == this); 58 m_attribute->unbindAttr(this); 59 } 60 61 void Attr::createTextChild() 62 { 63 ASSERT(refCount()); 64 if (!m_attribute->value().isEmpty()) { 65 RefPtr<Text> textNode = document()->createTextNode(m_attribute->value().string()); 66 67 // This does everything appendChild() would do in this situation (assuming m_ignoreChildrenChanged was set), 68 // but much more efficiently. 69 textNode->setParent(this); 70 setFirstChild(textNode.get()); 71 setLastChild(textNode.get()); 72 } 73 } 74 75 String Attr::nodeName() const 76 { 77 return name(); 78 } 79 80 Node::NodeType Attr::nodeType() const 81 { 82 return ATTRIBUTE_NODE; 83 } 84 85 const AtomicString& Attr::localName() const 86 { 87 return m_attribute->localName(); 88 } 89 90 const AtomicString& Attr::namespaceURI() const 91 { 92 return m_attribute->namespaceURI(); 93 } 94 95 const AtomicString& Attr::prefix() const 96 { 97 return m_attribute->prefix(); 98 } 99 100 void Attr::setPrefix(const AtomicString& prefix, ExceptionCode& ec) 101 { 102 ec = 0; 103 checkSetPrefix(prefix, ec); 104 if (ec) 105 return; 106 107 if ((prefix == xmlnsAtom && namespaceURI() != XMLNSNames::xmlnsNamespaceURI) 108 || static_cast<Attr*>(this)->qualifiedName() == xmlnsAtom) { 109 ec = NAMESPACE_ERR; 110 return; 111 } 112 113 m_attribute->setPrefix(prefix.isEmpty() ? AtomicString() : prefix); 114 } 115 116 String Attr::nodeValue() const 117 { 118 return value(); 119 } 120 121 void Attr::setValue(const AtomicString& value) 122 { 123 EventQueueScope scope; 124 m_ignoreChildrenChanged++; 125 removeChildren(); 126 m_attribute->setValue(value); 127 createTextChild(); 128 m_ignoreChildrenChanged--; 129 } 130 131 void Attr::setValue(const AtomicString& value, ExceptionCode&) 132 { 133 if (m_element && m_element->isIdAttributeName(m_attribute->name())) 134 m_element->updateId(m_element->getIdAttribute(), value); 135 136 setValue(value); 137 138 if (m_element) 139 m_element->attributeChanged(m_attribute.get()); 140 } 141 142 void Attr::setNodeValue(const String& v, ExceptionCode& ec) 143 { 144 setValue(v, ec); 145 } 146 147 PassRefPtr<Node> Attr::cloneNode(bool /*deep*/) 148 { 149 RefPtr<Attr> clone = adoptRef(new Attr(0, document(), m_attribute->clone())); 150 cloneChildNodes(clone.get()); 151 return clone.release(); 152 } 153 154 // DOM Section 1.1.1 155 bool Attr::childTypeAllowed(NodeType type) const 156 { 157 switch (type) { 158 case TEXT_NODE: 159 case ENTITY_REFERENCE_NODE: 160 return true; 161 default: 162 return false; 163 } 164 } 165 166 void Attr::childrenChanged(bool changedByParser, Node* beforeChange, Node* afterChange, int childCountDelta) 167 { 168 if (m_ignoreChildrenChanged > 0) 169 return; 170 171 Node::childrenChanged(changedByParser, beforeChange, afterChange, childCountDelta); 172 173 // FIXME: We should include entity references in the value 174 175 String val = ""; 176 for (Node *n = firstChild(); n; n = n->nextSibling()) { 177 if (n->isTextNode()) 178 val += static_cast<Text *>(n)->data(); 179 } 180 181 if (m_element && m_element->isIdAttributeName(m_attribute->name())) 182 m_element->updateId(m_attribute->value(), val); 183 184 m_attribute->setValue(val.impl()); 185 if (m_element) 186 m_element->attributeChanged(m_attribute.get()); 187 } 188 189 bool Attr::isId() const 190 { 191 return qualifiedName().matches(document()->idAttributeName()); 192 } 193 194 } 195