Skip to content

Commit

Permalink
Extended/added F.scrollIntoView(), F.scrollToTop() and F.scrollToBott…
Browse files Browse the repository at this point in the history
…om()
  • Loading branch information
ygoe committed Jan 5, 2023
1 parent 34a0155 commit 78815cf
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 25 deletions.
1 change: 1 addition & 0 deletions doc/changes.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ <h3 class="no-toc">New features</h3>
<li><code>F.value()</code> function for date/time input fields accepts setting a string value instead of a Date instance</li>
<li>More CSS style support for elements with the <code class="css-class">not-dark</code> class (little tested)</li>
<li>CSS class <code class="css-class">indent</code> for accordion contents</li>
<li>Extended/added <a href="frontfire-core.html#scrollIntoView"><code>F.scrollIntoView()</code></a>, <a href="frontfire-core.html#scrollToTop"><code>F.scrollToTop()</code></a> and <a href="frontfire-core.html#scrollToBottom"><code>F.scrollToBottom()</code></a></li>
</ul>
<h3 class="no-toc">Breaking changes</h3>
<ul>
Expand Down
42 changes: 36 additions & 6 deletions doc/frontfire-core.html
Original file line number Diff line number Diff line change
Expand Up @@ -2204,7 +2204,7 @@ <h3 id="isScrollVisible">isScrollVisible</h3>
Determines whether the first selected element is fully visible in its scrolling parent.
</p>
<p class="see-also">
See also: <a href="#closestScrollable">Frontfire.closestScrollable()</a>, <a href="#scrollIntoView">Frontfire.scrollIntoView()</a>
See also: <a href="#closestScrollable">Frontfire.closestScrollable()</a>, <a href="#scrollIntoView">Frontfire.scrollIntoView()</a>, <a href="#scrollToTop">Frontfire.scrollToTop()</a>, <a href="#scrollToBottom">Frontfire.scrollToBottom()</a>
</p>
</div>

Expand All @@ -2213,29 +2213,59 @@ <h3 id="scrollIntoView">scrollIntoView</h3>
<ul>
<li><code>scrollIntoView()</code> → this</li>
<li><code>scrollIntoView(margin)</code> → this</li>
<li><code>scrollIntoView(margin, smooth)</code> → this</li>
<li><code>scrollIntoView(margin, smooth, recursive)</code> → this</li>
<li><code>scrollIntoView([marginTop, marginBottom])</code> → this</li>
<li><code>scrollIntoView([marginTop, marginBottom], smooth)</code> → this</li>
<li><code>scrollIntoView([marginTop, marginBottom], smooth, recursive)</code> → this</li>
</ul>
<p>
Scrolls the first selected element into view in its scrolling parent, if it is not already fully visible.
If the element does not fit in the view height, it is aligned at the top edge.
If a margin is specified, the parent is scrolled further to keep the margin around the element visible.
If the smooth parameter is true, the scrolling animates smoothly instead of an instant scroll.
If the recursive parameter is set to true, parent scroll containers are also brought into view of their respective parents, up to the window.
</p>
<p class="see-also">
See also: <a href="#isScrollVisible">Frontfire.isScrollVisible()</a>
See also: <a href="#scrollToTop">Frontfire.scrollToTop()</a>, <a href="#scrollToBottom">Frontfire.scrollToBottom()</a>, <a href="#isScrollVisible">Frontfire.isScrollVisible()</a>
</p>
</div>

<div class="member">
<h3 id="scrollToBottom">scrollToBottom</h3>
<ul>
<li><code>scrollToBottom()</code> → this</li>
<li><code>scrollToBottom(bottomMargin)</code> → this</li>
<li><code>scrollToBottom(bottomMargin, smooth)</code> → this</li>
<li><code>scrollToBottom(bottomMargin, smooth, recursive)</code> → this</li>
</ul>
<p>
Scrolls the first selected element to the bottom of its scrolling parent.
If a margin is specified, the parent is scrolled further to keep the margin below the element visible.
If the smooth parameter is true, the scrolling animates smoothly instead of an instant scroll.
If the recursive parameter is set to true, parent scroll containers are also brought to the bottom of their respective parents, up to the window.
</p>
<p class="see-also">
See also: <a href="#scrollToTop">Frontfire.scrollToTop()</a>, <a href="#scrollIntoView">Frontfire.scrollIntoView()</a>, <a href="#isScrollVisible">Frontfire.isScrollVisible()</a>
</p>
</div>

