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