View Javadoc
1   /*
2    * Copyright (c) 2002-2026 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.html;
16  
17  import java.util.ArrayList;
18  import java.util.Collections;
19  import java.util.Iterator;
20  import java.util.List;
21  import java.util.Map;
22  import java.util.NoSuchElementException;
23  
24  import org.htmlunit.SgmlPage;
25  
26  /**
27   * Wrapper for the HTML element "tr".
28   *
29   * @author Mike Bowler
30   * @author David K. Taylor
31   * @author Christian Sell
32   * @author Ahmed Ashour
33   * @author Ronald Brill
34   * @author Frank Danek
35   */
36  public class HtmlTableRow extends HtmlElement {
37  
38      /** The HTML tag represented by this element. */
39      public static final String TAG_NAME = "tr";
40  
41      /**
42       * Creates an instance.
43       *
44       * @param qualifiedName the qualified name of the element type to instantiate
45       * @param page the page that this element is contained within
46       * @param attributes the initial attributes
47       */
48      HtmlTableRow(final String qualifiedName, final SgmlPage page,
49              final Map<String, DomAttr> attributes) {
50          super(qualifiedName, page, attributes);
51      }
52  
53      /**
54       * Returns an iterator over all cells in this row.
55       *
56       * @return an iterator over all {@link HtmlTableCell} objects in this row
57       */
58      public CellIterator getCellIterator() {
59          return new CellIterator();
60      }
61  
62      /**
63       * Returns an immutable list of all cells in this row.
64       *
65       * @return an immutable list containing all {@link HtmlTableCell} objects in this row
66       * @see #getCellIterator()
67       */
68      public List<HtmlTableCell> getCells() {
69          final List<HtmlTableCell> result = new ArrayList<>();
70          for (final HtmlTableCell cell : getCellIterator()) {
71              result.add(cell);
72          }
73          return Collections.unmodifiableList(result);
74      }
75  
76      /**
77       * Returns the cell at the specified index.
78       *
79       * @param index the 0-based index
80       * @return the cell at the given index
81       * @throws IndexOutOfBoundsException if there is no cell at the given index
82       */
83      public HtmlTableCell getCell(final int index) throws IndexOutOfBoundsException {
84          int count = 0;
85          for (final HtmlTableCell cell : getCellIterator()) {
86              if (count == index) {
87                  return cell;
88              }
89              count++;
90          }
91          throw new IndexOutOfBoundsException("No cell found for index " + index + ".");
92      }
93  
94      /**
95       * Returns the value of the attribute {@code align}. Refer to the
96       * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
97       * documentation for details on the use of this attribute.
98       *
99       * @return the value of the attribute {@code align}
100      *         or an empty string if that attribute isn't defined.
101      */
102     public final String getAlignAttribute() {
103         return getAttributeDirect("align");
104     }
105 
106     /**
107      * Returns the value of the attribute {@code char}. Refer to the
108      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
109      * documentation for details on the use of this attribute.
110      *
111      * @return the value of the attribute {@code char}
112      *         or an empty string if that attribute isn't defined.
113      */
114     public final String getCharAttribute() {
115         return getAttributeDirect("char");
116     }
117 
118     /**
119      * Returns the value of the attribute {@code charoff}. Refer to the
120      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
121      * documentation for details on the use of this attribute.
122      *
123      * @return the value of the attribute {@code charoff}
124      *         or an empty string if that attribute isn't defined.
125      */
126     public final String getCharoffAttribute() {
127         return getAttributeDirect("charoff");
128     }
129 
130     /**
131      * Returns the value of the attribute {@code valign}. Refer to the
132      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
133      * documentation for details on the use of this attribute.
134      *
135      * @return the value of the attribute {@code valign}
136      *         or an empty string if that attribute isn't defined.
137      */
138     public final String getValignAttribute() {
139         return getAttributeDirect("valign");
140     }
141 
142     /**
143      * Returns the table containing this row.
144      *
145      * @return the enclosing table
146      */
147     public HtmlTable getEnclosingTable() {
148         return (HtmlTable) getEnclosingElement("table");
149     }
150 
151     /**
152      * Returns the value of the attribute {@code bgcolor}. Refer to the
153      * <a href="http://www.w3.org/TR/html401/">HTML 4.01</a>
154      * documentation for details on the use of this attribute.
155      *
156      * @return the value of the attribute {@code bgcolor}
157      *         or an empty string if that attribute isn't defined.
158      */
159     public final String getBgcolorAttribute() {
160         return getAttributeDirect("bgcolor");
161     }
162 
163     /**
164      * An Iterator over the HtmlTableCells contained in this row. It will also dive
165      * into nested forms, even though that is illegal HTML.
166      */
167     public class CellIterator implements Iterator<HtmlTableCell>, Iterable<HtmlTableCell> {
168         private HtmlTableCell nextCell_;
169         private HtmlForm currentForm_;
170 
171         /** Creates an instance. */
172         public CellIterator() {
173             setNextCell(getFirstChild());
174         }
175 
176         /**
177          * {@inheritDoc}
178          */
179         @Override
180         public boolean hasNext() {
181             return nextCell_ != null;
182         }
183 
184         /**
185          * {@inheritDoc}
186          */
187         @Override
188         public HtmlTableCell next() throws NoSuchElementException {
189             return nextCell();
190         }
191 
192         /**
193          * {@inheritDoc}
194          */
195         @Override
196         public void remove() {
197             if (nextCell_ == null) {
198                 throw new IllegalStateException();
199             }
200             final DomNode sibling = nextCell_.getPreviousSibling();
201             if (sibling != null) {
202                 sibling.remove();
203             }
204         }
205 
206         /**
207          * Returns the next cell.
208          *
209          * @return the next cell
210          * @throws NoSuchElementException if no cell is available
211          */
212         public HtmlTableCell nextCell() throws NoSuchElementException {
213             if (nextCell_ != null) {
214                 final HtmlTableCell result = nextCell_;
215                 setNextCell(nextCell_.getNextSibling());
216                 return result;
217             }
218             throw new NoSuchElementException();
219         }
220 
221         /**
222          * Sets the internal position to the next cell, starting at the given node.
223          * @param node the node to mark as the next cell; if this is not a cell, the
224          *        next reachable cell will be marked.
225          */
226         private void setNextCell(final DomNode node) {
227             nextCell_ = null;
228             for (DomNode next = node; next != null; next = next.getNextSibling()) {
229                 if (next instanceof HtmlTableCell cell) {
230                     nextCell_ = cell;
231                     return;
232                 }
233                 else if (currentForm_ == null && next instanceof HtmlForm form) {
234                     // Completely illegal HTML but some of the big sites (ie amazon) do this
235                     currentForm_ = form;
236                     setNextCell(next.getFirstChild());
237                     return;
238                 }
239             }
240             if (currentForm_ != null) {
241                 final DomNode form = currentForm_;
242                 currentForm_ = null;
243                 setNextCell(form.getNextSibling());
244             }
245         }
246 
247         /**
248          * {@inheritDoc}
249          */
250         @Override
251         public Iterator<HtmlTableCell> iterator() {
252             return this;
253         }
254     }
255 
256     /**
257      * {@inheritDoc}
258      */
259     @Override
260     public DisplayStyle getDefaultStyleDisplay() {
261         return DisplayStyle.TABLE_ROW;
262     }
263 }