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 static org.htmlunit.BrowserVersionFeatures.JS_TABLE_SPAN_SET_ZERO_IF_INVALID;
18  
19  import org.htmlunit.css.ComputedCssStyleDeclaration;
20  import org.htmlunit.css.StyleAttributes;
21  import org.htmlunit.html.DomNode;
22  import org.htmlunit.html.HtmlTableCell;
23  import org.htmlunit.html.HtmlTableRow;
24  import org.htmlunit.javascript.JavaScriptEngine;
25  import org.htmlunit.javascript.configuration.JsxClass;
26  import org.htmlunit.javascript.configuration.JsxConstructor;
27  import org.htmlunit.javascript.configuration.JsxGetter;
28  import org.htmlunit.javascript.configuration.JsxSetter;
29  import org.htmlunit.javascript.host.event.MouseEvent;
30  
31  /**
32   * The JavaScript object representing a TD or TH.
33   *
34   * @author <a href="https://sourceforge.net/users/marlee/">Mark van Leeuwen</a>
35   * @author Ahmed Ashour
36   * @author Sudhan Moghe
37   * @author Daniel Gredler
38   * @author Ronald Brill
39   * @author Frank Danek
40   * @author Lai Quang Duong
41   */
42  @JsxClass(domClass = HtmlTableCell.class)
43  public class HTMLTableCellElement extends HTMLTableComponent {
44  
45      /**
46       * JavaScript constructor.
47       */
48      @Override
49      @JsxConstructor
50      public void jsConstructor() {
51          super.jsConstructor();
52      }
53  
54      /**
55       * {@inheritDoc}
56       */
57      @Override
58      public int getOffsetHeight() {
59          final MouseEvent event = MouseEvent.getCurrentMouseEvent();
60          if (isAncestorOfEventTarget(event)) {
61              return super.getOffsetHeight();
62          }
63  
64          if (isDisplayNone()) {
65              return 0;
66          }
67          final ComputedCssStyleDeclaration style = getWindow().getWebWindow().getComputedStyle(getDomNodeOrDie(), null);
68          return style.getCalculatedHeight(false, true);
69      }
70  
71      /**
72       * {@inheritDoc}
73       */
74      @Override
75      public int getOffsetWidth() {
76          float w = super.getOffsetWidth();
77          final MouseEvent event = MouseEvent.getCurrentMouseEvent();
78          if (isAncestorOfEventTarget(event)) {
79              return (int) w;
80          }
81  
82          if (isDisplayNone()) {
83              return 0;
84          }
85  
86          final ComputedCssStyleDeclaration style = getWindow().getWebWindow().getComputedStyle(getDomNodeOrDie(), null);
87          if ("collapse".equals(style.getStyleAttribute(StyleAttributes.Definition.BORDER_COLLAPSE, true))) {
88              final HtmlTableRow row = getRow();
89              if (row != null) {
90                  w -= 0.5 * style.getBorderLeftValue();
91                  w -= 0.5 * style.getBorderRightValue();
92              }
93          }
94  
95          return (int) w;
96      }
97  
98      /**
99       * Returns the index of this cell within the parent row.
100      * @return the index of this cell within the parent row
101      * @see <a href="http://msdn.microsoft.com/en-us/library/ms533549.aspx">MSDN Documentation</a>
102      */
103     @JsxGetter
104     public int getCellIndex() {
105         final HtmlTableCell cell = (HtmlTableCell) getDomNodeOrDie();
106         final HtmlTableRow row = cell.getEnclosingRow();
107         if (row == null) { // a not attached document.createElement('TD')
108             return Integer.valueOf(-1);
109         }
110         return Integer.valueOf(row.getCells().indexOf(cell));
111     }
112 
113     /**
114      * Returns the value of the {@code abbr} attribute.
115      * @return the value of the {@code abbr} attribute
116      */
117     @JsxGetter
118     public String getAbbr() {
119         return getDomNodeOrDie().getAttributeDirect("abbr");
120     }
121 
122     /**
123      * Sets the value of the {@code abbr} attribute.
124      * @param abbr the value of the {@code abbr} attribute
125      */
126     @JsxSetter
127     public void setAbbr(final String abbr) {
128         getDomNodeOrDie().setAttribute("abbr", abbr);
129     }
130 
131     /**
132      * Returns the value of the {@code axis} attribute.
133      * @return the value of the {@code axis} attribute
134      */
135     @JsxGetter
136     public String getAxis() {
137         return getDomNodeOrDie().getAttributeDirect("axis");
138     }
139 
140     /**
141      * Sets the value of the {@code axis} attribute.
142      * @param axis the value of the {@code axis} attribute
143      */
144     @JsxSetter
145     public void setAxis(final String axis) {
146         getDomNodeOrDie().setAttribute("axis", axis);
147     }
148 
149     /**
150      * Returns the value of the {@code bgColor} attribute.
151      * @return the value of the {@code bgColor} attribute
152      * @see <a href="http://msdn.microsoft.com/en-us/library/ms533505.aspx">MSDN Documentation</a>
153      */
154     @JsxGetter
155     public String getBgColor() {
156         return getDomNodeOrDie().getAttribute("bgColor");
157     }
158 
159     /**
160      * Sets the value of the {@code bgColor} attribute.
161      * @param bgColor the value of the {@code bgColor} attribute
162      * @see <a href="http://msdn.microsoft.com/en-us/library/ms533505.aspx">MSDN Documentation</a>
163      */
164     @JsxSetter
165     public void setBgColor(final String bgColor) {
166         setColorAttribute("bgColor", bgColor);
167     }
168 
169     /**
170      * Returns the value of the {@code colSpan} attribute.
171      * @return the value of the {@code colSpan} attribute
172      */
173     @JsxGetter
174     public int getColSpan() {
175         return ((HtmlTableCell) getDomNodeOrDie()).getColumnSpan();
176     }
177 
178     /**
179      * Sets the value of the {@code colSpan} attribute.
180      * @param colSpan the value of the {@code colSpan} attribute
181      */
182     @JsxSetter
183     public void setColSpan(final String colSpan) {
184         try {
185             final int i = (int) Double.parseDouble(colSpan);
186             if (i <= 0) {
187                 throw new NumberFormatException(colSpan);
188             }
189             getDomNodeOrDie().setAttribute("colSpan", Integer.toString(i));
190         }
191         catch (final NumberFormatException e) {
192             getDomNodeOrDie().setAttribute("colSpan", "1");
193         }
194     }
195 
196     /**
197      * Returns the value of the {@code rowSpan} attribute.
198      * @return the value of the {@code rowSpan} attribute
199      */
200     @JsxGetter
201     public int getRowSpan() {
202         return ((HtmlTableCell) getDomNodeOrDie()).getRowSpan();
203     }
204 
205     /**
206      * Sets the value of the {@code rowSpan} attribute.
207      * @param rowSpan the value of the {@code rowSpan} attribute
208      */
209     @JsxSetter
210     public void setRowSpan(final String rowSpan) {
211         try {
212             final int i = (int) Double.parseDouble(rowSpan);
213             if (i < 0 && getBrowserVersion().hasFeature(JS_TABLE_SPAN_SET_ZERO_IF_INVALID)) {
214                 getDomNodeOrDie().setAttribute("rowSpan", "1");
215                 return;
216             }
217             if (i <= 0) {
218                 throw new NumberFormatException(rowSpan);
219             }
220             getDomNodeOrDie().setAttribute("rowSpan", Integer.toString(i));
221         }
222         catch (final NumberFormatException e) {
223             if (getBrowserVersion().hasFeature(JS_TABLE_SPAN_SET_ZERO_IF_INVALID)) {
224                 getDomNodeOrDie().setAttribute("rowSpan", "0");
225             }
226             else {
227                 getDomNodeOrDie().setAttribute("rowSpan", "1");
228             }
229         }
230     }
231 
232     /**
233      * Returns the value of the {@code noWrap} attribute.
234      * @return the value of the {@code noWrap} attribute
235      * @see <a href="http://msdn.microsoft.com/en-us/library/ms534196.aspx">MSDN Documentation</a>
236      */
237     @JsxGetter
238     public boolean isNoWrap() {
239         return getDomNodeOrDie().hasAttribute("noWrap");
240     }
241 
242     /**
243      * Sets the value of the {@code noWrap} attribute.
244      * @param noWrap the value of the {@code noWrap} attribute
245      * @see <a href="http://msdn.microsoft.com/en-us/library/ms534196.aspx">MSDN Documentation</a>
246      */
247     @JsxSetter
248     public void setNoWrap(final boolean noWrap) {
249         if (noWrap) {
250             getDomNodeOrDie().setAttribute("noWrap", "");
251         }
252         else {
253             getDomNodeOrDie().removeAttribute("noWrap");
254         }
255     }
256 
257     /**
258      * Returns the row element which contains this cell's HTML element; may return {@code null}.
259      * @return the row element which contains this cell's HTML element
260      */
261     private HtmlTableRow getRow() {
262         DomNode node = getDomNodeOrDie();
263         while (node != null && !(node instanceof HtmlTableRow)) {
264             node = node.getParentNode();
265         }
266         return (HtmlTableRow) node;
267     }
268 
269     /**
270      * Returns the value of the {@code width} property.
271      * @return the value of the {@code width} property
272      */
273     @JsxGetter(propertyName = "width")
274     public String getWidth_js() {
275         return getWidthOrHeight("width", null);
276     }
277 
278     /**
279      * Sets the value of the {@code width} property.
280      * @param width the value of the {@code width} property
281      */
282     @JsxSetter(propertyName = "width")
283     public void setWidth_js(final String width) {
284         setWidthOrHeight("width", width, true);
285     }
286 
287     /**
288      * Returns the value of the {@code width} property.
289      * @return the value of the {@code width} property
290      */
291     @JsxGetter(propertyName = "height")
292     public String getHeight_js() {
293         return getWidthOrHeight("height", null);
294     }
295 
296     /**
297      * Sets the value of the {@code height} property.
298      * @param height the value of the {@code height} property
299      */
300     @JsxSetter(propertyName = "height")
301     public void setHeight_js(final String height) {
302         setWidthOrHeight("height", height, true);
303     }
304 
305     /**
306      * Overwritten to throw an exception.
307      * @param value the new value for replacing this node
308      */
309     @Override
310     public void setOuterHTML(final Object value) {
311         throw JavaScriptEngine.reportRuntimeError("outerHTML is read-only for tag '"
312                         + getDomNodeOrDie().getTagName() + "'");
313     }
314 
315     /**
316      * Returns the {@code headers} attribute.
317      * @return the {@code headers} attribute
318      */
319     @JsxGetter
320     public String getHeaders() {
321         return getDomNodeOrDie().getAttributeDirect("headers");
322     }
323 
324     /**
325      * Sets the {@code headers} attribute.
326      * @param headers the new attribute
327      */
328     @JsxSetter
329     public void setHeaders(final String headers) {
330         getDomNodeOrDie().setAttribute("headers", headers);
331     }
332 
333     /**
334      * Returns the {@code scope} attribute.
335      * @return the {@code scope} attribute
336      */
337     @JsxGetter
338     public String getScope() {
339         return getDomNodeOrDie().getAttributeDirect("scope");
340     }
341 
342     /**
343      * Sets the {@code scope} attribute.
344      * @param scope the new attribute
345      */
346     @JsxSetter
347     public void setScope(final String scope) {
348         getDomNodeOrDie().setAttribute("scope", scope);
349     }
350 }