From e9f5da45c0fcfec5f7c150229301904d7915e090 Mon Sep 17 00:00:00 2001 From: Marcin Aman Date: Wed, 7 Oct 2020 13:58:46 +0200 Subject: Make logo replaceable #1339 (#1488) --- .../src/main/resources/dokka/images/logo-text.svg | 6 - .../resources/dokka/scripts/navigation-loader.js | 54 +++++ .../resources/dokka/scripts/navigationLoader.js | 54 ----- .../dokka/scripts/platform-content-handler.js | 256 +++++++++++++++++++++ .../dokka/scripts/platformContentHandler.js | 256 --------------------- .../src/main/resources/dokka/scripts/search.js | 7 - .../main/resources/dokka/styles/logo-styles.css | 3 + .../base/src/main/resources/dokka/styles/style.css | 1 - 8 files changed, 313 insertions(+), 324 deletions(-) delete mode 100755 plugins/base/src/main/resources/dokka/images/logo-text.svg create mode 100644 plugins/base/src/main/resources/dokka/scripts/navigation-loader.js delete mode 100644 plugins/base/src/main/resources/dokka/scripts/navigationLoader.js create mode 100644 plugins/base/src/main/resources/dokka/scripts/platform-content-handler.js delete mode 100644 plugins/base/src/main/resources/dokka/scripts/platformContentHandler.js delete mode 100644 plugins/base/src/main/resources/dokka/scripts/search.js create mode 100644 plugins/base/src/main/resources/dokka/styles/logo-styles.css (limited to 'plugins/base/src/main/resources/dokka') diff --git a/plugins/base/src/main/resources/dokka/images/logo-text.svg b/plugins/base/src/main/resources/dokka/images/logo-text.svg deleted file mode 100755 index 7bf3e6c5..00000000 --- a/plugins/base/src/main/resources/dokka/images/logo-text.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/plugins/base/src/main/resources/dokka/scripts/navigation-loader.js b/plugins/base/src/main/resources/dokka/scripts/navigation-loader.js new file mode 100644 index 00000000..c2f60ec5 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/scripts/navigation-loader.js @@ -0,0 +1,54 @@ +window.addEventListener('load', () => { + fetch(pathToRoot + "navigation.html") + .then(response => response.text()) + .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() + }) + + /* Smooth scrolling support for going to the top of the page */ + document.querySelectorAll('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) + } +}; \ No newline at end of file diff --git a/plugins/base/src/main/resources/dokka/scripts/navigationLoader.js b/plugins/base/src/main/resources/dokka/scripts/navigationLoader.js deleted file mode 100644 index c2f60ec5..00000000 --- a/plugins/base/src/main/resources/dokka/scripts/navigationLoader.js +++ /dev/null @@ -1,54 +0,0 @@ -window.addEventListener('load', () => { - fetch(pathToRoot + "navigation.html") - .then(response => response.text()) - .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() - }) - - /* Smooth scrolling support for going to the top of the page */ - document.querySelectorAll('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) - } -}; \ No newline at end of file diff --git a/plugins/base/src/main/resources/dokka/scripts/platform-content-handler.js b/plugins/base/src/main/resources/dokka/scripts/platform-content-handler.js new file mode 100644 index 00000000..022aca4f --- /dev/null +++ b/plugins/base/src/main/resources/dokka/scripts/platform-content-handler.js @@ -0,0 +1,256 @@ +filteringContext = { + dependencies: {}, + restrictedDependencies: [], + activeFilters: [] +} +let highlightedAnchor; + +window.addEventListener('load', () => { + document.querySelectorAll("div[data-platform-hinted]") + .forEach(elem => elem.addEventListener('click', (event) => togglePlatformDependent(event,elem))) + document.querySelectorAll("div[tabs-section]") + .forEach(elem => elem.addEventListener('click', (event) => toggleSectionsEventHandler(event))) + const filterSection = document.getElementById('filter-section') + if (filterSection) { + filterSection.addEventListener('click', (event) => filterButtonHandler(event)) + initializeFiltering() + } + initTabs() + handleAnchor() + initHidingLeftNavigation() +}) + +const initHidingLeftNavigation = () => { + document.getElementById("leftToggler").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 handleAnchor() { + if(highlightedAnchor){ + highlightedAnchor.classList.remove('anchor-highlight') + highlightedAnchor = null; + } + + let searchForTab = function(element) { + if(element && element.hasAttribute) { + if(element.hasAttribute("data-togglable")) return element; + else return searchForTab(element.parentNode) + } else return null + } + let anchor = window.location.hash + if (anchor != "") { + anchor = anchor.substring(1) + let element = document.querySelector('a[data-name="' + anchor+'"]') + if (element) { + let tab = searchForTab(element) + if (tab) { + toggleSections(tab) + } + const content = element.nextElementSibling + if(content){ + content.classList.add('anchor-highlight') + highlightedAnchor = content + } + element.scrollIntoView({behavior: "smooth"}) + } + } +} + +function initTabs(){ + document.querySelectorAll("div[tabs-section]") + .forEach(element => { + showCorrespondingTabBody(element) + element.addEventListener('click', (event) => toggleSectionsEventHandler(event)) + }) + let cached = localStorage.getItem("active-tab") + if (cached) { + let parsed = JSON.parse(cached) + let tab = document.querySelector('div[tabs-section] > button[data-togglable="' + parsed + '"]') + if(tab) { + toggleSections(tab) + } + } +} + +function showCorrespondingTabBody(element){ + const key = element.querySelector("button[data-active]").getAttribute("data-togglable") + document.querySelector(".tabs-section-body") + .querySelector("div[data-togglable='" + key + "']") + .setAttribute("data-active", "") +} + +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) { + localStorage.setItem('active-tab', JSON.stringify(target.getAttribute("data-togglable"))) + 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") + } + } + } + } + + activateTabs("tabs-section") + activateTabs("tabs-section-body") +} + +function toggleSectionsEventHandler(evt){ + if(!evt.target.getAttribute("data-togglable")) return + toggleSections(evt.target) +} + +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() +} + +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") + } + }) +} + diff --git a/plugins/base/src/main/resources/dokka/scripts/platformContentHandler.js b/plugins/base/src/main/resources/dokka/scripts/platformContentHandler.js deleted file mode 100644 index 022aca4f..00000000 --- a/plugins/base/src/main/resources/dokka/scripts/platformContentHandler.js +++ /dev/null @@ -1,256 +0,0 @@ -filteringContext = { - dependencies: {}, - restrictedDependencies: [], - activeFilters: [] -} -let highlightedAnchor; - -window.addEventListener('load', () => { - document.querySelectorAll("div[data-platform-hinted]") - .forEach(elem => elem.addEventListener('click', (event) => togglePlatformDependent(event,elem))) - document.querySelectorAll("div[tabs-section]") - .forEach(elem => elem.addEventListener('click', (event) => toggleSectionsEventHandler(event))) - const filterSection = document.getElementById('filter-section') - if (filterSection) { - filterSection.addEventListener('click', (event) => filterButtonHandler(event)) - initializeFiltering() - } - initTabs() - handleAnchor() - initHidingLeftNavigation() -}) - -const initHidingLeftNavigation = () => { - document.getElementById("leftToggler").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 handleAnchor() { - if(highlightedAnchor){ - highlightedAnchor.classList.remove('anchor-highlight') - highlightedAnchor = null; - } - - let searchForTab = function(element) { - if(element && element.hasAttribute) { - if(element.hasAttribute("data-togglable")) return element; - else return searchForTab(element.parentNode) - } else return null - } - let anchor = window.location.hash - if (anchor != "") { - anchor = anchor.substring(1) - let element = document.querySelector('a[data-name="' + anchor+'"]') - if (element) { - let tab = searchForTab(element) - if (tab) { - toggleSections(tab) - } - const content = element.nextElementSibling - if(content){ - content.classList.add('anchor-highlight') - highlightedAnchor = content - } - element.scrollIntoView({behavior: "smooth"}) - } - } -} - -function initTabs(){ - document.querySelectorAll("div[tabs-section]") - .forEach(element => { - showCorrespondingTabBody(element) - element.addEventListener('click', (event) => toggleSectionsEventHandler(event)) - }) - let cached = localStorage.getItem("active-tab") - if (cached) { - let parsed = JSON.parse(cached) - let tab = document.querySelector('div[tabs-section] > button[data-togglable="' + parsed + '"]') - if(tab) { - toggleSections(tab) - } - } -} - -function showCorrespondingTabBody(element){ - const key = element.querySelector("button[data-active]").getAttribute("data-togglable") - document.querySelector(".tabs-section-body") - .querySelector("div[data-togglable='" + key + "']") - .setAttribute("data-active", "") -} - -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) { - localStorage.setItem('active-tab', JSON.stringify(target.getAttribute("data-togglable"))) - 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") - } - } - } - } - - activateTabs("tabs-section") - activateTabs("tabs-section-body") -} - -function toggleSectionsEventHandler(evt){ - if(!evt.target.getAttribute("data-togglable")) return - toggleSections(evt.target) -} - -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() -} - -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") - } - }) -} - diff --git a/plugins/base/src/main/resources/dokka/scripts/search.js b/plugins/base/src/main/resources/dokka/scripts/search.js deleted file mode 100644 index 04d88ab5..00000000 --- a/plugins/base/src/main/resources/dokka/scripts/search.js +++ /dev/null @@ -1,7 +0,0 @@ -let query = new URLSearchParams(window.location.search).get("query"); -document.getElementById("searchTitle").innerHTML += '"' + query + '":'; -document.getElementById("searchTable").innerHTML = pages - .filter(el => el.name.toLowerCase().startsWith(query.toLowerCase())) - .reduce((acc, element) => { - return acc + '' + element.name + '' - }, ""); \ No newline at end of file diff --git a/plugins/base/src/main/resources/dokka/styles/logo-styles.css b/plugins/base/src/main/resources/dokka/styles/logo-styles.css new file mode 100644 index 00000000..a3a07d75 --- /dev/null +++ b/plugins/base/src/main/resources/dokka/styles/logo-styles.css @@ -0,0 +1,3 @@ +#logo { + background-image: url(../images/docs_logo.svg); +} \ No newline at end of file diff --git a/plugins/base/src/main/resources/dokka/styles/style.css b/plugins/base/src/main/resources/dokka/styles/style.css index 24fd8fa3..7c1b2803 100644 --- a/plugins/base/src/main/resources/dokka/styles/style.css +++ b/plugins/base/src/main/resources/dokka/styles/style.css @@ -191,7 +191,6 @@ background-size: 125px 26px; border-bottom: 1px solid #DADFE6; background-repeat: no-repeat; - background-image: url(../images/docs_logo.svg); background-origin: content-box; padding-left: 24px; padding-top: 24px; -- cgit