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.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 }