mirror of
https://github.com/HighCapable/KavaRef.git
synced 2025-09-06 10:45:27 +08:00
Deploy to GitHub pages
This commit is contained in:
56
KDoc/kavaref-core/scripts/clipboard.js
Normal file
56
KDoc/kavaref-core/scripts/clipboard.js
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright 2014-2023 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]
|
||||
|
44
KDoc/kavaref-core/scripts/main.js
Normal file
44
KDoc/kavaref-core/scripts/main.js
Normal file
File diff suppressed because one or more lines are too long
95
KDoc/kavaref-core/scripts/navigation-loader.js
Normal file
95
KDoc/kavaref-core/scripts/navigation-loader.js
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
|
||||
*/
|
||||
|
||||
navigationPageText = fetch(pathToRoot + "navigation.html").then(response => response.text())
|
||||
|
||||
displayNavigationFromPage = () => {
|
||||
navigationPageText.then(data => {
|
||||
document.getElementById("sideMenu").innerHTML = data;
|
||||
}).then(() => {
|
||||
document.querySelectorAll(".overview > a").forEach(link => {
|
||||
link.setAttribute("href", pathToRoot + link.getAttribute("href"));
|
||||
})
|
||||
}).then(() => {
|
||||
document.querySelectorAll(".sideMenuPart").forEach(nav => {
|
||||
if (!nav.classList.contains("hidden"))
|
||||
nav.classList.add("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'
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
revealNavigationForCurrentPage = () => {
|
||||
let pageId = document.getElementById("content").attributes["pageIds"].value.toString();
|
||||
let parts = document.querySelectorAll(".sideMenuPart");
|
||||
let found = 0;
|
||||
do {
|
||||
parts.forEach(part => {
|
||||
if (part.attributes['pageId'].value.indexOf(pageId) !== -1 && found === 0) {
|
||||
found = 1;
|
||||
if (part.classList.contains("hidden")) {
|
||||
part.classList.remove("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("sideMenuPart")) {
|
||||
if (part.classList.contains("hidden"))
|
||||
part.classList.remove("hidden");
|
||||
revealParents(part.parentNode)
|
||||
}
|
||||
};
|
||||
|
||||
scrollNavigationToSelectedElement = () => {
|
||||
let selectedElement = document.querySelector('div.sideMenuPart[data-active]')
|
||||
if (selectedElement == null) { // nothing selected, probably just the main page opened
|
||||
return
|
||||
}
|
||||
|
||||
let hasIcon = selectedElement.querySelectorAll(":scope > div.overview span.nav-icon").length > 0
|
||||
|
||||
// for instance enums also have children and are expandable, but are not package/module elements
|
||||
let isPackageElement = selectedElement.children.length > 1 && !hasIcon
|
||||
if (isPackageElement) {
|
||||
// if 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'
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
This is a work-around for safari being IE of our times.
|
||||
It doesn't fire a DOMContentLoaded, presumabely because eventListener is added after it wants to do it
|
||||
*/
|
||||
if (document.readyState == 'loading') {
|
||||
window.addEventListener('DOMContentLoaded', () => {
|
||||
displayNavigationFromPage()
|
||||
})
|
||||
} else {
|
||||
displayNavigationFromPage()
|
||||
}
|
1
KDoc/kavaref-core/scripts/pages.json
Normal file
1
KDoc/kavaref-core/scripts/pages.json
Normal file
File diff suppressed because one or more lines are too long
400
KDoc/kavaref-core/scripts/platform-content-handler.js
Normal file
400
KDoc/kavaref-core/scripts/platform-content-handler.js
Normal file
@@ -0,0 +1,400 @@
|
||||
/*
|
||||
* Copyright 2014-2023 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license.
|
||||
*/
|
||||
|
||||
filteringContext = {
|
||||
dependencies: {},
|
||||
restrictedDependencies: [],
|
||||
activeFilters: []
|
||||
}
|
||||
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)))
|
||||
const filterSection = document.getElementById('filter-section')
|
||||
if (filterSection) {
|
||||
filterSection.addEventListener('click', (event) => filterButtonHandler(event))
|
||||
initializeFiltering()
|
||||
}
|
||||
initTabs()
|
||||
handleAnchor()
|
||||
initHidingLeftNavigation()
|
||||
topNavbarOffset = document.getElementById('navigation-wrapper')
|
||||
darkModeSwitch()
|
||||
})
|
||||
|
||||
const darkModeSwitch = () => {
|
||||
const localStorageKey = "dokka-dark-mode"
|
||||
const storage = localStorage.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")
|
||||
initPlayground(darkModeEnabled ? samplesDarkThemeName : samplesLightThemeName)
|
||||
|
||||
element.addEventListener('click', () => {
|
||||
const enabledClasses = document.getElementsByTagName("html")[0].classList
|
||||
enabledClasses.toggle("theme-dark")
|
||||
|
||||
//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)
|
||||
}
|
||||
localStorage.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 {
|
||||
KotlinPlayground
|
||||
return true
|
||||
} catch (e) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const initHidingLeftNavigation = () => {
|
||||
document.getElementById("menu-toggle").onclick = function (event) {
|
||||
//Events need to be prevented from bubbling since they will trigger next handler
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
event.stopImmediatePropagation();
|
||||
document.getElementById("leftColumn").classList.toggle("open");
|
||||
}
|
||||
|
||||
document.getElementById("main").onclick = () => {
|
||||
document.getElementById("leftColumn").classList.remove("open");
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
|
||||
function scrollToElementInContent(element) {
|
||||
const scrollToElement = () => document.getElementById('main').scrollTo({
|
||||
top: element.offsetTop - topNavbarOffset.offsetHeight,
|
||||
behavior: "smooth"
|
||||
})
|
||||
|
||||
const waitAndScroll = () => {
|
||||
setTimeout(() => {
|
||||
if (topNavbarOffset) {
|
||||
scrollToElement()
|
||||
} else {
|
||||
waitForScroll()
|
||||
}
|
||||
}, 50)
|
||||
}
|
||||
|
||||
if (topNavbarOffset) {
|
||||
scrollToElement()
|
||||
} else {
|
||||
waitAndScroll()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function handleAnchor() {
|
||||
if (highlightedAnchor) {
|
||||
highlightedAnchor.classList.remove('anchor-highlight')
|
||||
highlightedAnchor = null;
|
||||
}
|
||||
|
||||
let searchForContentTarget = function (element) {
|
||||
if (element && element.hasAttribute) {
|
||||
if (element.hasAttribute("data-togglable")) return element.getAttribute("data-togglable");
|
||||
else return searchForContentTarget(element.parentNode)
|
||||
} else return null
|
||||
}
|
||||
|
||||
let findAnyTab = function (target) {
|
||||
let result = null
|
||||
document.querySelectorAll('div[tabs-section] > button[data-togglable]')
|
||||
.forEach(node => {
|
||||
if(node.getAttribute("data-togglable").split(",").includes(target)) {
|
||||
result = node
|
||||
}
|
||||
})
|
||||
return result
|
||||
}
|
||||
|
||||
let anchor = window.location.hash
|
||||
if (anchor != "") {
|
||||
anchor = anchor.substring(1)
|
||||
let element = document.querySelector('a[data-name="' + anchor + '"]')
|
||||
|
||||
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 (content) {
|
||||
content.classList.add('anchor-highlight')
|
||||
highlightedAnchor = content
|
||||
}
|
||||
|
||||
scrollToElementInContent(element)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initTabs() {
|
||||
// we could have only a single type of data - classlike or package
|
||||
const mainContent = document.querySelector('.main-content');
|
||||
const type = mainContent ? mainContent.getAttribute("data-page-type") : null;
|
||||
const localStorageKey = "active-tab-" + type;
|
||||
document.querySelectorAll('div[tabs-section]').forEach(element => {
|
||||
showCorrespondingTabBody(element);
|
||||
element.addEventListener('click', ({target}) => {
|
||||
const togglable = target ? target.getAttribute("data-togglable") : null;
|
||||
if (!togglable) return;
|
||||
|
||||
localStorage.setItem(localStorageKey, JSON.stringify(togglable));
|
||||
toggleSections(target);
|
||||
});
|
||||
});
|
||||
|
||||
const cached = localStorage.getItem(localStorageKey);
|
||||
if (!cached) return;
|
||||
|
||||
const tab = document.querySelector(
|
||||
'div[tabs-section] > button[data-togglable="' + JSON.parse(cached) + '"]'
|
||||
);
|
||||
if (!tab) return;
|
||||
|
||||
toggleSections(tab);
|
||||
}
|
||||
|
||||
function showCorrespondingTabBody(element) {
|
||||
const buttonWithKey = element.querySelector("button[data-active]")
|
||||
if (buttonWithKey) {
|
||||
toggleSections(buttonWithKey)
|
||||
}
|
||||
}
|
||||
|
||||
function filterButtonHandler(event) {
|
||||
if (event.target.tagName == "BUTTON" && event.target.hasAttribute("data-filter")) {
|
||||
let sourceset = event.target.getAttribute("data-filter")
|
||||
if (filteringContext.activeFilters.indexOf(sourceset) != -1) {
|
||||
filterSourceset(sourceset)
|
||||
} else {
|
||||
unfilterSourceset(sourceset)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function initializeFiltering() {
|
||||
filteringContext.dependencies = JSON.parse(sourceset_dependencies)
|
||||
document.querySelectorAll("#filter-section > button")
|
||||
.forEach(p => filteringContext.restrictedDependencies.push(p.getAttribute("data-filter")))
|
||||
Object.keys(filteringContext.dependencies).forEach(p => {
|
||||
filteringContext.dependencies[p] = filteringContext.dependencies[p]
|
||||
.filter(q => -1 !== filteringContext.restrictedDependencies.indexOf(q))
|
||||
})
|
||||
let cached = window.localStorage.getItem('inactive-filters')
|
||||
if (cached) {
|
||||
let parsed = JSON.parse(cached)
|
||||
filteringContext.activeFilters = filteringContext.restrictedDependencies
|
||||
.filter(q => parsed.indexOf(q) == -1)
|
||||
} else {
|
||||
filteringContext.activeFilters = filteringContext.restrictedDependencies
|
||||
}
|
||||
refreshFiltering()
|
||||
}
|
||||
|
||||
function filterSourceset(sourceset) {
|
||||
filteringContext.activeFilters = filteringContext.activeFilters.filter(p => p != sourceset)
|
||||
refreshFiltering()
|
||||
addSourcesetFilterToCache(sourceset)
|
||||
}
|
||||
|
||||
function unfilterSourceset(sourceset) {
|
||||
if (filteringContext.activeFilters.length == 0) {
|
||||
filteringContext.activeFilters = filteringContext.dependencies[sourceset].concat([sourceset])
|
||||
refreshFiltering()
|
||||
filteringContext.dependencies[sourceset].concat([sourceset]).forEach(p => removeSourcesetFilterFromCache(p))
|
||||
} else {
|
||||
filteringContext.activeFilters.push(sourceset)
|
||||
refreshFiltering()
|
||||
removeSourcesetFilterFromCache(sourceset)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function addSourcesetFilterToCache(sourceset) {
|
||||
let cached = localStorage.getItem('inactive-filters')
|
||||
if (cached) {
|
||||
let parsed = JSON.parse(cached)
|
||||
localStorage.setItem('inactive-filters', JSON.stringify(parsed.concat([sourceset])))
|
||||
} else {
|
||||
localStorage.setItem('inactive-filters', JSON.stringify([sourceset]))
|
||||
}
|
||||
}
|
||||
|
||||
function removeSourcesetFilterFromCache(sourceset) {
|
||||
let cached = localStorage.getItem('inactive-filters')
|
||||
if (cached) {
|
||||
let parsed = JSON.parse(cached)
|
||||
localStorage.setItem('inactive-filters', JSON.stringify(parsed.filter(p => p != sourceset)))
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSections(target) {
|
||||
const activateTabs = (containerClass) => {
|
||||
for (const element of document.getElementsByClassName(containerClass)) {
|
||||
for (const child of element.children) {
|
||||
if (child.getAttribute("data-togglable") === target.getAttribute("data-togglable")) {
|
||||
child.setAttribute("data-active", "")
|
||||
} else {
|
||||
child.removeAttribute("data-active")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
const toggleTargets = target.getAttribute("data-togglable").split(",")
|
||||
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")
|
||||
}
|
||||
})
|
||||
}
|
||||
activateTabs("tabs-section")
|
||||
activateTabsBody("tabs-section-body")
|
||||
}
|
||||
|
||||
function togglePlatformDependent(e, container) {
|
||||
let target = e.target
|
||||
if (target.tagName != 'BUTTON') return;
|
||||
let index = target.getAttribute('data-toggle')
|
||||
|
||||
for (let child of container.children) {
|
||||
if (child.hasAttribute('data-toggle-list')) {
|
||||
for (let bm of child.children) {
|
||||
if (bm == target) {
|
||||
bm.setAttribute('data-active', "")
|
||||
} else if (bm != target) {
|
||||
bm.removeAttribute('data-active')
|
||||
}
|
||||
}
|
||||
} else if (child.getAttribute('data-togglable') == index) {
|
||||
child.setAttribute('data-active', "")
|
||||
} else {
|
||||
child.removeAttribute('data-active')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function refreshFiltering() {
|
||||
let sourcesetList = filteringContext.activeFilters
|
||||
document.querySelectorAll("[data-filterable-set]")
|
||||
.forEach(
|
||||
elem => {
|
||||
let platformList = elem.getAttribute("data-filterable-set").split(',').filter(v => -1 !== sourcesetList.indexOf(v))
|
||||
elem.setAttribute("data-filterable-current", platformList.join(','))
|
||||
}
|
||||
)
|
||||
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() {
|
||||
const element = document.getElementsByClassName("main-content")[0]
|
||||
if(filteringContext.activeFilters.length === 0){
|
||||
element.style.display = "none";
|
||||
|
||||
const appended = document.createElement("div")
|
||||
appended.className = "filtered-message"
|
||||
appended.innerText = "All documentation is filtered, please adjust your source set filters in top-right corner of the screen"
|
||||
sourcesetNotification = appended
|
||||
element.parentNode.prepend(appended)
|
||||
} else {
|
||||
if(sourcesetNotification) sourcesetNotification.remove()
|
||||
element.style.display = "block"
|
||||
}
|
||||
}
|
||||
|
||||
function refreshPlatformTabs() {
|
||||
document.querySelectorAll(".platform-hinted > .platform-bookmarks-row").forEach(
|
||||
p => {
|
||||
let active = false;
|
||||
let firstAvailable = null
|
||||
p.childNodes.forEach(
|
||||
element => {
|
||||
if (element.getAttribute("data-filterable-current") != '') {
|
||||
if (firstAvailable == null) {
|
||||
firstAvailable = element
|
||||
}
|
||||
if (element.hasAttribute("data-active")) {
|
||||
active = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
if (active == false && firstAvailable) {
|
||||
firstAvailable.click()
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
function refreshFilterButtons() {
|
||||
document.querySelectorAll("#filter-section > button")
|
||||
.forEach(f => {
|
||||
if (filteringContext.activeFilters.indexOf(f.getAttribute("data-filter")) != -1) {
|
||||
f.setAttribute("data-active", "")
|
||||
} else {
|
||||
f.removeAttribute("data-active")
|
||||
}
|
||||
})
|
||||
}
|
22
KDoc/kavaref-core/scripts/prism.js
Normal file
22
KDoc/kavaref-core/scripts/prism.js
Normal file
File diff suppressed because one or more lines are too long
1
KDoc/kavaref-core/scripts/sourceset_dependencies.js
Normal file
1
KDoc/kavaref-core/scripts/sourceset_dependencies.js
Normal file
@@ -0,0 +1 @@
|
||||
sourceset_dependencies='{":kavaref-core:dokkaHtml/main":[]}'
|
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* Copyright 2014-2023 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