mirror of
https://github.com/InsanusMokrassar/MicroUtils.git
synced 2026-06-26 05:05:01 +00:00
deploy: c793bea0c3
This commit is contained in:
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
|
||||
*/
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
document.querySelectorAll('span.copy-icon').forEach(element => {
|
||||
element.addEventListener('click', (el) => copyElementsContentToClipboard(element));
|
||||
})
|
||||
|
||||
document.querySelectorAll('span.anchor-icon').forEach(element => {
|
||||
element.addEventListener('click', (el) => {
|
||||
if(element.hasAttribute('pointing-to')){
|
||||
const location = hrefWithoutCurrentlyUsedAnchor() + '#' + element.getAttribute('pointing-to')
|
||||
copyTextToClipboard(element, location)
|
||||
}
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
const copyElementsContentToClipboard = (element) => {
|
||||
const selection = window.getSelection();
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(element.parentNode.parentNode);
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
|
||||
copyAndShowPopup(element, () => selection.removeAllRanges())
|
||||
}
|
||||
|
||||
const copyTextToClipboard = (element, text) => {
|
||||
var textarea = document.createElement("textarea");
|
||||
textarea.textContent = text;
|
||||
textarea.style.position = "fixed";
|
||||
document.body.appendChild(textarea);
|
||||
textarea.select();
|
||||
|
||||
copyAndShowPopup(element, () => document.body.removeChild(textarea))
|
||||
}
|
||||
|
||||
const copyAndShowPopup = (element, after) => {
|
||||
try {
|
||||
document.execCommand('copy');
|
||||
element.nextElementSibling.classList.add('active-popup');
|
||||
setTimeout(() => {
|
||||
element.nextElementSibling.classList.remove('active-popup');
|
||||
}, 1200);
|
||||
} catch (e) {
|
||||
console.error('Failed to write to clipboard:', e)
|
||||
}
|
||||
finally {
|
||||
if(after) after()
|
||||
}
|
||||
}
|
||||
|
||||
const hrefWithoutCurrentlyUsedAnchor = () => window.location.href.split('#')[0]
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,95 +1,195 @@
|
||||
/*
|
||||
* Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
|
||||
* Copyright 2014-2025 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
|
||||
*/
|
||||
const TOC_STATE_KEY_PREFIX = 'TOC_STATE::';
|
||||
const TOC_CONTAINER_ID = 'sideMenu';
|
||||
const TOC_SCROLL_CONTAINER_ID = 'leftColumn';
|
||||
const TOC_PART_CLASS = 'toc--part';
|
||||
const TOC_PART_HIDDEN_CLASS = 'toc--part_hidden';
|
||||
const TOC_LINK_CLASS = 'toc--link';
|
||||
const TOC_SKIP_LINK_CLASS = 'toc--skip-link';
|
||||
|
||||
navigationPageText = fetch(pathToRoot + "navigation.html").then(response => response.text())
|
||||
(function () {
|
||||
function displayToc() {
|
||||
fetch(pathToRoot + 'navigation.html')
|
||||
.then((response) => response.text())
|
||||
.then((tocHTML) => {
|
||||
renderToc(tocHTML);
|
||||
updateTocLinks();
|
||||
collapseTocParts();
|
||||
expandTocPathToCurrentPage();
|
||||
restoreTocExpandedState();
|
||||
restoreTocScrollTop();
|
||||
});
|
||||
}
|
||||
|
||||
displayNavigationFromPage = () => {
|
||||
navigationPageText.then(data => {
|
||||
document.getElementById("sideMenu").innerHTML = data;
|
||||
}).then(() => {
|
||||
document.querySelectorAll(".toc--row > a").forEach(link => {
|
||||
link.setAttribute("href", pathToRoot + link.getAttribute("href"));
|
||||
})
|
||||
}).then(() => {
|
||||
document.querySelectorAll(".toc--part").forEach(nav => {
|
||||
if (!nav.classList.contains("toc--part_hidden"))
|
||||
nav.classList.add("toc--part_hidden")
|
||||
})
|
||||
}).then(() => {
|
||||
revealNavigationForCurrentPage()
|
||||
}).then(() => {
|
||||
scrollNavigationToSelectedElement()
|
||||
})
|
||||
document.querySelectorAll('.footer a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
document.querySelector(this.getAttribute('href')).scrollIntoView({
|
||||
behavior: 'smooth'
|
||||
});
|
||||
});
|
||||
function renderToc(tocHTML) {
|
||||
const containerElement = document.getElementById(TOC_CONTAINER_ID);
|
||||
if (containerElement) {
|
||||
containerElement.innerHTML = tocHTML;
|
||||
}
|
||||
}
|
||||
|
||||
function updateTocLinks() {
|
||||
document.querySelectorAll(`.${TOC_LINK_CLASS}`).forEach((tocLink) => {
|
||||
tocLink.setAttribute('href', `${pathToRoot}${tocLink.getAttribute('href')}`);
|
||||
tocLink.addEventListener('keydown', preventScrollBySpaceKey);
|
||||
});
|
||||
}
|
||||
document.querySelectorAll(`.${TOC_SKIP_LINK_CLASS}`).forEach((skipLink) => {
|
||||
skipLink.setAttribute('href', `#main`);
|
||||
skipLink.addEventListener('keydown', preventScrollBySpaceKey);
|
||||
})
|
||||
}
|
||||
|
||||
revealNavigationForCurrentPage = () => {
|
||||
let pageId = document.getElementById("content").attributes["pageIds"].value.toString();
|
||||
let parts = document.querySelectorAll(".toc--part");
|
||||
let found = 0;
|
||||
do {
|
||||
parts.forEach(part => {
|
||||
if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) {
|
||||
found = 1;
|
||||
if (part.classList.contains("toc--part_hidden")) {
|
||||
part.classList.remove("toc--part_hidden");
|
||||
part.setAttribute('data-active', "");
|
||||
}
|
||||
revealParents(part)
|
||||
}
|
||||
});
|
||||
pageId = pageId.substring(0, pageId.lastIndexOf("/"))
|
||||
} while (pageId.indexOf("/") !== -1 && found === 0)
|
||||
};
|
||||
revealParents = (part) => {
|
||||
if (part.classList.contains("toc--part")) {
|
||||
if (part.classList.contains("toc--part_hidden"))
|
||||
part.classList.remove("toc--part_hidden");
|
||||
revealParents(part.parentNode)
|
||||
}
|
||||
};
|
||||
function collapseTocParts() {
|
||||
document.querySelectorAll(`.${TOC_PART_CLASS}`).forEach((tocPart) => {
|
||||
if (!tocPart.classList.contains(TOC_PART_HIDDEN_CLASS)) {
|
||||
tocPart.classList.add(TOC_PART_HIDDEN_CLASS);
|
||||
const tocToggleButton = tocPart.querySelector('button');
|
||||
if (tocToggleButton) {
|
||||
tocToggleButton.setAttribute("aria-expanded", "false");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
scrollNavigationToSelectedElement = () => {
|
||||
let selectedElement = document.querySelector('div.toc--part[data-active]')
|
||||
if (selectedElement == null) { // nothing selected, probably just the main page opened
|
||||
return
|
||||
const expandTocPathToCurrentPage = () => {
|
||||
const tocParts = [...document.querySelectorAll(`.${TOC_PART_CLASS}`)];
|
||||
const currentPageId = document.getElementById('content')?.getAttribute('pageIds');
|
||||
if (!currentPageId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let hasIcon = selectedElement.querySelectorAll(":scope > div.toc--row span.toc--icon").length > 0
|
||||
|
||||
// for an instance enums also have children and are expandable but are not package/module elements
|
||||
let isPackageElement = selectedElement.children.length > 1 && !hasIcon
|
||||
if (isPackageElement) {
|
||||
// if a package is selected or linked, it makes sense to align it to top
|
||||
// so that you can see all the members it contains
|
||||
selectedElement.scrollIntoView(true)
|
||||
} else {
|
||||
// if a member within a package is linked, it makes sense to center it since it,
|
||||
// this should make it easier to look at surrounding members
|
||||
selectedElement.scrollIntoView({
|
||||
behavior: 'auto',
|
||||
block: 'center',
|
||||
inline: 'center'
|
||||
})
|
||||
let isPartFound = false;
|
||||
let currentPageIdPrefix = currentPageId;
|
||||
while (!isPartFound && currentPageIdPrefix !== '') {
|
||||
tocParts.forEach((part) => {
|
||||
const partId = part.getAttribute('pageId');
|
||||
if (!isPartFound && partId?.includes(currentPageIdPrefix)) {
|
||||
isPartFound = true;
|
||||
expandTocPart(part);
|
||||
expandTocPathToParent(part);
|
||||
part.dataset.active = 'true';
|
||||
}
|
||||
});
|
||||
currentPageIdPrefix = currentPageIdPrefix.substring(0, currentPageIdPrefix.lastIndexOf('/'));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
const expandTocPathToParent = (part) => {
|
||||
if (part.classList.contains(TOC_PART_CLASS)) {
|
||||
expandTocPart(part);
|
||||
expandTocPathToParent(part.parentNode);
|
||||
}
|
||||
};
|
||||
|
||||
const expandTocPart = (tocPart) => {
|
||||
if (tocPart.classList.contains(TOC_PART_HIDDEN_CLASS)) {
|
||||
tocPart.classList.remove(TOC_PART_HIDDEN_CLASS);
|
||||
const tocToggleButton = tocPart.querySelector('button');
|
||||
if (tocToggleButton) {
|
||||
tocToggleButton.setAttribute("aria-expanded", "true");
|
||||
}
|
||||
const tocPartId = tocPart.getAttribute('id');
|
||||
safeSessionStorage.setItem(`${TOC_STATE_KEY_PREFIX}${tocPartId}`, 'true');
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Restores the state of the navigation tree from the local storage.
|
||||
* LocalStorage keys are in the format of `TOC_STATE::${id}` where `id` is the id of the part
|
||||
*/
|
||||
const restoreTocExpandedState = () => {
|
||||
const allLocalStorageKeys = safeSessionStorage.getKeys();
|
||||
const tocStateKeys = allLocalStorageKeys.filter((key) => key.startsWith(TOC_STATE_KEY_PREFIX));
|
||||
tocStateKeys.forEach((key) => {
|
||||
const isExpandedTOCPart = safeSessionStorage.getItem(key) === 'true';
|
||||
const tocPartId = key.substring(TOC_STATE_KEY_PREFIX.length);
|
||||
const tocPart = document.querySelector(`.toc--part[id="${tocPartId}"]`);
|
||||
if (tocPart !== null && isExpandedTOCPart) {
|
||||
tocPart.classList.remove(TOC_PART_HIDDEN_CLASS);
|
||||
const tocToggleButton = tocPart.querySelector('button');
|
||||
if (tocToggleButton) {
|
||||
tocToggleButton.setAttribute("aria-expanded", "true");
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
function saveTocScrollTop() {
|
||||
const container = document.getElementById(TOC_SCROLL_CONTAINER_ID);
|
||||
if (container) {
|
||||
const currentScrollTop = container.scrollTop;
|
||||
safeSessionStorage.setItem(`${TOC_STATE_KEY_PREFIX}SCROLL_TOP`, `${currentScrollTop}`);
|
||||
}
|
||||
}
|
||||
|
||||
function restoreTocScrollTop() {
|
||||
const container = document.getElementById(TOC_SCROLL_CONTAINER_ID);
|
||||
if (container) {
|
||||
const storedScrollTop = safeSessionStorage.getItem(`${TOC_STATE_KEY_PREFIX}SCROLL_TOP`);
|
||||
if (storedScrollTop) {
|
||||
container.scrollTop = Number(storedScrollTop);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initTocScrollListener() {
|
||||
const container = document.getElementById(TOC_SCROLL_CONTAINER_ID);
|
||||
if (container) {
|
||||
container.addEventListener('scroll', saveTocScrollTop);
|
||||
}
|
||||
}
|
||||
|
||||
function preventScrollBySpaceKey(event) {
|
||||
if (event.key === ' ') {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
function resetTocState() {
|
||||
const tocKeys = safeSessionStorage.getKeys();
|
||||
tocKeys.forEach((key) => {
|
||||
if (key.startsWith(TOC_STATE_KEY_PREFIX)) {
|
||||
safeSessionStorage.removeItem(key);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function initLogoClickListener() {
|
||||
const logo = document.querySelector('.library-name--link');
|
||||
if (logo) {
|
||||
logo.addEventListener('click', resetTocState);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This is a work-around for safari being IE of our times.
|
||||
It doesn't fire a DOMContentLoaded, presumably because eventListener is added after it wants to do it
|
||||
*/
|
||||
if (document.readyState === 'loading') {
|
||||
if (document.readyState === 'loading') {
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
displayNavigationFromPage()
|
||||
displayToc();
|
||||
initTocScrollListener();
|
||||
initLogoClickListener();
|
||||
})
|
||||
} else {
|
||||
displayNavigationFromPage()
|
||||
} else {
|
||||
displayToc();
|
||||
initTocScrollListener();
|
||||
initLogoClickListener();
|
||||
}
|
||||
})();
|
||||
|
||||
|
||||
function handleTocButtonClick(event, navId) {
|
||||
const tocPart = document.getElementById(navId);
|
||||
if (!tocPart) {
|
||||
return;
|
||||
}
|
||||
tocPart.classList.toggle(TOC_PART_HIDDEN_CLASS);
|
||||
const isExpandedTOCPart = !tocPart.classList.contains(TOC_PART_HIDDEN_CLASS);
|
||||
const button = tocPart.querySelector('button');
|
||||
button?.setAttribute("aria-expanded", `${isExpandedTOCPart}`);
|
||||
safeSessionStorage.setItem(`${TOC_STATE_KEY_PREFIX}${navId}`, `${isExpandedTOCPart}`);
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,35 +1,6 @@
|
||||
/*
|
||||
* 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: {},
|
||||
@@ -38,12 +9,8 @@ filteringContext = {
|
||||
}
|
||||
let highlightedAnchor;
|
||||
let topNavbarOffset;
|
||||
let instances = [];
|
||||
let sourcesetNotification;
|
||||
|
||||
const samplesDarkThemeName = 'darcula'
|
||||
const samplesLightThemeName = 'idea'
|
||||
|
||||
window.addEventListener('load', () => {
|
||||
document.querySelectorAll("div[data-platform-hinted]")
|
||||
.forEach(elem => elem.addEventListener('click', (event) => togglePlatformDependent(event, elem)))
|
||||
@@ -66,7 +33,11 @@ const darkModeSwitch = () => {
|
||||
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")
|
||||
initPlayground(darkModeEnabled ? samplesDarkThemeName : samplesLightThemeName)
|
||||
|
||||
// Notify external scripts about changing dark mode, runnable samples plugin depends on this
|
||||
if (window.onDarkModeChanged) {
|
||||
window.onDarkModeChanged(darkModeEnabled)
|
||||
}
|
||||
|
||||
element.addEventListener('click', () => {
|
||||
const enabledClasses = document.getElementsByTagName("html")[0].classList
|
||||
@@ -74,48 +45,14 @@ const darkModeSwitch = () => {
|
||||
|
||||
//if previously we had saved dark theme then we set it to light as this is what we save in local storage
|
||||
const darkModeEnabled = enabledClasses.contains("theme-dark")
|
||||
if (darkModeEnabled) {
|
||||
initPlayground(samplesDarkThemeName)
|
||||
} else {
|
||||
initPlayground(samplesLightThemeName)
|
||||
// Notify external scripts about changing dark mode, runnable samples plugin depends on this
|
||||
if (window.onDarkModeChanged) {
|
||||
window.onDarkModeChanged(darkModeEnabled)
|
||||
}
|
||||
safeLocalStorage.setItem(localStorageKey, JSON.stringify(darkModeEnabled))
|
||||
})
|
||||
}
|
||||
|
||||
const initPlayground = (theme) => {
|
||||
if (!samplesAreEnabled()) return
|
||||
instances.forEach(instance => instance.destroy())
|
||||
instances = []
|
||||
|
||||
// Manually tag code fragments as not processed by playground since we also manually destroy all of its instances
|
||||
document.querySelectorAll('code.runnablesample').forEach(node => {
|
||||
node.removeAttribute("data-kotlin-playground-initialized");
|
||||
})
|
||||
|
||||
KotlinPlayground('code.runnablesample', {
|
||||
getInstance: playgroundInstance => {
|
||||
instances.push(playgroundInstance)
|
||||
},
|
||||
theme: theme
|
||||
});
|
||||
}
|
||||
|
||||
// We check if type is accessible from the current scope to determine if samples script is present
|
||||
// As an alternative we could extract this samples-specific script to new js file but then we would handle dark mode in 2 separate files which is not ideal
|
||||
const samplesAreEnabled = () => {
|
||||
try {
|
||||
if (typeof KotlinPlayground === 'undefined') {
|
||||
// KotlinPlayground is exported universally as a global variable or as a module
|
||||
// Due to possible interaction with other js scripts KotlinPlayground may not be accessible directly from `window`, so we need an additional check
|
||||
KotlinPlayground = exports.KotlinPlayground;
|
||||
}
|
||||
return typeof KotlinPlayground === 'function';
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
// Hash change is needed in order to allow for linking inside the same page with anchors
|
||||
// If this is not present user is forced to refresh the site in order to use an anchor
|
||||
window.onhashchange = handleAnchor
|
||||
@@ -275,14 +212,18 @@ function togglePlatformDependent(e, container) {
|
||||
for (let bm of child.children) {
|
||||
if (bm === target) {
|
||||
bm.setAttribute('data-active', "")
|
||||
bm.setAttribute('aria-pressed', "true")
|
||||
} else if (bm !== target) {
|
||||
bm.removeAttribute('data-active')
|
||||
bm.removeAttribute('aria-pressed')
|
||||
}
|
||||
}
|
||||
} else if (child.getAttribute('data-togglable') === index) {
|
||||
child.setAttribute('data-active', "")
|
||||
child.setAttribute('aria-pressed', "true")
|
||||
} else {
|
||||
child.removeAttribute('data-active')
|
||||
child.removeAttribute('aria-pressed')
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -299,16 +240,6 @@ function refreshFiltering() {
|
||||
refreshFilterButtons()
|
||||
refreshPlatformTabs()
|
||||
refreshNoContentNotification()
|
||||
refreshPlaygroundSamples()
|
||||
}
|
||||
|
||||
function refreshPlaygroundSamples() {
|
||||
document.querySelectorAll('code.runnablesample').forEach(node => {
|
||||
const playground = node.KotlinPlayground;
|
||||
/* Some samples may be hidden by filter, they have 0px height for visible code area
|
||||
* after rendering. Call this method for re-calculate code area height */
|
||||
playground && playground.view.codemirror.refresh();
|
||||
});
|
||||
}
|
||||
|
||||
function refreshNoContentNotification() {
|
||||
@@ -360,12 +291,20 @@ function refreshFilterButtons() {
|
||||
.forEach(f => {
|
||||
if (filteringContext.activeFilters.indexOf(f.getAttribute("data-filter")) !== -1) {
|
||||
f.setAttribute("data-active", "")
|
||||
f.setAttribute("aria-pressed", "true")
|
||||
} else {
|
||||
f.removeAttribute("data-active")
|
||||
f.removeAttribute("aria-pressed")
|
||||
}
|
||||
})
|
||||
document.querySelectorAll("#filter-section .checkbox--input")
|
||||
.forEach(f => {
|
||||
f.checked = filteringContext.activeFilters.indexOf(f.getAttribute("data-filter")) !== -1;
|
||||
const isChecked = filteringContext.activeFilters.indexOf(f.getAttribute("data-filter")) !== -1
|
||||
f.checked = isChecked;
|
||||
if (isChecked) {
|
||||
f.setAttribute("aria-pressed", "true")
|
||||
} else {
|
||||
f.removeAttribute("aria-pressed");
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
86
scripts/safe-local-storage_blocking.js
Normal file
86
scripts/safe-local-storage_blocking.js
Normal file
@@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Copyright 2014-2025 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);
|
||||
},
|
||||
removeItem: (key) => {
|
||||
if (!isLocalStorageAvailable) {
|
||||
return;
|
||||
}
|
||||
localStorage.removeItem(key);
|
||||
},
|
||||
getKeys: () => {
|
||||
if (!isLocalStorageAvailable) {
|
||||
return [];
|
||||
}
|
||||
return Object.keys(localStorage);
|
||||
},
|
||||
};
|
||||
})();
|
||||
|
||||
/** When Dokka is viewed via iframe, session storage could be inaccessible (see https://github.com/Kotlin/dokka/issues/3323)
|
||||
* This is a wrapper around session storage to prevent errors in such cases
|
||||
* */
|
||||
const safeSessionStorage = (() => {
|
||||
let isSessionStorageAvailable = false;
|
||||
try {
|
||||
const testKey = '__testSessionStorageKey__';
|
||||
sessionStorage.setItem(testKey, testKey);
|
||||
sessionStorage.removeItem(testKey);
|
||||
isSessionStorageAvailable = true;
|
||||
} catch (e) {
|
||||
console.error('Session storage is not available', e);
|
||||
}
|
||||
|
||||
return {
|
||||
getItem: (key) => {
|
||||
if (!isSessionStorageAvailable) {
|
||||
return null;
|
||||
}
|
||||
return sessionStorage.getItem(key);
|
||||
},
|
||||
setItem: (key, value) => {
|
||||
if (!isSessionStorageAvailable) {
|
||||
return;
|
||||
}
|
||||
sessionStorage.setItem(key, value);
|
||||
},
|
||||
removeItem: (key) => {
|
||||
if (!isSessionStorageAvailable) {
|
||||
return;
|
||||
}
|
||||
sessionStorage.removeItem(key);
|
||||
},
|
||||
getKeys: () => {
|
||||
if (!isSessionStorageAvailable) {
|
||||
return [];
|
||||
}
|
||||
return Object.keys(sessionStorage);
|
||||
},
|
||||
};
|
||||
})();
|
||||
@@ -1 +1 @@
|
||||
sourceset_dependencies='{":micro_utils.dokka:dokkaHtml/commonMain":[],":micro_utils.dokka:dokkaHtml/jsMain":[":micro_utils.dokka:dokkaHtml/webMain"],":micro_utils.dokka:dokkaHtml/jvmMain":[":micro_utils.dokka:dokkaHtml/commonMain"],":micro_utils.dokka:dokkaHtml/webMain":[":micro_utils.dokka:dokkaHtml/commonMain"]}'
|
||||
sourceset_dependencies='{":micro_utils.dokka/androidMain":[":micro_utils.dokka/commonMain"],":micro_utils.dokka/androidRelease":[":micro_utils.dokka/commonMain"],":micro_utils.dokka/commonMain":[],":micro_utils.dokka/jsMain":[":micro_utils.dokka/webMain"],":micro_utils.dokka/jvmMain":[":micro_utils.dokka/commonMain"],":micro_utils.dokka/webMain":[":micro_utils.dokka/commonMain"]}'
|
||||
@@ -1,64 +0,0 @@
|
||||
/*
|
||||
* Copyright 2014-2024 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
|
||||
*/
|
||||
|
||||
// helps with some corner cases where <wbr> starts working already,
|
||||
// but the signature is not yet long enough to be wrapped
|
||||
(function() {
|
||||
const leftPaddingPx = 60;
|
||||
|
||||
function createNbspIndent() {
|
||||
let indent = document.createElement("span");
|
||||
indent.append(document.createTextNode("\u00A0\u00A0\u00A0\u00A0"));
|
||||
indent.classList.add("nbsp-indent");
|
||||
return indent;
|
||||
}
|
||||
|
||||
function wrapSymbolParameters(entry) {
|
||||
const symbol = entry.target;
|
||||
const symbolBlockWidth = entry.borderBoxSize && entry.borderBoxSize[0] && entry.borderBoxSize[0].inlineSize;
|
||||
|
||||
// Even though the script is marked as `defer` and we wait for `DOMContentLoaded` event,
|
||||
// or if this block is a part of hidden tab, it can happen that `symbolBlockWidth` is 0,
|
||||
// indicating that something hasn't been loaded.
|
||||
// In this case, observer will be triggered onсe again when it will be ready.
|
||||
if (symbolBlockWidth > 0) {
|
||||
const node = symbol.querySelector(".parameters");
|
||||
|
||||
if (node) {
|
||||
// if window resize happened and observer was triggered, reset previously wrapped
|
||||
// parameters as they might not need wrapping anymore, and check again
|
||||
node.classList.remove("wrapped");
|
||||
node.querySelectorAll(".parameter .nbsp-indent")
|
||||
.forEach(indent => indent.remove());
|
||||
|
||||
const innerTextWidth = Array.from(symbol.children)
|
||||
.filter(it => !it.classList.contains("block")) // blocks are usually on their own (like annotations), so ignore it
|
||||
.map(it => it.getBoundingClientRect().width)
|
||||
.reduce((a, b) => a + b, 0);
|
||||
|
||||
// if signature text takes up more than a single line, wrap params for readability
|
||||
if (innerTextWidth > (symbolBlockWidth - leftPaddingPx)) {
|
||||
node.classList.add("wrapped");
|
||||
node.querySelectorAll(".parameter").forEach(param => {
|
||||
// has to be a physical indent so that it can be copied. styles like
|
||||
// paddings and `::before { content: " " }` do not work for that
|
||||
param.prepend(createNbspIndent());
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const symbolsObserver = new ResizeObserver(entries => entries.forEach(wrapSymbolParameters));
|
||||
|
||||
function initHandlers() {
|
||||
document.querySelectorAll("div.symbol").forEach(symbol => symbolsObserver.observe(symbol));
|
||||
}
|
||||
|
||||
if (document.readyState === 'loading') window.addEventListener('DOMContentLoaded', initHandlers);
|
||||
else initHandlers();
|
||||
|
||||
// ToDo: Add `unobserve` if dokka will be SPA-like:
|
||||
// https://github.com/w3c/csswg-drafts/issues/5155
|
||||
})();
|
||||
Reference in New Issue
Block a user