docs: publish channels: main api

This commit is contained in:
github-actions[bot] committed 2026-07-24 19:31:43 +00:00
commit 8ebb84c5ef
10921 files changed
+1871564

No files matched your search

File diff suppressed because one or more lines are too long.
+195
View File
@@ -0,0 +1,195 @@
/*
* 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';
(function () {
function displayToc() {
fetch(pathToRoot + 'navigation.html')
.then((response) => response.text())
.then((tocHTML) => {
renderToc(tocHTML);
updateTocLinks();
collapseTocParts();
expandTocPathToCurrentPage();
restoreTocExpandedState();
restoreTocScrollTop();
});
}
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);
})
}
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");
}
}
});
}
const expandTocPathToCurrentPage = () => {
const tocParts = [...document.querySelectorAll(`.${TOC_PART_CLASS}`)];
const currentPageId = document.getElementById('content')?.getAttribute('pageIds');
if (!currentPageId) {
return;
}
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') {
window.addEventListener('DOMContentLoaded', () => {
displayToc();
initTocScrollListener();
initLogoClickListener();
})
} 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.
+310
View File
@@ -0,0 +1,310 @@
/*
* Copyright 2014-2024 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 sourcesetNotification;
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()
}
if (typeof initTabs === 'function') {
initTabs() // initTabs comes from ui-kit/tabs
}
handleAnchor()
topNavbarOffset = document.getElementById('navigation-wrapper')
darkModeSwitch()
})
const darkModeSwitch = () => {
const localStorageKey = "dokka-dark-mode"
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")
// 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
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")
// 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))
})
}
// 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) // toggleSections comes from ui-kit/tabs
}
}
if (content) {
content.classList.add('anchor-highlight')
highlightedAnchor = content
}
scrollToElementInContent(element)
}
}
}
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 = safeLocalStorage.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 = safeLocalStorage.getItem('inactive-filters')
if (cached) {
let parsed = JSON.parse(cached)
safeLocalStorage.setItem('inactive-filters', JSON.stringify(parsed.concat([sourceset])))
} else {
safeLocalStorage.setItem('inactive-filters', JSON.stringify([sourceset]))
}
}
function removeSourcesetFilterFromCache(sourceset) {
let cached = safeLocalStorage.getItem('inactive-filters')
if (cached) {
let parsed = JSON.parse(cached)
safeLocalStorage.setItem('inactive-filters', JSON.stringify(parsed.filter(p => p !== sourceset)))
}
}
function refreshSourcesetsCache() {
safeLocalStorage.setItem('inactive-filters', JSON.stringify(filteringContext.restrictedDependencies.filter(p => -1 === filteringContext.activeFilters.indexOf(p))))
}
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', "")
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')
}
}
}
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()
}
function refreshNoContentNotification() {
const element = document.getElementsByClassName("main-content")[0]
const filteredMessage = document.querySelector(".filtered-message")
if(filteringContext.activeFilters.length === 0){
element.style.display = "none";
if (!filteredMessage) {
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", "")
f.setAttribute("aria-pressed", "true")
} else {
f.removeAttribute("data-active")
f.removeAttribute("aria-pressed")
}
})
document.querySelectorAll("#filter-section .checkbox--input")
.forEach(f => {
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");
}
})
}
File diff suppressed because one or more lines are too long.
@@ -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
View File
@@ -0,0 +1 @@
sourceset_dependencies = '{":feature:messaging/androidMain":[":feature:messaging/commonMain"],":feature:messaging/commonMain":[],":feature:messaging/jvmMain":[":feature:messaging/commonMain"],":core:network/androidMain":[":core:network/jvmAndroidMain"],":core:network/commonMain":[],":core:network/jvmAndroidMain":[":core:network/commonMain"],":core:network/jvmMain":[":core:network/jvmAndroidMain"],":core:common/androidMain":[":core:common/jvmAndroidMain"],":core:common/commonMain":[],":core:common/jvmAndroidMain":[":core:common/commonMain"],":core:common/jvmMain":[":core:common/jvmAndroidMain"],":core:datastore/androidMain":[":core:datastore/commonMain"],":core:datastore/commonMain":[],":core:datastore/jvmMain":[":core:datastore/commonMain"],":core:di/androidMain":[":core:di/commonMain"],":core:di/commonMain":[],":core:di/jvmMain":[":core:di/commonMain"],":core:repository/androidMain":[":core:repository/commonMain"],":core:repository/commonMain":[],":core:repository/jvmMain":[":core:repository/commonMain"],":core:prefs/androidMain":[":core:prefs/commonMain"],":core:prefs/commonMain":[],":core:prefs/jvmMain":[":core:prefs/commonMain"],":core:takserver/androidMain":[":core:takserver/jvmAndroidMain"],":core:takserver/commonMain":[],":core:takserver/jvmAndroidMain":[":core:takserver/commonMain"],":core:takserver/jvmMain":[":core:takserver/jvmAndroidMain"],":core:model/androidMain":[":core:model/jvmAndroidMain"],":core:model/commonMain":[],":core:model/jvmAndroidMain":[":core:model/commonMain"],":core:model/jvmMain":[":core:model/jvmAndroidMain"],":feature:connections/androidMain":[":feature:connections/commonMain"],":feature:connections/commonMain":[],":feature:connections/jvmMain":[":feature:connections/commonMain"],":feature:widget/release":[],":feature:wifi-provision/androidMain":[":feature:wifi-provision/commonMain"],":feature:wifi-provision/commonMain":[],":feature:wifi-provision/jvmMain":[":feature:wifi-provision/commonMain"],":feature:discovery/androidMain":[":feature:discovery/commonMain"],":feature:discovery/commonMain":[],":feature:discovery/jvmMain":[":feature:discovery/commonMain"],":core:database/androidMain":[":core:database/commonMain"],":core:database/commonMain":[],":core:database/jvmMain":[":core:database/commonMain"],":core:ui/androidMain":[":core:ui/jvmAndroidMain"],":core:ui/commonMain":[],":core:ui/jvmAndroidMain":[":core:ui/commonMain"],":core:ui/jvmMain":[":core:ui/jvmAndroidMain"],":core:nfc/androidMain":[":core:nfc/commonMain"],":core:nfc/commonMain":[],":core:nfc/jvmMain":[":core:nfc/commonMain"],":core:service/androidMain":[":core:service/commonMain"],":core:service/commonMain":[],":core:service/jvmMain":[":core:service/commonMain"],":core:navigation/androidMain":[":core:navigation/commonMain"],":core:navigation/commonMain":[],":core:navigation/jvmMain":[":core:navigation/commonMain"],":feature:map/androidMain":[":feature:map/commonMain"],":feature:map/commonMain":[],":feature:map/jvmMain":[":feature:map/commonMain"],":feature:intro/androidMain":[":feature:intro/commonMain"],":feature:intro/commonMain":[],":feature:intro/jvmMain":[":feature:intro/commonMain"],":feature:firmware/androidMain":[":feature:firmware/commonMain"],":feature:firmware/commonMain":[],":feature:firmware/jvmMain":[":feature:firmware/commonMain"],":feature:node/androidMain":[":feature:node/commonMain"],":feature:node/commonMain":[],":feature:node/jvmMain":[":feature:node/commonMain"],":core:domain/androidMain":[":core:domain/commonMain"],":core:domain/commonMain":[],":core:domain/jvmMain":[":core:domain/commonMain"],":core:ble/androidMain":[":core:ble/commonMain"],":core:ble/commonMain":[],":core:ble/jvmMain":[":core:ble/commonMain"],":feature:docs/androidMain":[":feature:docs/jvmAndroidMain"],":feature:docs/commonMain":[],":feature:docs/jvmAndroidMain":[":feature:docs/commonMain"],":feature:docs/jvmMain":[":feature:docs/jvmAndroidMain"],":feature:settings/androidMain":[":feature:settings/jvmAndroidMain"],":feature:settings/commonMain":[],":feature:settings/jvmAndroidMain":[":feature:settings/commonMain"],":feature:settings/jvmMain":[":feature:settings/jvmAndroidMain"],":core:data/androidMain":[":core:data/jvmAndroidMain"],":core:data/commonMain":[],":core:data/jvmAndroidMain":[":core:data/commonMain"],":core:data/jvmMain":[":core:data/jvmAndroidMain"],":core:testing/androidMain":[":core:testing/commonMain"],":core:testing/commonMain":[],":core:testing/jvmMain":[":core:testing/commonMain"]}'