<div class="member">
<h3 id="scrollToTop">scrollToTop</h3>
<ul>
<li><code>scrollToTop()</code> → this</li>
<li><code>scrollToTop(offset)</code> → this</li>
<li><code>scrollToTop(offset, smooth)</code> → this</li>
<li><code>scrollToTop(topMargin)</code> → this</li>
<li><code>scrollToTop(topMargin, smooth)</code> → this</li>
<li><code>scrollToTop(topMargin, smooth, recursive)</code> → this</li>
</ul>
<p>
Scrolls the page so that the first selected element is at the top.
The offset specifies the vertical offset in pixels to scroll the element to, instead of the top of the viewport.
Scrolls the first selected element to the top of its scrolling parent.
If a margin is specified, the parent is scrolled further to keep the margin above the element visible.
If the smooth parameter is true, the scrolling animates smoothly instead of an instant scroll.
If the recursive parameter is set to true, parent scroll containers are also brought to the top of their respective parents, up to the window.
</p>
<p class="see-also">
See also: <a href="#scrollToBottom">Frontfire.scrollToBottom()</a>, <a href="#scrollIntoView">Frontfire.scrollIntoView()</a>, <a href="#isScrollVisible">Frontfire.isScrollVisible()</a>
</p>
</div>
</section>
Expand Down
72 changes: 53 additions & 19 deletions src/js/frontfire-core.js
Original file line number Diff line number Diff line change
Expand Up @@ -2218,8 +2218,39 @@

// Scrolls the first selected element into view in its scrolling parent, if it is not already
// fully visible. If the element does not fit in the view height, it is aligned at the top edge.
Frontfire_prototype.scrollIntoView = function (margin) {
// margin: Vertical margin to keep clear (top and bottom as single number or both values in an array), in pixels. (Optional)
// smooth: Indicates whether the scrolling should animate smoothly. (Optional, default: false)
// recursive: Indicates whether scrollable parents are also scrolled into view. (Optional, default: false)
Frontfire_prototype.scrollIntoView = function (margin, smooth, recursive) {
let element = this.first;
if (element)
scrollElement(element, margin, smooth, recursive, "");
return this; // Support chaining
};

// Scrolls the first selected element to the top of its scrolling parent.
// topMargin: Top margin to keep clear, in pixels. (Optional)
// smooth: Indicates whether the scrolling should animate smoothly. (Optional, default: false)
// recursive: Indicates whether scrollable parents are also scrolled to the top. (Optional, default: false)
Frontfire_prototype.scrollToTop = function (topMargin, smooth, recursive) {
let element = this.first;
if (element)
scrollElement(element, topMargin, smooth, recursive, "top");
return this; // Support chaining
};

// Scrolls the first selected element to the bottom of its scrolling parent.
// bottomMargin: Bottom margin to keep clear, in pixels. (Optional)
// smooth: Indicates whether the scrolling should animate smoothly. (Optional, default: false)
// recursive: Indicates whether scrollable parents are also scrolled to the bottom. (Optional, default: false)
Frontfire_prototype.scrollToBottom = function (bottomMargin, smooth, recursive) {
let element = this.first;
if (element)
scrollElement(element, bottomMargin, smooth, recursive, "bottom");
return this; // Support chaining
};

function scrollElement(element, margin, smooth, recursive, position) {
let scrollable = closestScrollable(element.parentElement ?? element);
let top = getRelativeTop(element, scrollable);
// getRelativeTop measures from top of the parent border, scrolling starts at bottom of border
Expand All @@ -2239,28 +2270,31 @@
}

let newScrollTop = scrollable.scrollTop;
if (viewBottom < bottom)
newScrollTop = bottom - scrollable.clientHeight;
if (viewTop > top)
newScrollTop = top;
switch (position) {
case "top":
newScrollTop = top;
break;
case "bottom":
newScrollTop = bottom - scrollable.clientHeight;
break;
default:
if (viewBottom < bottom)
newScrollTop = bottom - scrollable.clientHeight;
if (viewTop > top)
newScrollTop = top;
break;
}
if (newScrollTop !== scrollable.scrollTop)
scrollable.scrollTop = newScrollTop;
return this; // Support chaining
};

// Immediately scrolls the page so that the first selected element is at the top.
// offset: The vertical offset to scroll the element to.
// smooth: Indicates whether the scrolling should animate smoothly. (Optional, default: false)
// TODO: Scroll the closest scrolling parent, not just the entire page
Frontfire_prototype.scrollToTop = function (offset, smooth) {
if (this.length) {
document.documentElement.scrollTo({
top: this.array[0].getBoundingClientRect().top + window.scrollY - (offset || 0),
scrollable.scrollTo({
top: newScrollTop,
behavior: smooth ? "smooth" : "auto"
});

if (recursive && scrollable !== document.documentElement) {
//scrollable.F.scrollIntoView(margin, recursive);
scrollElement(scrollable, margin, smooth, recursive, position);
}
return this; // Support chaining
};
}

function isScrollable(element) {
let hasScrollableContent = element.scrollHeight > element.clientHeight;
Expand Down

0 comments on commit 78815cf

Please sign in to comment.