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.function.Predicate;
19  
20  import org.htmlunit.html.DomElement;
21  import org.htmlunit.html.DomNode;
22  import org.htmlunit.html.HtmlPage;
23  import org.htmlunit.html.HtmlTableBody;
24  import org.htmlunit.html.HtmlTableFooter;
25  import org.htmlunit.html.HtmlTableHeader;
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   * A JavaScript object representing "HTMLTableSectionElement", it is used by
38   * {@link HtmlTableBody}, {@link HtmlTableHeader}, and {@link HtmlTableFooter}.
39   *
40   * @author Daniel Gredler
41   * @author Ahmed Ashour
42   * @author Ronald Brill
43   */
44  @JsxClass(domClass = HtmlTableBody.class)
45  @JsxClass(domClass = HtmlTableHeader.class)
46  @JsxClass(domClass = HtmlTableFooter.class)
47  public class HTMLTableSectionElement 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 value of the {@code vAlign} property.
63       * @return the value of the {@code vAlign} property
64       */
65      @JsxGetter
66      public String getVAlign() {
67          return getVAlign(getValidVAlignValues(), VALIGN_DEFAULT_VALUE);
68      }
69  
70      /**
71       * Sets the value of the {@code vAlign} property.
72       * @param vAlign the value of the {@code vAlign} property
73       */
74      @JsxSetter
75      public void setVAlign(final Object vAlign) {
76          setVAlign(vAlign, getValidVAlignValues());
77      }
78  
79      /**
80       * Returns the valid "vAlign" values for this element, depending on the browser being emulated.
81       * @return the valid "vAlign" values for this element, depending on the browser being emulated
82       */
83      private String[] getValidVAlignValues() {
84          return null;
85      }
86  
87      /**
88       * Returns the value of the {@code ch} property.
89       * @return the value of the {@code ch} property
90       */
91      @Override
92      @JsxGetter
93      public String getCh() {
94          return super.getCh();
95      }
96  
97      /**
98       * Sets the value of the {@code ch} property.
99       * @param ch the value of the {@code ch} property
100      */
101     @Override
102     @JsxSetter
103     public void setCh(final String ch) {
104         super.setCh(ch);
105     }
106 
107     /**
108      * Returns the value of the {@code chOff} property.
109      * @return the value of the {@code chOff} property
110      */
111     @Override
112     @JsxGetter
113     public String getChOff() {
114         return super.getChOff();
115     }
116 
117     /**
118      * Sets the value of the {@code chOff} property.
119      * @param chOff the value of the {@code chOff} property
120      */
121     @Override
122     @JsxSetter
123     public void setChOff(final String chOff) {
124         super.setChOff(chOff);
125     }
126 
127     /**
128      * Returns the rows in the element.
129      * @return the rows in the element
130      */
131     @JsxGetter
132     public HTMLCollection getRows() {
133         final HTMLCollection rows = new HTMLCollection(getDomNodeOrDie(), false);
134         rows.setIsMatchingPredicate(
135                 (Predicate<DomNode> & Serializable)
136                 node -> node instanceof HtmlTableRow && isContainedRow((HtmlTableRow) node));
137         return rows;
138     }
139 
140     /**
141      * Indicates if the row belongs to this container.
142      * @param row the row to test
143      * @return {@code true} if it belongs to this container
144      */
145     protected boolean isContainedRow(final HtmlTableRow row) {
146         return row.getParentNode() == getDomNodeOrDie();
147     }
148 
149     /**
150      * Deletes the row at the specified index.
151      * @see <a href="http://msdn.microsoft.com/en-us/library/ms536408.aspx">MSDN Documentation</a>
152      * @param rowIndex the zero-based index of the row to delete
153      */
154     @JsxFunction
155     public void deleteRow(int rowIndex) {
156         final HTMLCollection rows = getRows();
157         final int rowCount = rows.getLength();
158         if (rowIndex == -1) {
159             rowIndex = rowCount - 1;
160         }
161         final boolean rowIndexValid = rowIndex >= 0 && rowIndex < rowCount;
162         if (rowIndexValid) {
163             final HtmlUnitScriptable row = (HtmlUnitScriptable) rows.item(Integer.valueOf(rowIndex));
164             row.getDomNodeOrDie().remove();
165         }
166     }
167 
168     /**
169      * Inserts a new row at the specified index in the element's row collection. If the index
170      * is -1 or there is no index specified, then the row is appended at the end of the
171      * element's row collection.
172      * @see <a href="http://msdn.microsoft.com/en-us/library/ms536457.aspx">MSDN Documentation</a>
173      * @param index specifies where to insert the row in the rows collection.
174      *        The default value is -1, which appends the new row to the end of the rows collection
175      * @return the newly-created row
176      */
177     @JsxFunction
178     public HtmlUnitScriptable insertRow(final Object index) {
179         int rowIndex = -1;
180         if (!JavaScriptEngine.isUndefined(index)) {
181             rowIndex = (int) JavaScriptEngine.toNumber(index);
182         }
183         final HTMLCollection rows = getRows();
184         final int rowCount = rows.getLength();
185         final int r;
186         if (rowIndex == -1 || rowIndex == rowCount) {
187             r = Math.max(0, rowCount);
188         }
189         else {
190             r = rowIndex;
191         }
192 
193         if (r < 0 || r > rowCount) {
194             throw JavaScriptEngine.asJavaScriptException(
195                     getWindow(),
196                     "Index or size is negative or greater than the allowed amount "
197                             + "(index: " + rowIndex + ", " + rowCount + " rows)",
198                     DOMException.INDEX_SIZE_ERR);
199         }
200 
201         return insertRow(r);
202     }
203 
204     /**
205      * Inserts a new row at the given position.
206      * @param index the index where the row should be inserted (0 &lt;= index &lt;= nbRows)
207      * @return the inserted row
208      */
209     public HtmlUnitScriptable insertRow(final int index) {
210         final HTMLCollection rows = getRows();
211         final int rowCount = rows.getLength();
212         final DomElement newRow = ((HtmlPage) getDomNodeOrDie().getPage()).createElement("tr");
213         if (rowCount == 0) {
214             getDomNodeOrDie().appendChild(newRow);
215         }
216         else if (index == rowCount) {
217             final HtmlUnitScriptable row = (HtmlUnitScriptable) rows.item(Integer.valueOf(index - 1));
218             row.getDomNodeOrDie().getParentNode().appendChild(newRow);
219         }
220         else {
221             final HtmlUnitScriptable row = (HtmlUnitScriptable) rows.item(Integer.valueOf(index));
222             // if at the end, then in the same "sub-container" as the last existing row
223             if (index > rowCount - 1) {
224                 row.getDomNodeOrDie().getParentNode().appendChild(newRow);
225             }
226             else {
227                 row.getDomNodeOrDie().insertBefore(newRow);
228             }
229         }
230         return getScriptableFor(newRow);
231     }
232 
233     /**
234      * Returns the value of the {@code align} property.
235      * @return the value of the {@code align} property
236      */
237     @JsxGetter
238     public String getAlign() {
239         return getAlign(true);
240     }
241 
242     /**
243      * Sets the value of the {@code align} property.
244      * @param align the value of the {@code align} property
245      */
246     @JsxSetter
247     public void setAlign(final String align) {
248         setAlign(align, false);
249     }
250 }