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.javascript.host.html;
16  
17  import java.io.Serializable;
18  import java.util.ArrayList;
19  import java.util.List;
20  import java.util.function.Supplier;
21  
22  import org.htmlunit.html.DomElement;
23  import org.htmlunit.html.DomNode;
24  import org.htmlunit.html.HtmlPage;
25  import org.htmlunit.html.HtmlTable;
26  import org.htmlunit.html.HtmlTableRow;
27  import org.htmlunit.javascript.HtmlUnitScriptable;
28  import org.htmlunit.javascript.JavaScriptEngine;
29  import org.htmlunit.javascript.configuration.JsxClass;
30  import org.htmlunit.javascript.configuration.JsxConstructor;
31  import org.htmlunit.javascript.configuration.JsxFunction;
32  import org.htmlunit.javascript.configuration.JsxGetter;
33  import org.htmlunit.javascript.configuration.JsxSetter;
34  import org.htmlunit.javascript.host.dom.DOMException;
35  
36  /**
37   * The JavaScript object {@code HTMLTableRowElement}.
38   *
39   * @author Daniel Gredler
40   * @author Marc Guillemot
41   * @author Chris Erskine
42   * @author Ahmed Ashour
43   * @author Ronald Brill
44   * @author Frank Danek
45   *
46   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement">MDN Documentation</a>
47   */
48  @JsxClass(domClass = HtmlTableRow.class)
49  public class HTMLTableRowElement extends HTMLElement {
50  
51      /** The default value of the "vAlign" property. */
52      private static final String VALIGN_DEFAULT_VALUE = "top";
53  
54      /**
55       * JavaScript constructor.
56       */
57      @Override
58      @JsxConstructor
59      public void jsConstructor() {
60          super.jsConstructor();
61      }
62  
63      /**
64       * Returns the index of the row within the parent table.
65       * @return the index of the row within the parent table
66       * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/rowIndex">MDN Documentation</a>
67       */
68      @JsxGetter
69      public int getRowIndex() {
70          final HtmlTableRow row = (HtmlTableRow) getDomNodeOrDie();
71          final HtmlTable table = row.getEnclosingTable();
72          if (table == null) { // a not attached document.createElement('TR')
73              return -1;
74          }
75          return table.getRows().indexOf(row);
76      }
77  
78      /**
79       * Returns the index of the row within the enclosing thead, tbody or tfoot.
80       * @return the index of the row within the enclosing thead, tbody or tfoot
81       * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/sectionRowIndex">MDN Documentation</a>
82       * @see <a href="http://www.w3.org/TR/2000/WD-DOM-Level-1-20000929/level-one-html.html#ID-79105901">
83       *     DOM Level 1</a>
84       */
85      @JsxGetter
86      public int getSectionRowIndex() {
87          DomNode row = getDomNodeOrDie();
88          final HtmlTable table = ((HtmlTableRow) row).getEnclosingTable();
89          if (table == null) { // a not attached document.createElement('TR')
90              return -1;
91          }
92          int index = -1;
93          while (row != null) {
94              if (row instanceof HtmlTableRow) {
95                  index++;
96              }
97              row = row.getPreviousSibling();
98          }
99          return index;
100     }
101 
102     /**
103      * Returns the cells in the row.
104      * @return the cells in the row
105      */
106     @JsxGetter
107     public HTMLCollection getCells() {
108         final HtmlTableRow row = (HtmlTableRow) getDomNodeOrDie();
109 
110         final HTMLCollection cells = new HTMLCollection(row, false);
111         cells.setElementsSupplier((Supplier<List<DomNode>> & Serializable) () -> new ArrayList<>(row.getCells()));
112         return cells;
113     }
114 
115     /**
116      * Returns the value of the {@code bgColor} attribute.
117      * @return the value of the {@code bgColor} attribute
118      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement#bgcolor">MDN Documentation</a>
119      */
120     @JsxGetter
121     public String getBgColor() {
122         return getDomNodeOrDie().getAttribute("bgColor");
123     }
124 
125     /**
126      * Sets the value of the {@code bgColor} attribute.
127      * @param bgColor the value of the {@code bgColor} attribute
128      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement#bgcolor">MDN Documentation</a>
129      */
130     @JsxSetter
131     public void setBgColor(final String bgColor) {
132         setColorAttribute("bgColor", bgColor);
133     }
134 
135     /**
136      * Inserts a new cell at the specified index in the element's cells collection. If the index
137      * is -1 or there is no index specified, then the cell is appended at the end of the
138      * element's cells collection.
139      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/insertCell">MDN Documentation</a>
140      * @param index specifies where to insert the cell in the 'tr'.
141      *        The default value is -1, which appends the new cell to the end of the cells collection
142      * @return the newly-created cell
143      */
144     @JsxFunction
145     public HtmlUnitScriptable insertCell(final Object index) {
146         int position = -1;
147         if (!JavaScriptEngine.isUndefined(index)) {
148             position = (int) JavaScriptEngine.toNumber(index);
149         }
150         final HtmlTableRow htmlRow = (HtmlTableRow) getDomNodeOrDie();
151 
152         final boolean indexValid = position >= -1 && position <= htmlRow.getCells().size();
153         if (indexValid) {
154             final DomElement newCell = ((HtmlPage) htmlRow.getPage()).createElement("td");
155             if (position == -1 || position == htmlRow.getCells().size()) {
156                 htmlRow.appendChild(newCell);
157             }
158             else {
159                 htmlRow.getCell(position).insertBefore(newCell);
160             }
161             return getScriptableFor(newCell);
162         }
163         throw JavaScriptEngine.asJavaScriptException(
164                 getWindow(),
165                 "Index or size is negative or greater than the allowed amount",
166                 DOMException.INDEX_SIZE_ERR);
167     }
168 
169     /**
170      * Deletes the cell at the specified index in the element's cells collection. If the index
171      * is -1, then the last cell is deleted.
172      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableRowElement/deleteCell">MDN Documentation</a>
173      * @see <a href="http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/html.html#ID-11738598">W3C DOM Level2</a>
174      * @param index specifies the cell to delete.
175      */
176     @JsxFunction
177     public void deleteCell(final Object index) {
178         if (JavaScriptEngine.isUndefined(index)) {
179             throw JavaScriptEngine.typeError("No enough arguments");
180         }
181 
182         int position = (int) JavaScriptEngine.toNumber(index);
183 
184         final HtmlTableRow htmlRow = (HtmlTableRow) getDomNodeOrDie();
185 
186         if (position == -1) {
187             position = htmlRow.getCells().size() - 1;
188         }
189         final boolean indexValid = position >= -1 && position <= htmlRow.getCells().size();
190         if (!indexValid) {
191             throw JavaScriptEngine.asJavaScriptException(
192                     getWindow(),
193                     "Index or size is negative or greater than the allowed amount",
194                     DOMException.INDEX_SIZE_ERR);
195         }
196 
197         htmlRow.getCell(position).remove();
198     }
199 
200     /**
201      * Overwritten to throw an exception.
202      * @param value the new value for replacing this node
203      */
204     @Override
205     public void setOuterHTML(final Object value) {
206         throw JavaScriptEngine.reportRuntimeError("outerHTML is read-only for tag 'tr'");
207     }
208 
209     /**
210      * Returns the value of the {@code align} property.
211      * @return the value of the {@code align} property
212      */
213     @JsxGetter
214     public String getAlign() {
215         return getAlign(true);
216     }
217 
218     /**
219      * Sets the value of the {@code align} property.
220      * @param align the value of the {@code align} property
221      */
222     @JsxSetter
223     public void setAlign(final String align) {
224         setAlign(align, false);
225     }
226 
227     /**
228      * Returns the value of the {@code vAlign} property.
229      * @return the value of the {@code vAlign} property
230      */
231     @JsxGetter
232     public String getVAlign() {
233         return getVAlign(getValidVAlignValues(), VALIGN_DEFAULT_VALUE);
234     }
235 
236     /**
237      * Sets the value of the {@code vAlign} property.
238      * @param vAlign the value of the {@code vAlign} property
239      */
240     @JsxSetter
241     public void setVAlign(final Object vAlign) {
242         setVAlign(vAlign, getValidVAlignValues());
243     }
244 
245     /**
246      * Returns the valid "vAlign" values for this element, depending on the browser being emulated.
247      * @return the valid "vAlign" values for this element, depending on the browser being emulated
248      */
249     private String[] getValidVAlignValues() {
250         return null;
251     }
252 
253     /**
254      * Returns the value of the {@code ch} property.
255      * @return the value of the {@code ch} property
256      */
257     @Override
258     @JsxGetter
259     public String getCh() {
260         return super.getCh();
261     }
262 
263     /**
264      * Sets the value of the {@code ch} property.
265      * @param ch the value of the {@code ch} property
266      */
267     @Override
268     @JsxSetter
269     public void setCh(final String ch) {
270         super.setCh(ch);
271     }
272 
273     /**
274      * Returns the value of the {@code chOff} property.
275      * @return the value of the {@code chOff} property
276      */
277     @Override
278     @JsxGetter
279     public String getChOff() {
280         return super.getChOff();
281     }
282 
283     /**
284      * Sets the value of the {@code chOff} property.
285      * @param chOff the value of the {@code chOff} property
286      */
287     @Override
288     @JsxSetter
289     public void setChOff(final String chOff) {
290         super.setChOff(chOff);
291     }
292 }