diff options
author | 0neGal <mail@0negal.com> | 2024-06-19 23:24:47 +0200 |
---|---|---|
committer | 0neGal <mail@0negal.com> | 2024-06-19 23:24:47 +0200 |
commit | fce388b3d9b520459413988e190f916f334a8d48 (patch) | |
tree | 5605416c2550cda739a28f82c8531cf98beff673 | |
parent | a2c165b16a82799422547b124fde72bfbad40f0d (diff) | |
download | Viper-fce388b3d9b520459413988e190f916f334a8d48.tar.gz Viper-fce388b3d9b520459413988e190f916f334a8d48.zip |
proper gamepad element scrolling support
-rw-r--r-- | src/app/css/selection.css | 6 | ||||
-rw-r--r-- | src/app/index.html | 6 | ||||
-rw-r--r-- | src/app/js/navigate.js | 112 |
3 files changed, 116 insertions, 8 deletions
diff --git a/src/app/css/selection.css b/src/app/css/selection.css index 04e1d5d..5b7d647 100644 --- a/src/app/css/selection.css +++ b/src/app/css/selection.css @@ -3,7 +3,7 @@ transition: 0.15s ease-in-out; transition-property: - opacity, border-radius, + opacity, border-radius, background, transform, width, height, top, left; position: fixed; @@ -13,6 +13,10 @@ border-radius: calc(var(--padding) / 2); } +:has(.active-selection.scroll-selection) #selection { + background: rgba(255, 255, 255, 0.2); +} + #selection.keyboard-selecting, #selection.controller-selecting { transform: scale(1.1); diff --git a/src/app/index.html b/src/app/index.html index 40b64a0..1f9f443 100644 --- a/src/app/index.html +++ b/src/app/index.html @@ -228,7 +228,7 @@ </button> </div> - <webview></webview> + <webview class="scroll-selection"></webview> </div> <nav class="gamesContainer"> @@ -252,7 +252,7 @@ <a id="setpath" href="#" onclick="gamepath.set()" class="disable-when-installing">%%gui.setpath%%</a> </div> </div> - <div id="vpReleaseNotes" class="hidden section"></div> + <div id="vpReleaseNotes" class="scroll-selection hidden section"></div> <div id="vpInfo" class="hidden section"> <h2>%%viper.info.links%%</h2> <ul> @@ -312,7 +312,7 @@ </div> </div> </div> - <div id="nsRelease" class="hidden section"></div> + <div id="nsRelease" class="scroll-selection hidden section"></div> </div> </div> diff --git a/src/app/js/navigate.js b/src/app/js/navigate.js index d9744fa..9f2a19f 100644 --- a/src/app/js/navigate.js +++ b/src/app/js/navigate.js @@ -115,7 +115,8 @@ navigate.get_els = (div) => { "button", "select", "textarea", - "[onclick]" + "[onclick]", + ".scroll-selection" ])] // this'll contain a filtered list of `els` @@ -129,13 +130,31 @@ navigate.get_els = (div) => { "#overlay", ".no-navigate", "button.visual", + ".scroll-selection", ".popup:not(.shown)" ] + // ignore, even if `.closest()` matches, if its just matching on + // itself instead of a different element + let ignore_closest_self = [ + ".scroll-selection" + ] + // check if `els[i].closest()` matches on any of the elements // inside of `ignore_closest` for (let ii = 0; ii < ignore_closest.length; ii++) { - if (els[i].closest(ignore_closest[ii])) { + let closest = els[i].closest(ignore_closest[ii]); + + // check if `.closest()` matches, but not on itself + if (closest) { + // ignore if `closest` is just `els[i]` and the selector + // is inside `ignore_closest_self` + if (closest == els[i] && + ignore_closest_self.includes(ignore_closest[ii])) { + + continue; + } + // it matches continue filter; } @@ -221,7 +240,7 @@ navigate.default_selection = () => { // this navigates `#selection` in the direction of `direction` // this can be: up, down, left and right -navigate.move = (direction) => { +navigate.move = async (direction) => { // get the `.active-selection` if there is one let active = document.querySelector(".active-selection"); @@ -238,6 +257,91 @@ navigate.move = (direction) => { } } + // is the active selection one that should be scrollable? + if (active.classList.contains("scroll-selection")) { + // scroll the respective `direction` if `active` has any more + // scroll left in that direction + + // short hand to easily scroll in `direction` by `amount` with + // smooth scrolling enabled + let scroll = (direction, amount) => { + // update the `#selection` element + navigate.selection(); + + // scroll inside `<webview>` if the active selection is one + if (active.tagName == "WEBVIEW") { + active.executeJavaScript(` + document.scrollingElement.scrollBy({ + behavior: "smooth", + ${direction}: ${amount} + }) + `) + + return; + } + + active.scrollBy({ + behavior: "smooth", + [direction]: amount + }) + } + + // get values needed for determining if we should scroll the + // active selection, and by how much + let scroll_el = { + top: active.scrollTop, + left: active.scrollLeft, + width: active.scrollWidth, + height: active.scrollHeight, + bounds: { + width: active.clientWidth, + height: active.clientWidth + } + } + + // get `scroll_el` from inside a `<webview>` if the active + // selection is one + if (active.tagName == "WEBVIEW") { + scroll_el = await active.executeJavaScript(`(() => { + return { + top: document.scrollingElement.scrollTop, + left: document.scrollingElement.scrollLeft, + width: document.scrollingElement.scrollWidth, + height: document.scrollingElement.scrollHeight, + bounds: { + width: document.scrollingElement.clientWidth, + height: document.scrollingElement.clientHeight + } + } + })()`) + } + + // decrease to increase scroll length, and in reverse + let scroll_scale = 2; + + if (direction == "up" && scroll_el.top > 0) { + return scroll("top", -scroll_el.bounds.height / scroll_scale); + } + + if (direction == "down" && + scroll_el.top <= scroll_el.height && + scroll_el.height != scroll_el.bounds.height) { + + return scroll("top", scroll_el.bounds.height / scroll_scale); + } + + if (direction == "left" && scroll_el.left > 0) { + return scroll("left", -width / scroll_scale); + } + + if (direction == "right" && + scroll_el.left <= scroll_el.width && + scroll_el.width != scroll_el.bounds.width) { + + return scroll("left", scroll_el.bounds.width / scroll_scale); + } + } + // attempt to get the element in the `direction` requested let move_to_el = navigate.get_relative_el(active, direction); @@ -269,7 +373,7 @@ navigate.move = (direction) => { // these elements cant be scrolled let no_scroll_parents = [ ".el .text", - ".gamesContainer" + ".gamesContainer", ] // run through unscrollable parent elements |