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