Skip to content

Commit

Permalink
fix: made tabs work when open via iframe (#3323)
Browse files Browse the repository at this point in the history
  • Loading branch information
berezinant committed Apr 26, 2024
1 parent d6c9fc8 commit 10dd055
Showing 1 changed file with 63 additions and 29 deletions.
@@ -1,6 +1,35 @@
/*
* Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
*/
/** When Dokka is viewed via iframe, local storage could be inaccessible (see https://github.com/Kotlin/dokka/issues/3323)
* This is a wrapper around local storage to prevent errors in such cases
* */
const safeLocalStorage = (() => {
let isLocalStorageAvailable = false;
try {
const testKey = '__testLocalStorageKey__';
localStorage.setItem(testKey, testKey);
localStorage.removeItem(testKey);
isLocalStorageAvailable = true;
} catch (e) {
console.error('Local storage is not available', e);
}

return {
getItem: (key) => {
if (!isLocalStorageAvailable) {
return null;
}
return localStorage.getItem(key);
},
setItem: (key, value) => {
if (!isLocalStorageAvailable) {
return;
}
localStorage.setItem(key, value);
}
};
})();

filteringContext = {
dependencies: {},
Expand Down Expand Up @@ -32,7 +61,7 @@ window.addEventListener('load', () => {

const darkModeSwitch = () => {
const localStorageKey = "dokka-dark-mode"
const storage = localStorage.getItem(localStorageKey)
const storage = safeLocalStorage.getItem(localStorageKey)
const osDarkSchemePreferred = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
const darkModeEnabled = storage ? JSON.parse(storage) : osDarkSchemePreferred
const element = document.getElementById("theme-toggle-button")
Expand All @@ -49,7 +78,7 @@ const darkModeSwitch = () => {
} else {
initPlayground(samplesLightThemeName)
}
localStorage.setItem(localStorageKey, JSON.stringify(darkModeEnabled))
safeLocalStorage.setItem(localStorageKey, JSON.stringify(darkModeEnabled))
})
}

Expand Down Expand Up @@ -139,13 +168,13 @@ function handleAnchor() {
}

let findAnyTab = function (target) {
let result = null
let result = null
document.querySelectorAll('div[tabs-section] > button[data-togglable]')
.forEach(node => {
if(node.getAttribute("data-togglable").split(",").includes(target)) {
result = node
}
})
.forEach(node => {
if (node.getAttribute("data-togglable").split(",").includes(target)) {
result = node
}
})
return result
}

Expand All @@ -157,11 +186,11 @@ function handleAnchor() {
if (element) {
const content = element.nextElementSibling
const contentStyle = window.getComputedStyle(content)
if(contentStyle.display == 'none') {
let tab = findAnyTab(searchForContentTarget(content))
if (tab) {
toggleSections(tab)
}
if (contentStyle.display == 'none') {
let tab = findAnyTab(searchForContentTarget(content))
if (tab) {
toggleSections(tab)
}
}

if (content) {
Expand All @@ -185,13 +214,18 @@ function initTabs() {
const togglable = target ? target.getAttribute("data-togglable") : null;
if (!togglable) return;

localStorage.setItem(localStorageKey, JSON.stringify(togglable));
safeLocalStorage.setItem(localStorageKey, JSON.stringify(togglable));
toggleSections(target);
});
});

const cached = localStorage.getItem(localStorageKey);
if (!cached) return;
let cached = null;
try {
cached = safeLocalStorage.getItem(localStorageKey);
} catch (e) {
console.error('Error reading from local storage', e);
}
console.log('cached tab', cached);

const tab = document.querySelector(
'div[tabs-section] > button[data-togglable="' + JSON.parse(cached) + '"]'
Expand Down Expand Up @@ -227,7 +261,7 @@ function initializeFiltering() {
filteringContext.dependencies[p] = filteringContext.dependencies[p]
.filter(q => -1 !== filteringContext.restrictedDependencies.indexOf(q))
})
let cached = window.localStorage.getItem('inactive-filters')
let cached = safeLocalStorage.getItem('inactive-filters')
if (cached) {
let parsed = JSON.parse(cached)
filteringContext.activeFilters = filteringContext.restrictedDependencies
Expand Down Expand Up @@ -258,20 +292,20 @@ function unfilterSourceset(sourceset) {
}

function addSourcesetFilterToCache(sourceset) {
let cached = localStorage.getItem('inactive-filters')
let cached = safeLocalStorage.getItem('inactive-filters')
if (cached) {
let parsed = JSON.parse(cached)
localStorage.setItem('inactive-filters', JSON.stringify(parsed.concat([sourceset])))
safeLocalStorage.setItem('inactive-filters', JSON.stringify(parsed.concat([sourceset])))
} else {
localStorage.setItem('inactive-filters', JSON.stringify([sourceset]))
safeLocalStorage.setItem('inactive-filters', JSON.stringify([sourceset]))
}
}

function removeSourcesetFilterFromCache(sourceset) {
let cached = localStorage.getItem('inactive-filters')
let cached = safeLocalStorage.getItem('inactive-filters')
if (cached) {
let parsed = JSON.parse(cached)
localStorage.setItem('inactive-filters', JSON.stringify(parsed.filter(p => p != sourceset)))
safeLocalStorage.setItem('inactive-filters', JSON.stringify(parsed.filter(p => p != sourceset)))
}
}

Expand All @@ -291,11 +325,11 @@ function toggleSections(target) {
const activateTabsBody = (containerClass) => {
document.querySelectorAll("." + containerClass + " *[data-togglable]")
.forEach(child => {
if (toggleTargets.includes(child.getAttribute("data-togglable"))) {
child.setAttribute("data-active", "")
} else if(!child.classList.contains("sourceset-dependent-content")) { // data-togglable is used to switch source set as well, ignore it
child.removeAttribute("data-active")
}
if (toggleTargets.includes(child.getAttribute("data-togglable"))) {
child.setAttribute("data-active", "")
} else if (!child.classList.contains("sourceset-dependent-content")) { // data-togglable is used to switch source set as well, ignore it
child.removeAttribute("data-active")
}
})
}
activateTabs("tabs-section")
Expand Down Expand Up @@ -350,7 +384,7 @@ function refreshPlaygroundSamples() {

function refreshNoContentNotification() {
const element = document.getElementsByClassName("main-content")[0]
if(filteringContext.activeFilters.length === 0){
if (filteringContext.activeFilters.length === 0) {
element.style.display = "none";

const appended = document.createElement("div")
Expand All @@ -359,7 +393,7 @@ function refreshNoContentNotification() {
sourcesetNotification = appended
element.parentNode.prepend(appended)
} else {
if(sourcesetNotification) sourcesetNotification.remove()
if (sourcesetNotification) sourcesetNotification.remove()
element.style.display = "block"
}
}
Expand Down

0 comments on commit 10dd055

Please sign in to comment.