|
16 | 16 |
|
17 | 17 | import static org.htmlunit.BrowserVersionFeatures.HTMLELEMENT_REMOVE_ACTIVE_TRIGGERS_BLUR_EVENT;
|
18 | 18 | import static org.htmlunit.BrowserVersionFeatures.KEYBOARD_EVENT_SPECIAL_KEYPRESS;
|
| 19 | +import static org.htmlunit.css.CssStyleSheet.ABSOLUTE; |
| 20 | +import static org.htmlunit.css.CssStyleSheet.FIXED; |
| 21 | +import static org.htmlunit.css.CssStyleSheet.STATIC; |
19 | 22 |
|
20 | 23 | import java.io.IOException;
|
21 | 24 | import java.util.ArrayList;
|
|
31 | 34 | import org.htmlunit.SgmlPage;
|
32 | 35 | import org.htmlunit.WebAssert;
|
33 | 36 | import org.htmlunit.WebClient;
|
| 37 | +import org.htmlunit.WebWindow; |
| 38 | +import org.htmlunit.css.ComputedCssStyleDeclaration; |
34 | 39 | import org.htmlunit.html.impl.SelectableTextInput;
|
35 | 40 | import org.htmlunit.javascript.HtmlUnitScriptable;
|
36 | 41 | import org.htmlunit.javascript.host.dom.Document;
|
@@ -1423,6 +1428,186 @@ public void setRequired(final boolean required) {
|
1423 | 1428 | }
|
1424 | 1429 | }
|
1425 | 1430 |
|
| 1431 | + /** |
| 1432 | + * <span style="color:red">INTERNAL API - SUBJECT TO CHANGE AT ANY TIME - USE AT YOUR OWN RISK.</span><br> |
| 1433 | + * |
| 1434 | + * @param returnNullIfFixed if position is 'fixed' return null |
| 1435 | + * @return the offset parent {@link HtmlElement} |
| 1436 | + */ |
| 1437 | + public HtmlElement getOffsetParentInternal(final boolean returnNullIfFixed) { |
| 1438 | + if (getParentNode() == null) { |
| 1439 | + return null; |
| 1440 | + } |
| 1441 | + |
| 1442 | + final WebWindow webWindow = getPage().getEnclosingWindow(); |
| 1443 | + final ComputedCssStyleDeclaration style = webWindow.getComputedStyle(this, null); |
| 1444 | + final String position = style.getPositionWithInheritance(); |
| 1445 | + |
| 1446 | + if (returnNullIfFixed && FIXED.equals(position)) { |
| 1447 | + return null; |
| 1448 | + } |
| 1449 | + |
| 1450 | + final boolean staticPos = STATIC.equals(position); |
| 1451 | + |
| 1452 | + DomNode currentElement = this; |
| 1453 | + while (currentElement != null) { |
| 1454 | + |
| 1455 | + final DomNode parentNode = currentElement.getParentNode(); |
| 1456 | + if (parentNode instanceof HtmlBody |
| 1457 | + || (staticPos && parentNode instanceof HtmlTableDataCell) |
| 1458 | + || (staticPos && parentNode instanceof HtmlTable)) { |
| 1459 | + return (HtmlElement) parentNode; |
| 1460 | + } |
| 1461 | + |
| 1462 | + if (parentNode instanceof HtmlElement) { |
| 1463 | + final ComputedCssStyleDeclaration parentStyle = |
| 1464 | + webWindow.getComputedStyle((HtmlElement) parentNode, null); |
| 1465 | + final String parentPosition = parentStyle.getPositionWithInheritance(); |
| 1466 | + if (!STATIC.equals(parentPosition)) { |
| 1467 | + return (HtmlElement) parentNode; |
| 1468 | + } |
| 1469 | + } |
| 1470 | + |
| 1471 | + currentElement = currentElement.getParentNode(); |
| 1472 | + } |
| 1473 | + |
| 1474 | + return null; |
| 1475 | + } |
| 1476 | + |
| 1477 | + /** |
| 1478 | + * @return this element's top offset, which is the calculated left position of this |
| 1479 | + * element relative to the <code>offsetParent</code>. |
| 1480 | + */ |
| 1481 | + public int getOffsetTop() { |
| 1482 | + if (this instanceof HtmlBody) { |
| 1483 | + return 0; |
| 1484 | + } |
| 1485 | + |
| 1486 | + int top = 0; |
| 1487 | + |
| 1488 | + // Add the offset for this node. |
| 1489 | + final WebWindow webWindow = getPage().getEnclosingWindow(); |
| 1490 | + ComputedCssStyleDeclaration style = webWindow.getComputedStyle(this, null); |
| 1491 | + top += style.getTop(true, false, false); |
| 1492 | + |
| 1493 | + // If this node is absolutely positioned, we're done. |
| 1494 | + final String position = style.getPositionWithInheritance(); |
| 1495 | + if (ABSOLUTE.equals(position) || FIXED.equals(position)) { |
| 1496 | + return top; |
| 1497 | + } |
| 1498 | + |
| 1499 | + final HtmlElement offsetParent = getOffsetParentInternal(false); |
| 1500 | + |
| 1501 | + // Add the offset for the ancestor nodes. |
| 1502 | + DomNode parentNode = getParentNode(); |
| 1503 | + while (parentNode != null && parentNode != offsetParent) { |
| 1504 | + if (parentNode instanceof HtmlElement) { |
| 1505 | + style = webWindow.getComputedStyle((HtmlElement) parentNode, null); |
| 1506 | + top += style.getTop(false, true, true); |
| 1507 | + } |
| 1508 | + parentNode = parentNode.getParentNode(); |
| 1509 | + } |
| 1510 | + |
| 1511 | + if (offsetParent != null) { |
| 1512 | + style = webWindow.getComputedStyle(this, null); |
| 1513 | + final boolean thisElementHasTopMargin = style.getMarginTopValue() != 0; |
| 1514 | + |
| 1515 | + style = webWindow.getComputedStyle(offsetParent, null); |
| 1516 | + if (!thisElementHasTopMargin) { |
| 1517 | + top += style.getMarginTopValue(); |
| 1518 | + } |
| 1519 | + top += style.getPaddingTopValue(); |
| 1520 | + } |
| 1521 | + |
| 1522 | + return top; |
| 1523 | + } |
| 1524 | + |
| 1525 | + /** |
| 1526 | + * @return this element's left offset, which is the calculated left position of this |
| 1527 | + * element relative to the <code>offsetParent</code>. |
| 1528 | + */ |
| 1529 | + public int getOffsetLeft() { |
| 1530 | + if (this instanceof HtmlBody) { |
| 1531 | + return 0; |
| 1532 | + } |
| 1533 | + |
| 1534 | + int left = 0; |
| 1535 | + |
| 1536 | + // Add the offset for this node. |
| 1537 | + final WebWindow webWindow = getPage().getEnclosingWindow(); |
| 1538 | + ComputedCssStyleDeclaration style = webWindow.getComputedStyle(this, null); |
| 1539 | + left += style.getLeft(true, false, false); |
| 1540 | + |
| 1541 | + // If this node is absolutely positioned, we're done. |
| 1542 | + final String position = style.getPositionWithInheritance(); |
| 1543 | + if (ABSOLUTE.equals(position) || FIXED.equals(position)) { |
| 1544 | + return left; |
| 1545 | + } |
| 1546 | + |
| 1547 | + final HtmlElement offsetParent = getOffsetParentInternal(false); |
| 1548 | + |
| 1549 | + DomNode parentNode = getParentNode(); |
| 1550 | + while (parentNode != null && parentNode != offsetParent) { |
| 1551 | + if (parentNode instanceof HtmlElement) { |
| 1552 | + style = webWindow.getComputedStyle((HtmlElement) parentNode, null); |
| 1553 | + left += style.getLeft(true, true, true); |
| 1554 | + } |
| 1555 | + parentNode = parentNode.getParentNode(); |
| 1556 | + } |
| 1557 | + |
| 1558 | + if (offsetParent != null) { |
| 1559 | + style = webWindow.getComputedStyle(offsetParent, null); |
| 1560 | + left += style.getMarginLeftValue(); |
| 1561 | + left += style.getPaddingLeftValue(); |
| 1562 | + } |
| 1563 | + |
| 1564 | + return left; |
| 1565 | + } |
| 1566 | + |
| 1567 | + /** |
| 1568 | + * Returns this element's X position. |
| 1569 | + * @return this element's X position |
| 1570 | + */ |
| 1571 | + public int getPosX() { |
| 1572 | + int cumulativeOffset = 0; |
| 1573 | + final WebWindow webWindow = getPage().getEnclosingWindow(); |
| 1574 | + |
| 1575 | + HtmlElement element = this; |
| 1576 | + while (element != null) { |
| 1577 | + cumulativeOffset += element.getOffsetLeft(); |
| 1578 | + if (element != this) { |
| 1579 | + final ComputedCssStyleDeclaration style = |
| 1580 | + webWindow.getComputedStyle(element, null); |
| 1581 | + cumulativeOffset += style.getBorderLeftValue(); |
| 1582 | + } |
| 1583 | + element = element.getOffsetParentInternal(false); |
| 1584 | + } |
| 1585 | + |
| 1586 | + return cumulativeOffset; |
| 1587 | + } |
| 1588 | + |
| 1589 | + /** |
| 1590 | + * Returns this element's Y position. |
| 1591 | + * @return this element's Y position |
| 1592 | + */ |
| 1593 | + public int getPosY() { |
| 1594 | + int cumulativeOffset = 0; |
| 1595 | + final WebWindow webWindow = getPage().getEnclosingWindow(); |
| 1596 | + |
| 1597 | + HtmlElement element = this; |
| 1598 | + while (element != null) { |
| 1599 | + cumulativeOffset += element.getOffsetTop(); |
| 1600 | + if (element != this) { |
| 1601 | + final ComputedCssStyleDeclaration style = |
| 1602 | + webWindow.getComputedStyle(element, null); |
| 1603 | + cumulativeOffset += style.getBorderTopValue(); |
| 1604 | + } |
| 1605 | + element = element.getOffsetParentInternal(false); |
| 1606 | + } |
| 1607 | + |
| 1608 | + return cumulativeOffset; |
| 1609 | + } |
| 1610 | + |
1426 | 1611 | /**
|
1427 | 1612 | * {@inheritDoc}
|
1428 | 1613 | */
|
|
0 commit comments