diff --git a/code/mad-wikijs-customization.js b/code/mad-wikijs-customization.js index 3463365..71eb408 100644 --- a/code/mad-wikijs-customization.js +++ b/code/mad-wikijs-customization.js @@ -1,902 +1 @@ -/***************************************************/ -/* https://github.com/madodig/wikijs-customization */ -/***************************************************/ - - - -/* CUSTOM CLASSES */ -const CM_LNK_ACTIVE = 'mad-cm-lnk-active'; -const CM_LNK_ACTIVE2 = 'mad-cm-lnk-active2'; -const CM_COLLAPSIBLE = 'mad-cm-collapsible'; -const CM_COLLAPSIBLE_ACTIVE = 'mad-cm-collapsible-active'; -const CM_COLLAPSIBLE_INACTIVE = 'mad-cm-collapsible-inactive'; -const CM_SECTION = 'mad-cm-section'; -const CM_SECTION_EXPANDED = 'expanded'; -/* No line numbers class to find */ -const NO_LINE_NUMBERS_CLASS = 'next-codeblock-no-line-numbers'; - -/* VARIABLES */ -var menuItemType; -var headerProcessed = navProcessed = mainProcessed = footerProcessed = false; -var breadcrumbsHidden = false; -var btnToTopProcessed = false; -var btnToTopVisible = false; - -var curPathRel = window.location.pathname; -var curPathAbs = window.location.href; - - -/* Mutation Observer instantiation */ -var mo = new MutationObserver(moCallback); - -/* Mutation Observer configuration object with the listeners configuration */ -/*var moConfig = { attributes: true, childList: true, subtree: true }; */ -var moConfig = { attributes: true, childList: true, subtree: true, characterDataOldValue: true, attributeOldValue: true }; - -/* Target node to be observed */ -var moTarget = document; - -/* SLIDING MENU */ -if ( slidingMenu ) { - /* const icon_pinOff = "mdi-pin-off-outline"; */ - /* const icon_pinOn = "mdi-pin-outline"; */ - /* const icon_menu = "mdi-menu"; // mdi-backburger */ - var icon_pinOff = "mdi-pin-off-outline"; - var icon_pinOn = "mdi-pin-outline"; - var icon_menu = "mdi-menu"; /* mdi-backburger */ - - var pmb = null; - var pmbHolder = null; - - var mb = null; - var mbHolder = null; - var contentHolder = null; - var backToTopHolder = null; - var menuOpening = menuClosing = menuClosed = menuOpened = false; - var pinMenu = getCookie(COOKIE_NAME); if ( pinMenu == "" ) { pinMenu = false; setCookie(COOKIE_NAME, pinMenu, COOKIE_DAYS); } else if ( pinMenu === "false" ) { pinMenu = false; } else { pinMenu = true; } -} else { - var pinMenu = true; -} - -var header, navigation, main, footer; -var btnToTop; -var sideColumn, pageTitle, breadcrumbs, hideSideColumn; -var sideColumnHidden = false; -var mouseLeftEdgeOpensMenu; -var isMouseOverNav = false; -var menuFirstHover = true; - - - - - -/* MAIN */ - - -/*var curUser = getLoggedInUser(); */ - -var mobileDevice = isMobileDevice(); -moStart(); - - - - - -/* FUNCTIONS */ - - -/* Test if the client is a mobile device */ -function isMobileDevice () { - if ( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) { /* true for mobile device */ - return true; - } else { /* false for not mobile device */ - return false; - } -} - - -function fixMobileDeviceNodeValue(node) { - var nodeValue = node.nodeValue; - if ( nodeValue ) { - var parts = nodeValue.split("#"); - if ( parts.length > 1 ) { - if ( isNumeric(parts[1]) ) { - level = parseInt(parts[1]); - var text = nodeValue.replace("#" + parts[1] + "#", ""); - } - } else { var text = nodeValue; } - var parts = text.split("#"); - node.nodeValue = parts[0]; - } -} - - -/* Starting Mutation Observer */ -function moStart() { mo.observe(moTarget, moConfig); } - - -/* Stopping (disconnecting) Mutation Observer */ -function moStop() { mo.disconnect(); } - - -/* Mutation Observer callback function */ -function moCallback( mutations, mutationObserver ) { - - for ( const { addedNodes } of mutations ) { - for ( const n of addedNodes ) { - if ( n.tagName && n.matches('NAV') && n.style && n.style.getPropertyValue('transform') ) { - if ( n.style.removeProperty ) { n.style.removeProperty('transform'); } else { n.style.removeAttribute('transform'); } - } - } - } - - /* Mutations. Object containing mutation records. */ - /* Mutation Record's keys: addedNode, attributeName, attributeNamespace, nextSibling, oldValue, previousSibling, removedNodes, target, type */ - header = document.querySelector("header[data-booted='true']"); - navigation = document.querySelector("nav[data-booted='true']"); - main = document.querySelector("main[data-booted='true']"); - footer = document.querySelector("footer[data-booted='true']"); - /* btnToTop = document.querySelector("button[aria-label='Return to top']"); // Not working with localization because aria-label is language specific */ - btnToTop = document.querySelector("i.mdi-arrow-up"); - - btnToTopVisible = false; - if ( btnToTop ) { /* Retun to top button customization */ - btnToTopVisible = true; - btnToTop = btnToTop.closest("button"); - if ( !pinMenu && btnToTop.style.left != "5px" ) { - btnToTop.style.left = "5px"; - } - } - - if ( header && !headerProcessed ) { /* Header customization */ - customizeHeader(header); - headerProcessed = true; - } - if ( navigation && !navProcessed ) { /* Navigation customization */ - customizeNavigation(navigation); - navProcessed = true; - } - if ( main && !mainProcessed ) { /* Main Content customization */ - customizeMainContent(main); - mainProcessed = true; - } - if ( footer && !footerProcessed ) { /* Footer customization */ - customizeFooter(footer); - footerProcessed = true; - } - - if ( mouseLeftEdgeOpensMenu ) { document.onmousemove = handleMouseMove; } - -} - - -/* Callback executed when HTML header tag was found with data-booted attribute set to true */ -function customizeHeader(header) { - - if ( addSiteTitleNavigation ) { - /* Add navigation Site Title */ - var subHeading = header.querySelector("span.subheading"); - if ( subHeading ) { - subHeading.style.cssText = "cursor: pointer;"; - subHeading.addEventListener('click', function() { window.location = "/"; }); - addSiteTitleNavigation = false; - } - } - -} - - - -/* Callback executed when HTML nav tag was found with data-booted attribute set to true */ -function customizeNavigation(navigation) { - - if ( slidingMenu ) { - if ( navigation.style.removeProperty ) { navigation.style.removeProperty('transform'); } else { navigation.style.removeAttribute('transform'); } - } - - /* COLLAPSIBLE MENU */ - if ( collapsibleMenu ) { - - var menuItems = navigation.querySelector('.__view').children[0].children[1].childNodes; - - if ( mobileDevice ) { - menuItems.forEach( function(item) { - if ( item.childNodes[0] ) { fixMobileDeviceNodeValue(item.childNodes[0]); } - if ( item.childNodes[1] && item.childNodes[1].childNodes[0] ) { fixMobileDeviceNodeValue(item.childNodes[1].childNodes[0]); } - }); - } else { - menuItems.forEach( function(item) { - /* FIRST RUN: Group items in sections and apply styles */ - var next = item.nextElementSibling; - var prev = item.previousElementSibling; - var sectionHeader = item.previousElementSibling; - - menuItemType = getMenuItemType(item); - - if ( menuItemType == "DVD" && hideDivider ) { - item.style.display = "none"; - } else if ( getMenuItemInfo(item, "level") > getMenuItemInfo(sectionHeader, "level") ) { - /* Group items */ - var newSection = groupItems(item); - /* Wrap each item group (menu section) */ - newSection.wrapGroup(CM_SECTION); - sectionHeader.classList.add(CM_COLLAPSIBLE, CM_COLLAPSIBLE_INACTIVE); - - if ( sectionContainsActivePage(newSection) ) { - sectionHeader.classList.toggle(CM_COLLAPSIBLE_INACTIVE); - } else if ( sectionHeader.href == curPathAbs ) { /* Section header is currently active page (opened) */ - sectionHeader.classList.add(CM_LNK_ACTIVE2); - sectionHeader.nextElementSibling.classList.add(CM_SECTION_EXPANDED); - sectionHeader.classList.toggle(CM_COLLAPSIBLE_ACTIVE); - sectionHeader.classList.toggle(CM_COLLAPSIBLE_INACTIVE); - } - - /* Add event listener only if section header is of type header, not if it is a page link to avoid expanding section before navigating to link target */ - if ( getMenuItemType(sectionHeader) == "HDR" ) { sectionHeader.addEventListener('click', (ev) => { const elm = ev.target; sectionState(sectionHeader.nextElementSibling, 'toggle'); }, false); } - - } - - }); - - menuItems.forEach( function(item) { - /* SECOND RUN: When everything's grouped and styled, parse names and header icons (if any) */ - - menuItemType = getMenuItemType(item); - if ( menuItemType == "HDR" ) { - if ( getMenuItemInfo(item, "icon") ) { - headerAppendIcon(item, getMenuItemInfo(item, "icon")); - item.childNodes[1].nodeValue = getMenuItemInfo(item, "text"); - } - item.childNodes[0].nodeValue = getMenuItemInfo(item, "text"); - } else if ( menuItemType == "LNK" ) { - item.childNodes[1].childNodes[0].nodeValue = getMenuItemInfo(item, "text"); - } - }); - } - } - - /* SLIDING MENU */ - if ( !mobileDevice && slidingMenu ) { - - pmbHolder = document.createElement('button'); - pmbHolder.className = "v-btn v-btn--top v-btn--depressed v-btn--fab v-btn--fixed v-btn--left v-btn--round theme--dark v-size--small primary mad-pmb"; - pmbHolder.type = "button"; - pmbHolder.insertAdjacentHTML('afterbegin', ''); - pmb = pmbHolder.querySelector('i'); - - mbHolder = document.createElement('button'); - mbHolder.className = "v-btn v-btn--top v-btn--depressed v-btn--fab v-btn--fixed v-btn--left v-btn--round theme--dark v-size--small primary mb"; - mbHolder.type = "button"; - mbHolder.insertAdjacentHTML('afterbegin', ''); - navigation.parentNode.insertBefore(mbHolder, navigation); - mb = mbHolder.querySelector('i'); - - mbHolder.addEventListener('mouseenter', menuOpen); - addListeners(navigation, "mouseenter mouseleave mouseover", navEvent); - addListeners(pmbHolder, "mouseleave mouseup", pmbEvent); - - /* navigation.classList.add('mad-nav-hidden'); */ - - if ( !pinMenu && isMouseOverNav !== true ) { setTimeout( function() { menuClose()}, 100); } - menuOpening = false; menuOpened = true; - - - if ( pinMenu ) { - pmb.classList.add(icon_pinOff); - menuOpen(); - navigation.classList.add('mad-nav-visible'); - } else { - pmb.classList.add(icon_pinOn); - } - - } - -} - - -/* Callback executed when HTML main tag was found with data-booted attribute set to true */ -function customizeMainContent(main) { - - breadcrumbs = main.querySelector("header"); /* Returns first header tag found */ - if ( removeBreadcrumbs && !breadcrumbsHidden ) { - if ( breadcrumbs ) { - if ( breadcrumbs.nextSibling ) { - breadcrumbs.nextSibling.remove(); /* Removes next