|
1009 | 1009 | highlightClass = 'introjs-helperLayer',
|
1010 | 1010 | nextTooltipButton,
|
1011 | 1011 | prevTooltipButton,
|
1012 |
| - skipTooltipButton; |
| 1012 | + skipTooltipButton, |
| 1013 | + scrollParent; |
1013 | 1014 |
|
1014 | 1015 | //check for a current step highlight class
|
1015 | 1016 | if (typeof (targetElement.highlightClass) === 'string') {
|
|
1044 | 1045 | }
|
1045 | 1046 | }
|
1046 | 1047 |
|
1047 |
| - //set new position to helper layer |
| 1048 | + // scroll to element |
| 1049 | + scrollParent = _getScrollParent( targetElement.element ); |
| 1050 | + |
| 1051 | + if (scrollParent !== document.body) { |
| 1052 | + // target is within a scrollable element |
| 1053 | + _scrollParentToElement(scrollParent, targetElement.element); |
| 1054 | + } |
| 1055 | + |
| 1056 | + // set new position to helper layer |
1048 | 1057 | _setHelperLayerPosition.call(self, oldHelperLayer);
|
1049 | 1058 | _setHelperLayerPosition.call(self, oldReferenceLayer);
|
1050 | 1059 |
|
|
1112 | 1121 | helperLayer.className = highlightClass;
|
1113 | 1122 | referenceLayer.className = 'introjs-tooltipReferenceLayer';
|
1114 | 1123 |
|
| 1124 | + // scroll to element |
| 1125 | + scrollParent = _getScrollParent( targetElement.element ); |
| 1126 | + |
| 1127 | + if (scrollParent !== document.body) { |
| 1128 | + // target is within a scrollable element |
| 1129 | + _scrollParentToElement(scrollParent, targetElement.element); |
| 1130 | + } |
| 1131 | + |
1115 | 1132 | //set new position to helper layer
|
1116 | 1133 | _setHelperLayerPosition.call(self, helperLayer);
|
1117 | 1134 | _setHelperLayerPosition.call(self, referenceLayer);
|
|
2090 | 2107 | * @returns Element's position info
|
2091 | 2108 | */
|
2092 | 2109 | function _getOffset(element) {
|
2093 |
| - var elementPosition = {}; |
2094 |
| - |
2095 | 2110 | var body = document.body;
|
2096 | 2111 | var docEl = document.documentElement;
|
2097 |
| - |
2098 | 2112 | var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
|
2099 | 2113 | var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
|
| 2114 | + var x = element.getBoundingClientRect(); |
| 2115 | + return { |
| 2116 | + top: x.top + scrollTop, |
| 2117 | + width: x.width, |
| 2118 | + height: x.height, |
| 2119 | + left: x.left + scrollLeft |
| 2120 | + }; |
| 2121 | + } |
2100 | 2122 |
|
2101 |
| - if (element instanceof SVGElement) { |
2102 |
| - var x = element.getBoundingClientRect(); |
2103 |
| - elementPosition.top = x.top + scrollTop; |
2104 |
| - elementPosition.width = x.width; |
2105 |
| - elementPosition.height = x.height; |
2106 |
| - elementPosition.left = x.left + scrollLeft; |
2107 |
| - } else { |
2108 |
| - //set width |
2109 |
| - elementPosition.width = element.offsetWidth; |
2110 |
| - |
2111 |
| - //set height |
2112 |
| - elementPosition.height = element.offsetHeight; |
2113 |
| - |
2114 |
| - //calculate element top and left |
2115 |
| - var _x = 0; |
2116 |
| - var _y = 0; |
2117 |
| - while (element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) { |
2118 |
| - _x += element.offsetLeft; |
2119 |
| - _y += element.offsetTop; |
2120 |
| - element = element.offsetParent; |
| 2123 | + /** |
| 2124 | + * Find the nearest scrollable parent |
| 2125 | + * copied from https://stackoverflow.com/questions/35939886/find-first-scrollable-parent |
| 2126 | + * |
| 2127 | + * @param Element element |
| 2128 | + * @return Element |
| 2129 | + */ |
| 2130 | + function _getScrollParent(element) { |
| 2131 | + var style = window.getComputedStyle(element); |
| 2132 | + var excludeStaticParent = (style.position === "absolute"); |
| 2133 | + var overflowRegex = /(auto|scroll)/; |
| 2134 | + |
| 2135 | + if (style.position === "fixed") return document.body; |
| 2136 | + |
| 2137 | + for (var parent = element; (parent = parent.parentElement);) { |
| 2138 | + style = window.getComputedStyle(parent); |
| 2139 | + if (excludeStaticParent && style.position === "static") { |
| 2140 | + continue; |
2121 | 2141 | }
|
2122 |
| - //set top |
2123 |
| - elementPosition.top = _y; |
2124 |
| - //set left |
2125 |
| - elementPosition.left = _x; |
| 2142 | + if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) return parent; |
2126 | 2143 | }
|
2127 | 2144 |
|
2128 |
| - return elementPosition; |
| 2145 | + return document.body; |
| 2146 | + } |
| 2147 | + |
| 2148 | + /** |
| 2149 | + * scroll a scrollable element to a child element |
| 2150 | + * |
| 2151 | + * @param Element parent |
| 2152 | + * @param Element element |
| 2153 | + * @return Null |
| 2154 | + */ |
| 2155 | + function _scrollParentToElement (parent, element) { |
| 2156 | + parent.scrollTop = element.offsetTop - parent.offsetTop; |
2129 | 2157 | }
|
2130 | 2158 |
|
2131 | 2159 | /**
|
|
0 commit comments