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 }