From 65b898de0c7439d0902cd3205674c5af0b167cf1 Mon Sep 17 00:00:00 2001 From: Dan <39170265+chillenberger@users.noreply.github.com> Date: Fri, 26 Apr 2024 15:29:31 -0600 Subject: [PATCH] Dan docs left nav manage state w js update (#1417) --- .../src/components/cms/index_link/mod.rs | 10 ++ .../components/cms/index_link/template.html | 9 +- .../left_nav/docs/docs_controller.js | 147 ++++++++++++++---- .../navigation/left_nav/docs/template.html | 9 +- 4 files changed, 138 insertions(+), 37 deletions(-) diff --git a/pgml-dashboard/src/components/cms/index_link/mod.rs b/pgml-dashboard/src/components/cms/index_link/mod.rs index 0e4bc74cb..0572dfd47 100644 --- a/pgml-dashboard/src/components/cms/index_link/mod.rs +++ b/pgml-dashboard/src/components/cms/index_link/mod.rs @@ -12,6 +12,7 @@ pub struct IndexLink { pub open: bool, pub active: bool, pub level: i32, + pub id_suffix: String, } impl IndexLink { @@ -25,6 +26,7 @@ impl IndexLink { open: false, active: false, level, + id_suffix: "".to_owned(), } } @@ -70,4 +72,12 @@ impl IndexLink { } self } + + // Adds a suffix to this and all children ids. + // this prevents id collision with multiple naves on one screen + // like d-none for mobile nav + pub fn id_suffix(mut self, id_suffix: &str) -> IndexLink { + self.id_suffix = id_suffix.to_owned(); + self + } } diff --git a/pgml-dashboard/src/components/cms/index_link/template.html b/pgml-dashboard/src/components/cms/index_link/template.html index 19e12008a..a3b77bad0 100644 --- a/pgml-dashboard/src/components/cms/index_link/template.html +++ b/pgml-dashboard/src/components/cms/index_link/template.html @@ -46,7 +46,7 @@ <%- title %>
- expand_more + expand_more
@@ -56,15 +56,16 @@ <%- title %>
- expand_more + expand_more
<% } %> -
+
diff --git a/pgml-dashboard/src/components/navigation/left_nav/docs/docs_controller.js b/pgml-dashboard/src/components/navigation/left_nav/docs/docs_controller.js index 8159f6001..ac5232a32 100644 --- a/pgml-dashboard/src/components/navigation/left_nav/docs/docs_controller.js +++ b/pgml-dashboard/src/components/navigation/left_nav/docs/docs_controller.js @@ -1,69 +1,154 @@ import { Controller } from "@hotwired/stimulus"; export default class extends Controller { - static targets = ["level1Container", "level1Link", "highLevels"]; + static targets = ["level1Container", "level1Link", "highLevels", "leftNav"]; - // After page update we reset scroll position of nave back to where it was + // After page update we reset scroll position of nav back to where it + // was and ensure left nave and window location match. connect() { let nav = document.getElementsByClassName("doc-leftnav"); if (nav.length > 0) { let position = nav[0].getAttribute("data-scroll"); nav[0].scrollTop = position; } + + this.callback = () => { + this.setNavToLocation(); + }; + + document.addEventListener("turbo:load", this.callback); } - // trubo-frame permanent breakes bootstrap data attribute collapse for aria - // so we manually controll collapse - expand(e) { - let aria = e.currentTarget.getAttribute("aria-expanded"); - let id = e.currentTarget.getAttribute("aria-controls"); + // The active tags should always be set to the current page location + setNavToLocation() { + const tag = "a[href='" + window.location.pathname + "']"; + + let link = this.element.querySelectorAll(tag); + if (link.length > 0) { + if ( + link[0].getAttribute("data-navigation-left-nav-docs-target") == + "highLevels" + ) { + this.setHighLevelLeftNav(link[0]); + } else { + this.setLevel1LeftNav(link[0]); + } + } + } - let bsCollapse = bootstrap.Collapse.getOrCreateInstance( - document.getElementById(id), + expandSubmenuIfExists(containerEl) { + const controllerEl = containerEl.querySelector( + "[data-action='click->navigation-left-nav-docs#toggle']", ); + controllerEl ? this.expand(controllerEl) : null; + } + + // Finds all parent submenus this element is in and expands them. Takes + // the element containing the current level + expandAllParents(element) { + let level = element.getAttribute("data-level"); + + this.expandSubmenuIfExists(element); + if (level > 1) { + let next = "div[data-level='" + (parseInt(level) - 1) + "']"; + this.expandAllParents(element.closest(next)); + } + } + + // turbo-frame-permanent breaks bootstrap data attribute collapse for aria + // so we manually control collapse + toggle(event) { + let aria = event.currentTarget.getAttribute("aria-expanded"); + if (aria === "true") { - bsCollapse.hide(); - e.currentTarget.setAttribute("aria-expanded", "false"); + this.collapse(event.currentTarget); } else { + this.expand(event.currentTarget); + } + } + + // Expands the submenu, takes submenu control element. + expand(element) { + let id = element.getAttribute("aria-controls"); + let aria = element.getAttribute("aria-expanded"); + + if (aria === "false") { + let bsCollapse = bootstrap.Collapse.getOrCreateInstance( + document.getElementById(id), + ); bsCollapse.show(); - e.currentTarget.setAttribute("aria-expanded", "true"); + element.setAttribute("aria-expanded", "true"); } } - // Activly manage nav state for level 1 links - onNavigateManageLevel1(e) { + // Collapses the submenu, takes submenu control element. + collapse(element) { + let id = element.getAttribute("aria-controls"); + let aria = element.getAttribute("aria-expanded"); + + if (aria === "true") { + let bsCollapse = bootstrap.Collapse.getOrCreateInstance( + document.getElementById(id), + ); + bsCollapse.hide(); + element.setAttribute("aria-expanded", "false"); + } + } + + // Actively manage nav state for high level links. + setHighLevelLeftNav(element) { this.removeAllActive(); - let container = e.currentTarget.closest("div"); - container.classList.add("active"); + const parentContainer = element.closest('div[data-level="1"]'); + const parentMenu = parentContainer.querySelector(".menu-item"); + const parentLink = parentMenu.querySelector( + ".doc-left-nav-level1-link-container", + ); - e.currentTarget.classList.add("active"); + parentLink.classList.add("active"); + element.classList.add("purple"); + + const container = element.parentElement; + this.expandSubmenuIfExists(container); + + const levelEl = container.closest("div[data-level]"); + this.expandAllParents(levelEl); this.preventScrollOnNav(); } - // Activly manage nav state for high level links - onNavigateManageHighLevels(e) { + // Actively manage nav state for level 1 links + setLevel1LeftNav(element) { this.removeAllActive(); - let container = e.currentTarget.closest('div[data-level="1"]'); - let menu = container.querySelector(".menu-item"); - let link = menu.querySelector(".doc-left-nav-level1-link-container"); + const container = element.closest("div"); + container.classList.add("active"); + + element.classList.add("active"); - link.classList.add("active"); + this.expandSubmenuIfExists(container); - e.currentTarget.classList.add("purple"); + this.preventScrollOnNav(); + } + + // Actions to take when nav link is clicked + // currently just gets the scroll position before state change + onNavigateManageLevel1() { + this.preventScrollOnNav(); + } + // Actions to take when nav link is clicked + // currently just gets the scroll position before state change + onNavigateManageHighLevels() { this.preventScrollOnNav(); } - // trubo-frame permanent scrolles nav to top on navigation so we capture the scrroll position prior + // turbo-frame permanent scrolls nav to top on navigation so we capture the scroll position prior // to updating the page so after we can set the scroll position back to where it was preventScrollOnNav() { - let nav = document.getElementsByClassName("doc-leftnav"); - if (nav.length > 0) { - let position = nav[0].scrollTop; - nav[0].setAttribute("data-scroll", position); + if (this.hasLeftNavTarget) { + let position = this.leftNavTarget.scrollTop; + this.leftNavTarget.setAttribute("data-scroll", position); } } @@ -81,4 +166,8 @@ export default class extends Controller { this.level1LinkTargets[i].classList.remove("active"); } } + + disconnect() { + document.removeEventListener("turbo:load", this.callback); + } } diff --git a/pgml-dashboard/src/components/navigation/left_nav/docs/template.html b/pgml-dashboard/src/components/navigation/left_nav/docs/template.html index 5b0c221d4..15390a368 100644 --- a/pgml-dashboard/src/components/navigation/left_nav/docs/template.html +++ b/pgml-dashboard/src/components/navigation/left_nav/docs/template.html @@ -24,8 +24,8 @@ %> <% if !mobile { %> -
-