Bring element to view if not in view
Browse files- assets/scripts/src/element.js +42 -5
- assets/scripts/src/sholo.js +12 -2
- index.html +2 -0
assets/scripts/src/element.js
CHANGED
|
@@ -34,6 +34,40 @@ export default class Element {
|
|
| 34 |
return { x, y };
|
| 35 |
}
|
| 36 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 37 |
/**
|
| 38 |
* Gets the calculated position on screen, around which
|
| 39 |
* we need to draw
|
|
@@ -82,17 +116,17 @@ export default class Element {
|
|
| 82 |
|
| 83 |
const popoverTip = this.popover.querySelector('.sholo-popover-tip');
|
| 84 |
|
| 85 |
-
const
|
| 86 |
const popoverHeight = this.getPopoverHeight();
|
| 87 |
const popoverMargin = this.options.padding + 10;
|
| 88 |
|
| 89 |
this.popover.style.left = `${position.left - this.options.padding}px`;
|
| 90 |
|
| 91 |
// Calculate different dimensions after attaching popover
|
| 92 |
-
const
|
| 93 |
|
| 94 |
// If adding popover would go out of the window height, then show it to the top
|
| 95 |
-
if (
|
| 96 |
this.popover.style.top = `${position.top - popoverHeight - popoverMargin}px`;
|
| 97 |
popoverTip.classList.add('bottom');
|
| 98 |
} else {
|
|
@@ -113,12 +147,15 @@ export default class Element {
|
|
| 113 |
this.popover.style.display = 'none';
|
| 114 |
}
|
| 115 |
|
| 116 |
-
|
| 117 |
// eslint-disable-next-line prefer-destructuring
|
| 118 |
const body = this.document.body;
|
| 119 |
const html = this.document.documentElement;
|
| 120 |
|
| 121 |
-
return
|
|
|
|
|
|
|
|
|
|
| 122 |
}
|
| 123 |
|
| 124 |
getPopoverHeight() {
|
|
|
|
| 34 |
return { x, y };
|
| 35 |
}
|
| 36 |
|
| 37 |
+
isInView() {
|
| 38 |
+
let top = this.node.offsetTop;
|
| 39 |
+
let left = this.node.offsetLeft;
|
| 40 |
+
const width = this.node.offsetWidth;
|
| 41 |
+
const height = this.node.offsetHeight;
|
| 42 |
+
|
| 43 |
+
let el = this.node;
|
| 44 |
+
|
| 45 |
+
while (el.offsetParent) {
|
| 46 |
+
el = el.offsetParent;
|
| 47 |
+
top += el.offsetTop;
|
| 48 |
+
left += el.offsetLeft;
|
| 49 |
+
}
|
| 50 |
+
|
| 51 |
+
return (
|
| 52 |
+
top >= this.window.pageYOffset &&
|
| 53 |
+
left >= this.window.pageXOffset &&
|
| 54 |
+
(top + height) <= (this.window.pageYOffset + this.window.innerHeight) &&
|
| 55 |
+
(left + width) <= (this.window.pageXOffset + this.window.innerWidth)
|
| 56 |
+
);
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
bringInView() {
|
| 60 |
+
if (this.isInView()) {
|
| 61 |
+
return;
|
| 62 |
+
}
|
| 63 |
+
|
| 64 |
+
const elementRect = this.getCalculatedPosition();
|
| 65 |
+
const absoluteElementTop = elementRect.top + window.pageYOffset;
|
| 66 |
+
const middle = absoluteElementTop - (window.innerHeight / 2);
|
| 67 |
+
|
| 68 |
+
window.scrollTo(0, middle);
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
/**
|
| 72 |
* Gets the calculated position on screen, around which
|
| 73 |
* we need to draw
|
|
|
|
| 116 |
|
| 117 |
const popoverTip = this.popover.querySelector('.sholo-popover-tip');
|
| 118 |
|
| 119 |
+
const pageHeight = this.getFullPageSize().height;
|
| 120 |
const popoverHeight = this.getPopoverHeight();
|
| 121 |
const popoverMargin = this.options.padding + 10;
|
| 122 |
|
| 123 |
this.popover.style.left = `${position.left - this.options.padding}px`;
|
| 124 |
|
| 125 |
// Calculate different dimensions after attaching popover
|
| 126 |
+
const pageHeightAfterPopOver = position.bottom + popoverHeight + popoverMargin;
|
| 127 |
|
| 128 |
// If adding popover would go out of the window height, then show it to the top
|
| 129 |
+
if (pageHeightAfterPopOver >= pageHeight) {
|
| 130 |
this.popover.style.top = `${position.top - popoverHeight - popoverMargin}px`;
|
| 131 |
popoverTip.classList.add('bottom');
|
| 132 |
} else {
|
|
|
|
| 147 |
this.popover.style.display = 'none';
|
| 148 |
}
|
| 149 |
|
| 150 |
+
getFullPageSize() {
|
| 151 |
// eslint-disable-next-line prefer-destructuring
|
| 152 |
const body = this.document.body;
|
| 153 |
const html = this.document.documentElement;
|
| 154 |
|
| 155 |
+
return {
|
| 156 |
+
height: Math.max(body.scrollHeight, body.offsetHeight, html.scrollHeight, html.offsetHeight),
|
| 157 |
+
width: Math.max(body.scrollWidth, body.offsetWidth, html.scrollWidth, html.offsetWidth),
|
| 158 |
+
};
|
| 159 |
}
|
| 160 |
|
| 161 |
getPopoverHeight() {
|
assets/scripts/src/sholo.js
CHANGED
|
@@ -72,12 +72,22 @@ export default class Sholo {
|
|
| 72 |
const prevClicked = e.target.classList.contains('sholo-prev-btn');
|
| 73 |
const closeClicked = e.target.classList.contains('sholo-close-btn');
|
| 74 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
if (nextClicked) {
|
| 76 |
this.moveNext();
|
| 77 |
} else if (prevClicked) {
|
| 78 |
this.movePrevious();
|
| 79 |
-
}
|
| 80 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 81 |
}
|
| 82 |
}
|
| 83 |
|
|
|
|
| 72 |
const prevClicked = e.target.classList.contains('sholo-prev-btn');
|
| 73 |
const closeClicked = e.target.classList.contains('sholo-close-btn');
|
| 74 |
|
| 75 |
+
if (closeClicked) {
|
| 76 |
+
this.reset();
|
| 77 |
+
return;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
if (nextClicked) {
|
| 81 |
this.moveNext();
|
| 82 |
} else if (prevClicked) {
|
| 83 |
this.movePrevious();
|
| 84 |
+
}
|
| 85 |
+
|
| 86 |
+
// @todo - move to onHighlighted hook and add the check if not visible then do this
|
| 87 |
+
if (this.overlay.highlightedElement) {
|
| 88 |
+
window.setTimeout(() => {
|
| 89 |
+
this.overlay.highlightedElement.bringInView();
|
| 90 |
+
}, 800);
|
| 91 |
}
|
| 92 |
}
|
| 93 |
|
index.html
CHANGED
|
@@ -77,6 +77,8 @@
|
|
| 77 |
|
| 78 |
sholo.defineSteps([
|
| 79 |
{ element: '.section__header' },
|
|
|
|
|
|
|
| 80 |
{ element: '.section__examples' },
|
| 81 |
{ element: '.section__contributing' },
|
| 82 |
]);
|
|
|
|
| 77 |
|
| 78 |
sholo.defineSteps([
|
| 79 |
{ element: '.section__header' },
|
| 80 |
+
{ element: '.section__how' },
|
| 81 |
+
{ element: '.section__purpose' },
|
| 82 |
{ element: '.section__examples' },
|
| 83 |
{ element: '.section__contributing' },
|
| 84 |
]);
|