From 29765a96d22c68091eadc3cfa29a31390a36c889 Mon Sep 17 00:00:00 2001
From: Naomi Pentrel <5212232+npentrel@users.noreply.github.com>
Date: Thu, 14 Sep 2023 12:56:56 -0400
Subject: [PATCH] DOCS-792: Persist tab selection to local storage (#1825)
---
layouts/shortcodes/tabs.html | 4 +-
static/js/tabpane-persist.js | 109 +++++++++++++++++++++++++++++++++++
2 files changed, 111 insertions(+), 2 deletions(-)
create mode 100644 static/js/tabpane-persist.js
diff --git a/layouts/shortcodes/tabs.html b/layouts/shortcodes/tabs.html
index 4882c4b608..e2505add5c 100644
--- a/layouts/shortcodes/tabs.html
+++ b/layouts/shortcodes/tabs.html
@@ -7,9 +7,9 @@
{{- range $i, $e := $tabs -}}
{{- $id := printf "%s-%d" $tab_set_id $i -}}
{{- if (eq $i 0) -}}
-
{{- trim .name " " -}}
+{{- trim .name " " -}}
{{ else }}
-{{- trim .name " " -}}
+{{- trim .name " " -}}
{{- end -}}
{{- end -}}
diff --git a/static/js/tabpane-persist.js b/static/js/tabpane-persist.js
new file mode 100644
index 0000000000..6256ffe90c
--- /dev/null
+++ b/static/js/tabpane-persist.js
@@ -0,0 +1,109 @@
+// Utilities
+const _tdStoragePersistKey = (tabKey) =>
+ 'td-tp-persist:' + (tabKey || '');
+
+const _tdSupportsLocalStorage = () => typeof Storage !== 'undefined';
+
+// Helpers
+function tdPersistKey(key, value) {
+ // @requires: tdSupportsLocalStorage();
+ console.log("key", key, "value", value);
+ try {
+ if (value) {
+ localStorage.setItem(key, value);
+ } else {
+ localStorage.removeItem(key);
+ }
+ } catch (error) {
+ const action = value ? 'add' : 'remove';
+ console.error(
+ `Docsy tabpane: unable to ${action} localStorage key '${key}': `,
+ error
+ );
+ }
+}
+
+// Retrieve, increment, and store tab-select event count, then returns it.
+function tdGetTabSelectEventCountAndInc() {
+ // @requires: tdSupportsLocalStorage();
+
+ const storedCount = localStorage.getItem('td-tp-persist-count');
+ let numTabSelectEvents = parseInt(storedCount) || 0;
+ numTabSelectEvents++;
+ tdPersistKey('td-tp-persist-count', numTabSelectEvents.toString());
+ return numTabSelectEvents;
+}
+
+// Main functions
+
+function tdActivateTabsWithKey(key) {
+ console.log(key)
+
+ if (!key) return;
+
+ document.querySelectorAll(`.nav-tabs > .nav-item > a[data-td-tp-persist='${key}']`).forEach((element) => {
+ console.log(element)
+ new bootstrap.Tab(element).show();
+ });
+}
+
+function tdPersistActiveTab(activeTabKey) {
+ if (!_tdSupportsLocalStorage()) return;
+
+ tdPersistKey(
+ _tdStoragePersistKey(activeTabKey),
+ tdGetTabSelectEventCountAndInc()
+ );
+ tdActivateTabsWithKey(activeTabKey);
+}
+
+// Handlers
+
+function tdGetAndActivatePersistedTabs(tabs) {
+ // Get unique persistence keys of tabs in this page
+ var keyOfTabsInThisPage = [
+ ...new Set(
+ Array.from(tabs).map((el) => el.getAttribute("data-td-tp-persist"))
+ ),
+ ];
+
+ // Create a list of active tabs with their age:
+ let key_ageList = keyOfTabsInThisPage
+ // Map to [tab-key, last-activated-age]
+ .map((k) => [
+ k,
+ parseInt(localStorage.getItem(_tdStoragePersistKey(k))) || 0,
+ ])
+ // Exclude tabs that have never been activated
+ .filter(([k, v]) => v)
+ // Sort from oldest selected to most recently selected
+ .sort((a, b) => a[1] - b[1]);
+
+ // Activate tabs from the oldest to the newest
+ key_ageList.forEach(([key]) => {
+ tdActivateTabsWithKey(key);
+ });
+
+ return key_ageList;
+}
+
+function tdRegisterTabClickHandler(tabs) {
+ tabs.forEach((tab) => {
+ tab.addEventListener('click', () => {
+ const activeTabKey = tab.getAttribute("data-td-tp-persist");
+ console.log("!!", activeTabKey)
+ tdPersistActiveTab(activeTabKey);
+ tdActivateTabsWithKey(activeTabKey)
+ });
+ });
+}
+
+// Register listeners and activate tabs
+window.addEventListener('DOMContentLoaded', () => {
+ if (!_tdSupportsLocalStorage()) return;
+
+ var allTabsInThisPage = document.querySelectorAll(".nav-tabs > .nav-item > a");
+ console.log(allTabsInThisPage);
+ tdRegisterTabClickHandler(allTabsInThisPage);
+ tdGetAndActivatePersistedTabs(allTabsInThisPage);
+});
\ No newline at end of file