Home | History | Annotate | Download | only in dom
      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