1
2
3
4
5
6
7
8
9
10
11
12
13
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.Predicate;
21 import java.util.function.Supplier;
22
23 import org.htmlunit.html.DomElement;
24 import org.htmlunit.html.DomNode;
25 import org.htmlunit.html.HtmlElement;
26 import org.htmlunit.html.HtmlPage;
27 import org.htmlunit.html.HtmlTable;
28 import org.htmlunit.html.HtmlTableBody;
29 import org.htmlunit.html.HtmlTableFooter;
30 import org.htmlunit.html.HtmlTableHeader;
31 import org.htmlunit.html.HtmlTableRow;
32 import org.htmlunit.javascript.HtmlUnitScriptable;
33 import org.htmlunit.javascript.JavaScriptEngine;
34 import org.htmlunit.javascript.configuration.JsxClass;
35 import org.htmlunit.javascript.configuration.JsxConstructor;
36 import org.htmlunit.javascript.configuration.JsxFunction;
37 import org.htmlunit.javascript.configuration.JsxGetter;
38 import org.htmlunit.javascript.configuration.JsxSetter;
39 import org.htmlunit.javascript.host.dom.DOMException;
40 import org.htmlunit.javascript.host.dom.Node;
41
42
43
44
45
46
47
48
49
50
51
52
53
54 @JsxClass(domClass = HtmlTable.class)
55 public class HTMLTableElement extends HTMLElement {
56
57
58
59
60 @Override
61 @JsxConstructor
62 public void jsConstructor() {
63 super.jsConstructor();
64 }
65
66
67
68
69
70
71 @JsxGetter
72 public HtmlUnitScriptable getCaption() {
73 final List<HtmlElement> captions = getDomNodeOrDie().getStaticElementsByTagName("caption");
74 if (captions.isEmpty()) {
75 return null;
76 }
77 return getScriptableFor(captions.get(0));
78 }
79
80
81
82
83
84 @JsxSetter
85 public void setCaption(final Object o) {
86 if (!(o instanceof HTMLTableCaptionElement)) {
87 throw JavaScriptEngine.typeError("Not a caption");
88 }
89
90
91 deleteCaption();
92
93 final HTMLTableCaptionElement caption = (HTMLTableCaptionElement) o;
94 getDomNodeOrDie().appendChild(caption.getDomNodeOrDie());
95 }
96
97
98
99
100
101
102 @JsxGetter
103 public HtmlUnitScriptable getTFoot() {
104 final List<HtmlElement> tfoots = getDomNodeOrDie().getStaticElementsByTagName("tfoot");
105 if (tfoots.isEmpty()) {
106 return null;
107 }
108 return getScriptableFor(tfoots.get(0));
109 }
110
111
112
113
114
115 @JsxSetter
116 public void setTFoot(final Object o) {
117 if (!(o instanceof HTMLTableSectionElement
118 && "TFOOT".equals(((HTMLTableSectionElement) o).getTagName()))) {
119 throw JavaScriptEngine.typeError("Not a tFoot");
120 }
121
122
123 deleteTFoot();
124
125 final HTMLTableSectionElement tfoot = (HTMLTableSectionElement) o;
126 getDomNodeOrDie().appendChild(tfoot.getDomNodeOrDie());
127 }
128
129
130
131
132
133
134 @JsxGetter
135 public HtmlUnitScriptable getTHead() {
136 final List<HtmlElement> theads = getDomNodeOrDie().getStaticElementsByTagName("thead");
137 if (theads.isEmpty()) {
138 return null;
139 }
140 return getScriptableFor(theads.get(0));
141 }
142
143
144
145
146
147 @JsxSetter
148 public void setTHead(final Object o) {
149 if (!(o instanceof HTMLTableSectionElement
150 && "THEAD".equals(((HTMLTableSectionElement) o).getTagName()))) {
151 throw JavaScriptEngine.typeError("Not a tHead");
152 }
153
154
155 deleteTHead();
156
157 final HTMLTableSectionElement thead = (HTMLTableSectionElement) o;
158 getDomNodeOrDie().appendChild(thead.getDomNodeOrDie());
159 }
160
161
162
163
164
165 @JsxGetter
166 public HtmlUnitScriptable getTBodies() {
167 final HtmlTable table = (HtmlTable) getDomNodeOrDie();
168 final HTMLCollection bodies = new HTMLCollection(table, false);
169 bodies.setElementsSupplier((Supplier<List<DomNode>> & Serializable) () -> new ArrayList<>(table.getBodies()));
170 return bodies;
171 }
172
173
174
175
176
177
178
179
180 @JsxFunction
181 public HtmlUnitScriptable createCaption() {
182 return getScriptableFor(getDomNodeOrDie().appendChildIfNoneExists("caption"));
183 }
184
185
186
187
188
189
190
191
192 @JsxFunction
193 public HtmlUnitScriptable createTFoot() {
194 return getScriptableFor(getDomNodeOrDie().appendChildIfNoneExists("tfoot"));
195 }
196
197
198
199
200
201
202
203
204 @JsxFunction
205 public HtmlUnitScriptable createTBody() {
206 return getScriptableFor(getDomNodeOrDie().appendChildIfNoneExists("tbody"));
207 }
208
209
210
211
212
213
214
215
216 @JsxFunction
217 public HtmlUnitScriptable createTHead() {
218 return getScriptableFor(getDomNodeOrDie().appendChildIfNoneExists("thead"));
219 }
220
221
222
223
224
225
226
227 @JsxFunction
228 public void deleteCaption() {
229 getDomNodeOrDie().removeChild("caption", 0);
230 }
231
232
233
234
235
236
237
238 @JsxFunction
239 public void deleteTFoot() {
240 getDomNodeOrDie().removeChild("tfoot", 0);
241 }
242
243
244
245
246
247
248
249 @JsxFunction
250 public void deleteTHead() {
251 getDomNodeOrDie().removeChild("thead", 0);
252 }
253
254
255
256
257
258
259
260
261
262
263 @JsxFunction
264 public HtmlUnitScriptable insertRow(final Object index) {
265 int rowIndex = -1;
266 if (!JavaScriptEngine.isUndefined(index)) {
267 rowIndex = (int) JavaScriptEngine.toNumber(index);
268 }
269 final HTMLCollection rows = getRows();
270 final int rowCount = rows.getLength();
271 final int r;
272 if (rowIndex == -1 || rowIndex == rowCount) {
273 r = Math.max(0, rowCount);
274 }
275 else {
276 r = rowIndex;
277 }
278
279 if (r < 0 || r > rowCount) {
280 throw JavaScriptEngine.asJavaScriptException(
281 getWindow(),
282 "Index or size is negative or greater than the allowed amount "
283 + "(index: " + rowIndex + ", " + rowCount + " rows)",
284 DOMException.INDEX_SIZE_ERR);
285 }
286
287 return insertRow(r);
288 }
289
290
291
292
293
294
295 public HtmlUnitScriptable insertRow(final int index) {
296
297 if (index != 0) {
298 for (final HtmlElement htmlElement : getDomNodeOrDie().getHtmlElementDescendants()) {
299 if (htmlElement instanceof HtmlTableBody
300 || htmlElement instanceof HtmlTableHeader
301 || htmlElement instanceof HtmlTableFooter) {
302
303 final HTMLCollection rows = getRows();
304 final int rowCount = rows.getLength();
305 final DomElement newRow = ((HtmlPage) getDomNodeOrDie().getPage()).createElement("tr");
306 if (rowCount == 0) {
307 getDomNodeOrDie().appendChild(newRow);
308 }
309 else if (index == rowCount) {
310 final HtmlUnitScriptable row = (HtmlUnitScriptable) rows.item(Integer.valueOf(index - 1));
311 row.getDomNodeOrDie().getParentNode().appendChild(newRow);
312 }
313 else {
314 final HtmlUnitScriptable row = (HtmlUnitScriptable) rows.item(Integer.valueOf(index));
315
316 if (index > rowCount - 1) {
317 row.getDomNodeOrDie().getParentNode().appendChild(newRow);
318 }
319 else {
320 row.getDomNodeOrDie().insertBefore(newRow);
321 }
322 }
323 return getScriptableFor(newRow);
324 }
325 }
326 }
327
328 final HtmlElement tBody = getDomNodeOrDie().appendChildIfNoneExists("tbody");
329 return ((HTMLTableSectionElement) getScriptableFor(tBody)).insertRow(0);
330 }
331
332
333
334
335
336 @JsxGetter(propertyName = "width")
337 public String getWidth_js() {
338 return getDomNodeOrDie().getAttributeDirect("width");
339 }
340
341
342
343
344
345 @JsxSetter(propertyName = "width")
346 public void setWidth_js(final String width) {
347 getDomNodeOrDie().setAttribute("width", width);
348 }
349
350
351
352
353
354 @JsxGetter
355 public String getCellSpacing() {
356 return getDomNodeOrDie().getAttributeDirect("cellspacing");
357 }
358
359
360
361
362
363 @JsxSetter
364 public void setCellSpacing(final String cellSpacing) {
365 getDomNodeOrDie().setAttribute("cellspacing", cellSpacing);
366 }
367
368
369
370
371
372 @JsxGetter
373 public String getCellPadding() {
374 return getDomNodeOrDie().getAttributeDirect("cellpadding");
375 }
376
377
378
379
380
381 @JsxSetter
382 public void setCellPadding(final String cellPadding) {
383 getDomNodeOrDie().setAttribute("cellpadding", cellPadding);
384 }
385
386
387
388
389
390 @JsxGetter
391 public String getBorder() {
392 return getDomNodeOrDie().getAttributeDirect("border");
393 }
394
395
396
397
398
399 @JsxSetter
400 public void setBorder(final String border) {
401 getDomNodeOrDie().setAttribute("border", border);
402 }
403
404
405
406
407
408
409 @JsxGetter
410 public String getBgColor() {
411 return getDomNodeOrDie().getAttribute("bgColor");
412 }
413
414
415
416
417
418
419 @JsxSetter
420 public void setBgColor(final String bgColor) {
421 setColorAttribute("bgColor", bgColor);
422 }
423
424
425
426
427 @Override
428 public Node appendChild(final Object childObject) {
429 final Node appendedChild = super.appendChild(childObject);
430 getDomNodeOrDie().getPage().clearComputedStyles(getDomNodeOrDie());
431 return appendedChild;
432 }
433
434
435
436
437 @Override
438 public Node removeChild(final Object childObject) {
439 final Node removedChild = super.removeChild(childObject);
440 getDomNodeOrDie().getPage().clearComputedStyles(getDomNodeOrDie());
441 return removedChild;
442 }
443
444
445
446
447
448 @JsxGetter
449 public String getSummary() {
450 return getDomNodeOrDie().getAttributeDirect("summary");
451 }
452
453
454
455
456
457 @JsxSetter
458 public void setSummary(final String summary) {
459 setAttribute("summary", summary);
460 }
461
462
463
464
465
466 @JsxGetter
467 public String getRules() {
468 return getDomNodeOrDie().getAttributeDirect("rules");
469 }
470
471
472
473
474
475 @JsxSetter
476 public void setRules(final String rules) {
477 setAttribute("rules", rules);
478 }
479
480
481
482
483
484 @JsxGetter
485 public String getAlign() {
486 return getAlign(true);
487 }
488
489
490
491
492
493 @JsxSetter
494 public void setAlign(final String align) {
495 setAlign(align, false);
496 }
497
498
499
500
501
502
503 @JsxFunction
504 public void deleteRow(int rowIndex) {
505 final HTMLCollection rows = getRows();
506 final int rowCount = rows.getLength();
507 if (rowIndex == -1) {
508 rowIndex = rowCount - 1;
509 }
510 final boolean rowIndexValid = rowIndex >= 0 && rowIndex < rowCount;
511 if (rowIndexValid) {
512 final HtmlUnitScriptable row = (HtmlUnitScriptable) rows.item(Integer.valueOf(rowIndex));
513 row.getDomNodeOrDie().remove();
514 }
515 }
516
517
518
519
520
521 @JsxGetter
522 public HTMLCollection getRows() {
523 final HTMLCollection rows = new HTMLCollection(getDomNodeOrDie(), false);
524 rows.setIsMatchingPredicate(
525 (Predicate<DomNode> & Serializable)
526 node -> node instanceof HtmlTableRow && isContainedRow((HtmlTableRow) node));
527 return rows;
528 }
529
530
531
532
533
534
535 private boolean isContainedRow(final HtmlTableRow row) {
536 final DomNode parent = row.getParentNode();
537 return parent != null
538 && parent.getParentNode() == getDomNodeOrDie();
539 }
540 }