View Javadoc
1   /*
2    * Copyright (c) 2002-2025 Gargoyle Software Inc.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * https://www.apache.org/licenses/LICENSE-2.0
8    *
9    * Unless required by applicable law or agreed to in writing, software
10   * distributed under the License is distributed on an "AS IS" BASIS,
11   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12   * See the License for the specific language governing permissions and
13   * limitations under the License.
14   */
15  package org.htmlunit.javascript.host;
16  
17  import org.htmlunit.corejs.javascript.Scriptable;
18  import org.htmlunit.html.DomElement;
19  import org.htmlunit.html.DomNode;
20  import org.htmlunit.javascript.HtmlUnitScriptable;
21  import org.htmlunit.javascript.JavaScriptEngine;
22  import org.htmlunit.javascript.configuration.JsxClass;
23  import org.htmlunit.javascript.configuration.JsxConstructor;
24  import org.htmlunit.javascript.configuration.JsxFunction;
25  import org.htmlunit.javascript.configuration.JsxGetter;
26  import org.htmlunit.javascript.configuration.JsxSymbol;
27  import org.htmlunit.javascript.host.dom.Attr;
28  import org.htmlunit.javascript.host.dom.Node;
29  
30  /**
31   * A collection of nodes that can be accessed by name. String comparisons in this class are case-insensitive when
32   * used with an {@link org.htmlunit.html.HtmlElement},
33   * but case-sensitive when used with a {@link org.htmlunit.html.DomElement}.
34   *
35   * @author Daniel Gredler
36   * @author Ahmed Ashour
37   * @author Marc Guillemot
38   * @author Ronald Brill
39   * @author Frank Danek
40   * @see <a href="http://www.w3.org/TR/DOM-Level-2-Core/core.html#ID-1780488922">DOM Level 2 Core Spec</a>
41   * @see <a href="http://msdn2.microsoft.com/en-us/library/ms763824.aspx">IXMLDOMNamedNodeMap</a>
42   */
43  @JsxClass
44  public class NamedNodeMap extends HtmlUnitScriptable {
45  
46      private final org.w3c.dom.NamedNodeMap attributes_;
47  
48      /**
49       * We need default constructors to build the prototype instance.
50       */
51      public NamedNodeMap() {
52          super();
53          attributes_ = null;
54      }
55  
56      /**
57       * JavaScript constructor.
58       */
59      @JsxConstructor
60      public void jsConstructor() {
61          // nothing to do
62      }
63  
64      /**
65       * Creates a new named node map for the specified element.
66       *
67       * @param element the owning element
68       */
69      public NamedNodeMap(final DomElement element) {
70          super();
71          setParentScope(element.getScriptableObject());
72          setPrototype(getPrototype(getClass()));
73  
74          attributes_ = element.getAttributes();
75          setDomNode(element, false);
76      }
77  
78      /**
79       * Returns the element at the specified index, or {@link #NOT_FOUND} if the index is invalid.
80       * <p>
81       * {@inheritDoc}
82       */
83      @Override
84      public final Object get(final int index, final Scriptable start) {
85          final NamedNodeMap startMap = (NamedNodeMap) start;
86          final Object response = startMap.item(index);
87          if (response != null) {
88              return response;
89          }
90          return NOT_FOUND;
91      }
92  
93      /**
94       * {@inheritDoc}
95       */
96      @Override
97      public Object get(final String name, final Scriptable start) {
98          Object response = super.get(name, start);
99          if (response != NOT_FOUND) {
100             return response;
101         }
102 
103         response = getNamedItem(name);
104         if (response != null) {
105             return response;
106         }
107 
108         return NOT_FOUND;
109     }
110 
111     /**
112      * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br>
113      *
114      * Gets the specified attribute but does not handle the synthetic class attribute for IE.
115      * @see #getNamedItem(String)
116      *
117      * @param name attribute name
118      * @return the attribute node, {@code null} if the attribute is not defined
119      */
120     public HtmlUnitScriptable getNamedItemWithoutSytheticClassAttr(final String name) {
121         if (attributes_ != null) {
122             final DomNode attr = (DomNode) attributes_.getNamedItem(name);
123             if (attr != null) {
124                 return attr.getScriptableObject();
125             }
126         }
127 
128         return null;
129     }
130 
131     /**
132      * Gets the specified attribute.
133      * @param name attribute name
134      * @return the attribute node, {@code null} if the attribute is not defined
135      */
136     @JsxFunction
137     public HtmlUnitScriptable getNamedItem(final String name) {
138         return getNamedItemWithoutSytheticClassAttr(name);
139     }
140 
141     /**
142      * Gets the specified attribute.
143      * @param namespaceURI the namespace URI of the node to retrieve.
144      * @param localName the local name of the node to retrieve.
145      * @return the attribute node, {@code null} if the attribute is not defined
146      */
147     @JsxFunction
148     public Node getNamedItemNS(final String namespaceURI, final String localName) {
149         if (attributes_ != null) {
150             final DomNode attr = (DomNode) attributes_.getNamedItemNS(namespaceURI, localName);
151             if (attr != null) {
152                 return attr.getScriptableObject();
153             }
154         }
155 
156         return null;
157     }
158 
159     /**
160      * Sets the specified attribute.
161      * @param node the attribute
162      */
163     @JsxFunction
164     public void setNamedItem(final Node node) {
165         attributes_.setNamedItem(node.getDomNodeOrDie());
166     }
167 
168     /**
169      * Sets the specified attribute.
170      * @param node the attribute
171      */
172     @JsxFunction
173     public void setNamedItemNS(final Node node) {
174         attributes_.setNamedItemNS(node.getDomNodeOrDie());
175     }
176 
177     /**
178      * Removes the specified attribute.
179      * @param name the name of the item to remove
180      */
181     @JsxFunction
182     public void removeNamedItem(final String name) {
183         attributes_.removeNamedItem(name);
184     }
185 
186     /**
187      * Removes the specified attribute.
188      * @param namespaceURI the namespace URI of the node to retrieve.
189      * @param localName the local name of the node to retrieve.
190      * @return the attribute node, {@code null} if the attribute is not defined
191      */
192     @JsxFunction
193     public Attr removeNamedItemNS(final String namespaceURI, final String localName) {
194         return (Attr) attributes_.removeNamedItemNS(namespaceURI, localName);
195     }
196 
197     /**
198      * Returns the item at the specified index.
199      * @param index the index
200      * @return the item at the specified index
201      */
202     @JsxFunction
203     public HtmlUnitScriptable item(final int index) {
204         final DomNode attr = (DomNode) attributes_.item(index);
205         if (attr != null) {
206             return attr.getScriptableObject();
207         }
208         return null;
209     }
210 
211     /**
212      * Returns the number of attributes in this named node map.
213      * @return the number of attributes in this named node map
214      */
215     @JsxGetter
216     public int getLength() {
217         return attributes_.getLength();
218     }
219 
220     /**
221      * {@inheritDoc}
222      */
223     @Override
224     public boolean has(final int index, final Scriptable start) {
225         return index >= 0 && index < getLength();
226     }
227 
228     /**
229      * @return the Iterator symbol
230      */
231     @JsxSymbol
232     public Scriptable iterator() {
233         return JavaScriptEngine.newArrayIteratorTypeValues(getParentScope(), this);
234     }
235 }