|
1023 | 1023 | highlightClass = 'introjs-helperLayer',
|
1024 | 1024 | nextTooltipButton,
|
1025 | 1025 | prevTooltipButton,
|
1026 |
| - skipTooltipButton; |
| 1026 | + skipTooltipButton, |
| 1027 | + scrollParent; |
1027 | 1028 |
|
1028 | 1029 | //check for a current step highlight class
|
1029 | 1030 | if (typeof (targetElement.highlightClass) === 'string') {
|
|
1058 | 1059 | }
|
1059 | 1060 | }
|
1060 | 1061 |
|
1061 |
| - //set new position to helper layer |
| 1062 | + // scroll to element |
| 1063 | + scrollParent = _getScrollParent( targetElement.element ); |
| 1064 | + |
| 1065 | + if (scrollParent !== document.body) { |
| 1066 | + // target is within a scrollable element |
| 1067 | + _scrollParentToElement(scrollParent, targetElement.element); |
| 1068 | + } |
| 1069 | + |
| 1070 | + // set new position to helper layer |
1062 | 1071 | _setHelperLayerPosition.call(self, oldHelperLayer);
|
1063 | 1072 | _setHelperLayerPosition.call(self, oldReferenceLayer);
|
1064 | 1073 |
|
|
1126 | 1135 | helperLayer.className = highlightClass;
|
1127 | 1136 | referenceLayer.className = 'introjs-tooltipReferenceLayer';
|
1128 | 1137 |
|
| 1138 | + // scroll to element |
| 1139 | + scrollParent = _getScrollParent( targetElement.element ); |
| 1140 | + |
| 1141 | + if (scrollParent !== document.body) { |
| 1142 | + // target is within a scrollable element |
| 1143 | + _scrollParentToElement(scrollParent, targetElement.element); |
| 1144 | + } |
| 1145 | + |
1129 | 1146 | //set new position to helper layer
|
1130 | 1147 | _setHelperLayerPosition.call(self, helperLayer);
|
1131 | 1148 | _setHelperLayerPosition.call(self, referenceLayer);
|
|
2104 | 2121 | * @returns Element's position info
|
2105 | 2122 | */
|
2106 | 2123 | function _getOffset(element) {
|
2107 |
| - var elementPosition = {}; |
2108 |
| - |
2109 | 2124 | var body = document.body;
|
2110 | 2125 | var docEl = document.documentElement;
|
2111 |
| - |
2112 | 2126 | var scrollTop = window.pageYOffset || docEl.scrollTop || body.scrollTop;
|
2113 | 2127 | var scrollLeft = window.pageXOffset || docEl.scrollLeft || body.scrollLeft;
|
| 2128 | + var x = element.getBoundingClientRect(); |
| 2129 | + return { |
| 2130 | + top: x.top + scrollTop, |
| 2131 | + width: x.width, |
| 2132 | + height: x.height, |
| 2133 | + left: x.left + scrollLeft |
| 2134 | + }; |
| 2135 | + } |
2114 | 2136 |
|
2115 |
| - if (element instanceof SVGElement) { |
2116 |
| - var x = element.getBoundingClientRect(); |
2117 |
| - elementPosition.top = x.top + scrollTop; |
2118 |
| - elementPosition.width = x.width; |
2119 |
| - elementPosition.height = x.height; |
2120 |
| - elementPosition.left = x.left + scrollLeft; |
2121 |
| - } else { |
2122 |
| - //set width |
2123 |
| - elementPosition.width = element.offsetWidth; |
2124 |
| - |
2125 |
| - //set height |
2126 |
| - elementPosition.height = element.offsetHeight; |
2127 |
| - |
2128 |
| - //calculate element top and left |
2129 |
| - var _x = 0; |
2130 |
| - var _y = 0; |
2131 |
| - while (element && !isNaN(element.offsetLeft) && !isNaN(element.offsetTop)) { |
2132 |
| - _x += element.offsetLeft; |
2133 |
| - _y += element.offsetTop; |
2134 |
| - element = element.offsetParent; |
| 2137 | + /** |
| 2138 | + * Find the nearest scrollable parent |
| 2139 | + * copied from https://stackoverflow.com/questions/35939886/find-first-scrollable-parent |
| 2140 | + * |
| 2141 | + * @param Element element |
| 2142 | + * @return Element |
| 2143 | + */ |
| 2144 | + function _getScrollParent(element) { |
| 2145 | + var style = window.getComputedStyle(element); |
| 2146 | + var excludeStaticParent = (style.position === "absolute"); |
| 2147 | + var overflowRegex = /(auto|scroll)/; |
| 2148 | + |
| 2149 | + if (style.position === "fixed") return document.body; |
| 2150 | + |
| 2151 | + for (var parent = element; (parent = parent.parentElement);) { |
| 2152 | + style = window.getComputedStyle(parent); |
| 2153 | + if (excludeStaticParent && style.position === "static") { |
| 2154 | + continue; |
2135 | 2155 | }
|
2136 |
| - //set top |
2137 |
| - elementPosition.top = _y; |
2138 |
| - //set left |
2139 |
| - elementPosition.left = _x; |
| 2156 | + if (overflowRegex.test(style.overflow + style.overflowY + style.overflowX)) return parent; |
2140 | 2157 | }
|
2141 | 2158 |
|
2142 |
| - return elementPosition; |
| 2159 | + return document.body; |
| 2160 | + } |
| 2161 | + |
| 2162 | + /** |
| 2163 | + * scroll a scrollable element to a child element |
| 2164 | + * |
| 2165 | + * @param Element parent |
| 2166 | + * @param Element element |
| 2167 | + * @return Null |
| 2168 | + */ |
| 2169 | + function _scrollParentToElement (parent, element) { |
| 2170 | + parent.scrollTop = element.offsetTop - parent.offsetTop; |
2143 | 2171 | }
|
2144 | 2172 |
|
2145 | 2173 | /**
|
|
0 commit comments