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 org.htmlunit.css.ComputedCssStyleDeclaration;
18  import org.htmlunit.css.StyleAttributes;
19  import org.htmlunit.html.DomNode;
20  import org.htmlunit.html.HtmlTableCell;
21  import org.htmlunit.html.HtmlTableRow;
22  import org.htmlunit.javascript.JavaScriptEngine;
23  import org.htmlunit.javascript.configuration.JsxClass;
24  import org.htmlunit.javascript.configuration.JsxConstructor;
25  import org.htmlunit.javascript.configuration.JsxGetter;
26  import org.htmlunit.javascript.configuration.JsxSetter;
27  import org.htmlunit.javascript.host.event.MouseEvent;
28  
29  /**
30   * The JavaScript object representing a TD or TH.
31   *
32   * @author Mark van Leeuwen
33   * @author Ahmed Ashour
34   * @author Sudhan Moghe
35   * @author Daniel Gredler
36   * @author Ronald Brill
37   * @author Frank Danek
38   * @author Lai Quang Duong
39   *
40   * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement">MDN Documentation</a>
41   */
42  @JsxClass(domClass = HtmlTableCell.class)
43  public class HTMLTableCellElement extends HTMLElement {
44  
45      /** The default value of the "vAlign" property. */
46      private static final String VALIGN_DEFAULT_VALUE = "top";
47  
48      /**
49       * JavaScript constructor.
50       */
51      @Override
52      @JsxConstructor
53      public void jsConstructor() {
54          super.jsConstructor();
55      }
56  
57      /**
58       * {@inheritDoc}
59       */
60      @Override
61      public int getOffsetHeight() {
62          final MouseEvent event = MouseEvent.getCurrentMouseEvent();
63          if (isAncestorOfEventTarget(event)) {
64              return super.getOffsetHeight();
65          }
66  
67          if (isDisplayNone()) {
68              return 0;
69          }
70          final ComputedCssStyleDeclaration style = getWindow().getWebWindow().getComputedStyle(getDomNodeOrDie(), null);
71          return style.getCalculatedHeight(false, true);
72      }
73  
74      /**
75       * {@inheritDoc}
76       */
77      @Override
78      public int getOffsetWidth() {
79          float w = super.getOffsetWidth();
80          final MouseEvent event = MouseEvent.getCurrentMouseEvent();
81          if (isAncestorOfEventTarget(event)) {
82              return (int) w;
83          }
84  
85          if (isDisplayNone()) {
86              return 0;
87          }
88  
89          final ComputedCssStyleDeclaration style = getWindow().getWebWindow().getComputedStyle(getDomNodeOrDie(), null);
90          if ("collapse".equals(style.getStyleAttribute(StyleAttributes.Definition.BORDER_COLLAPSE, true))) {
91              final HtmlTableRow row = getRow();
92              if (row != null) {
93                  w -= 0.5f * style.getBorderLeftValue();
94                  w -= 0.5f * style.getBorderRightValue();
95              }
96          }
97  
98          return (int) w;
99      }
100 
101     /**
102      * Returns the index of this cell within the parent row.
103      * @return the index of this cell within the parent row
104      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement/cellIndex">MDN Documentation</a>
105      */
106     @JsxGetter
107     public int getCellIndex() {
108         final HtmlTableCell cell = (HtmlTableCell) getDomNodeOrDie();
109         final HtmlTableRow row = cell.getEnclosingRow();
110         if (row == null) { // a not attached document.createElement('TD')
111             return Integer.valueOf(-1);
112         }
113         return Integer.valueOf(row.getCells().indexOf(cell));
114     }
115 
116     /**
117      * Returns the value of the {@code abbr} attribute.
118      * @return the value of the {@code abbr} attribute
119      */
120     @JsxGetter
121     public String getAbbr() {
122         return getDomNodeOrDie().getAttributeDirect("abbr");
123     }
124 
125     /**
126      * Sets the value of the {@code abbr} attribute.
127      * @param abbr the value of the {@code abbr} attribute
128      */
129     @JsxSetter
130     public void setAbbr(final String abbr) {
131         getDomNodeOrDie().setAttribute("abbr", abbr);
132     }
133 
134     /**
135      * Returns the value of the {@code axis} attribute.
136      * @return the value of the {@code axis} attribute
137      */
138     @JsxGetter
139     public String getAxis() {
140         return getDomNodeOrDie().getAttributeDirect("axis");
141     }
142 
143     /**
144      * Sets the value of the {@code axis} attribute.
145      * @param axis the value of the {@code axis} attribute
146      */
147     @JsxSetter
148     public void setAxis(final String axis) {
149         getDomNodeOrDie().setAttribute("axis", axis);
150     }
151 
152     /**
153      * Returns the value of the {@code bgColor} attribute.
154      * @return the value of the {@code bgColor} attribute
155      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement#bgcolor">MDN Documentation</a>
156      */
157     @JsxGetter
158     public String getBgColor() {
159         return getDomNodeOrDie().getAttribute("bgColor");
160     }
161 
162     /**
163      * Sets the value of the {@code bgColor} attribute.
164      * @param bgColor the value of the {@code bgColor} attribute
165      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement#bgcolor">MDN Documentation</a>
166      */
167     @JsxSetter
168     public void setBgColor(final String bgColor) {
169         setColorAttribute("bgColor", bgColor);
170     }
171 
172     /**
173      * Returns the value of the {@code colSpan} attribute.
174      * @return the value of the {@code colSpan} attribute
175      */
176     @JsxGetter
177     public int getColSpan() {
178         return ((HtmlTableCell) getDomNodeOrDie()).getColumnSpan();
179     }
180 
181     /**
182      * Sets the value of the {@code colSpan} attribute.
183      * @param colSpan the value of the {@code colSpan} attribute
184      */
185     @JsxSetter
186     public void setColSpan(final String colSpan) {
187         try {
188             final int i = (int) Double.parseDouble(colSpan);
189             if (i <= 0) {
190                 throw new NumberFormatException(colSpan);
191             }
192             getDomNodeOrDie().setAttribute("colSpan", Integer.toString(i));
193         }
194         catch (final NumberFormatException e) {
195             getDomNodeOrDie().setAttribute("colSpan", "1");
196         }
197     }
198 
199     /**
200      * Returns the value of the {@code rowSpan} attribute.
201      * @return the value of the {@code rowSpan} attribute
202      */
203     @JsxGetter
204     public int getRowSpan() {
205         return ((HtmlTableCell) getDomNodeOrDie()).getRowSpan();
206     }
207 
208     /**
209      * Sets the value of the {@code rowSpan} attribute.
210      * @param rowSpan the value of the {@code rowSpan} attribute
211      */
212     @JsxSetter
213     public void setRowSpan(final String rowSpan) {
214         try {
215             final int i = (int) Double.parseDouble(rowSpan);
216             if (i < 0) {
217                 getDomNodeOrDie().setAttribute("rowSpan", "1");
218                 return;
219             }
220             if (i == 0) {
221                 throw new NumberFormatException(rowSpan);
222             }
223             getDomNodeOrDie().setAttribute("rowSpan", Integer.toString(i));
224         }
225         catch (final NumberFormatException e) {
226             getDomNodeOrDie().setAttribute("rowSpan", "0");
227         }
228     }
229 
230     /**
231      * Returns the value of the {@code noWrap} attribute.
232      * @return the value of the {@code noWrap} attribute
233      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement#nowrap">MDN Documentation</a>
234      */
235     @JsxGetter
236     public boolean isNoWrap() {
237         return getDomNodeOrDie().hasAttribute("noWrap");
238     }
239 
240     /**
241      * Sets the value of the {@code noWrap} attribute.
242      * @param noWrap the value of the {@code noWrap} attribute
243      * @see <a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLTableCellElement#nowrap">MDN Documentation</a>
244      */
245     @JsxSetter
246     public void setNoWrap(final boolean noWrap) {
247         if (noWrap) {
248             getDomNodeOrDie().setAttribute("noWrap", "");
249         }
250         else {
251             getDomNodeOrDie().removeAttribute("noWrap");
252         }
253     }
254 
255     /**
256      * Returns the row element which contains this cell's HTML element; may return {@code null}.
257      * @return the row element which contains this cell's HTML element
258      */
259     private HtmlTableRow getRow() {
260         DomNode node = getDomNodeOrDie();
261         while (node != null && !(node instanceof HtmlTableRow)) {
262             node = node.getParentNode();
263         }
264         return (HtmlTableRow) node;
265     }
266 
267     /**
268      * Returns the value of the {@code width} property.
269      * @return the value of the {@code width} property
270      */
271     @JsxGetter(propertyName = "width")
272     public String getWidth_js() {
273         return getWidthOrHeight("width", null);
274     }
275 
276     /**
277      * Sets the value of the {@code width} property.
278      * @param width the value of the {@code width} property
279      */
280     @JsxSetter(propertyName = "width")
281     public void setWidth_js(final String width) {
282         setWidthOrHeight("width", width, true);
283     }
284 
285     /**
286      * Returns the value of the {@code height} property.
287      * @return the value of the {@code height} property
288      */
289     @JsxGetter(propertyName = "height")
290     public String getHeight_js() {
291         return getWidthOrHeight("height", null);
292     }
293 
294     /**
295      * Sets the value of the {@code height} property.
296      * @param height the value of the {@code height} property
297      */
298     @JsxSetter(propertyName = "height")
299     public void setHeight_js(final String height) {
300         setWidthOrHeight("height", height, true);
301     }
302 
303     /**
304      * Overwritten to throw an exception.
305      * @param value the new value for replacing this node
306      */
307     @Override
308     public void setOuterHTML(final Object value) {
309         throw JavaScriptEngine.reportRuntimeError("outerHTML is read-only for tag '"
310                         + getDomNodeOrDie().getTagName() + "'");
311     }
312 
313     /**
314      * Returns the {@code headers} attribute.
315      * @return the {@code headers} attribute
316      */
317     @JsxGetter
318     public String getHeaders() {
319         return getDomNodeOrDie().getAttributeDirect("headers");
320     }
321 
322     /**
323      * Sets the {@code headers} attribute.
324      * @param headers the new {@code headers} attribute value
325      */
326     @JsxSetter
327     public void setHeaders(final String headers) {
328         getDomNodeOrDie().setAttribute("headers", headers);
329     }
330 
331     /**
332      * Returns the {@code scope} attribute.
333      * @return the {@code scope} attribute
334      */
335     @JsxGetter
336     public String getScope() {
337         return getDomNodeOrDie().getAttributeDirect("scope");
338     }
339 
340     /**
341      * Sets the {@code scope} attribute.
342      * @param scope the new {@code scope} attribute value
343      */
344     @JsxSetter
345     public void setScope(final String scope) {
346         getDomNodeOrDie().setAttribute("scope", scope);
347     }
348 
349     /**
350      * Returns the value of the {@code align} property.
351      * @return the value of the {@code align} property
352      */
353     @JsxGetter
354     public String getAlign() {
355         return getAlign(true);
356     }
357 
358     /**
359      * Sets the value of the {@code align} property.
360      * @param align the value of the {@code align} property
361      */
362     @JsxSetter
363     public void setAlign(final String align) {
364         setAlign(align, false);
365     }
366 
367     /**
368      * Returns the value of the {@code vAlign} property.
369      * @return the value of the {@code vAlign} property
370      */
371     @JsxGetter
372     public String getVAlign() {
373         return getVAlign(getValidVAlignValues(), VALIGN_DEFAULT_VALUE);
374     }
375 
376     /**
377      * Sets the value of the {@code vAlign} property.
378      * @param vAlign the value of the {@code vAlign} property
379      */
380     @JsxSetter
381     public void setVAlign(final Object vAlign) {
382         setVAlign(vAlign, getValidVAlignValues());
383     }
384 
385     /**
386      * Returns the valid "vAlign" values for this element, depending on the browser being emulated.
387      * @return the valid "vAlign" values for this element, depending on the browser being emulated
388      */
389     private String[] getValidVAlignValues() {
390         return null;
391     }
392 
393     /**
394      * Returns the value of the {@code ch} property.
395      * @return the value of the {@code ch} property
396      */
397     @Override
398     @JsxGetter
399     public String getCh() {
400         return super.getCh();
401     }
402 
403     /**
404      * Sets the value of the {@code ch} property.
405      * @param ch the value of the {@code ch} property
406      */
407     @Override
408     @JsxSetter
409     public void setCh(final String ch) {
410         super.setCh(ch);
411     }
412 
413     /**
414      * Returns the value of the {@code chOff} property.
415      * @return the value of the {@code chOff} property
416      */
417     @Override
418     @JsxGetter
419     public String getChOff() {
420         return super.getChOff();
421     }
422 
423     /**
424      * Sets the value of the {@code chOff} property.
425      * @param chOff the value of the {@code chOff} property
426      */
427     @Override
428     @JsxSetter
429     public void setChOff(final String chOff) {
430         super.setChOff(chOff);
431     }
432 }