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
<% } %>
-
+
<% for child in children.into_iter() { %>
- <%- child.render_once().unwrap() %>
+ <% let child = child.id_suffix(&id_suffix); %>
+ <%- child.render_once().unwrap() %>
<% } %>
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 { %>
-