| assets/js/code.js | ●●●●● patch | view | raw | blame | history | |
| assets/js/functions.js | ●●●●● patch | view | raw | blame | history | |
| assets/js/index.js | ●●●●● patch | view | raw | blame | history | |
| assets/js/search.js | ●●●●● patch | view | raw | blame | history | |
| assets/js/variables.js | ●●●●● patch | view | raw | blame | history |
assets/js/code.js
@@ -1,57 +1,66 @@ const codeActionButtons = [ const snippet_actions = [ { icon: 'copy', id: 'copy', title: 'Copy Code', title: copy_text, show: true }, { icon: 'order', id: 'lines', title: 'Toggle Line Numbers', title: toggle_line_numbers_text, show: true }, { icon: 'carly', id: 'wrap', title: 'Toggle Line Wrap', title: toggle_line_wrap_text, show: false }, { icon: 'expand', id: 'expand', title: 'Toggle code block expand', title: resize_snippet, show: false } ]; const body = elem('body'); const maxLines = codeBlockConfig.maximum; const showLines = codeBlockConfig.show; const copyId = 'panel_copy'; const wrapId = 'panel_wrap'; const linesId = 'panel_lines'; const panelExpand = 'panel_expand'; const panelExpanded = 'panel_expanded'; const panelHide = 'panel_hide'; const panelFrom = 'panel_from'; const panelBox = 'panel_box'; const fullHeight = 'initial'; const highlightWrap = 'highlight_wrap' const highlight = 'highlight'; function addLines(block) { let text = block.textContent; const snippet_fragment = []; if (text.includes('\n') && block.closest('pre') && !block.children.length) { text = text.split('\n'); text.forEach((text_node, index) => { if(text_node.trim().length) { const new_node = ` <span class="line line-flex"> <span class="ln">${index + 1}</span> <span class="cl">${text_node.trim()}</span> </span>`.trim(); // snippet_fragment.push(':;:'); snippet_fragment.push(new_node); block.closest('pre').className = 'chroma'; pushClass(block, 'language-unknown'); block.dataset.lang = not_set; } }); block.innerHTML = snippet_fragment.join('').trim(' '); } } function wrapOrphanedPreElements() { const pres = elems('pre'); Array.from(pres).forEach(function(pre){ const parent = pre.parentNode; const isOrpaned = !containsClass(parent, highlight) ; if(isOrpaned) { const preWrapper = createEl(); preWrapper.className = highlight; const outerWrapper = createEl(); outerWrapper.className = highlightWrap; wrapEl(pre, preWrapper); wrapEl(preWrapper, outerWrapper); const is_orpaned = !containsClass(parent, highlight); if(is_orpaned) { const pre_wrapper = createEl(); pre_wrapper.className = highlight; const outer_wrapper = createEl(); outer_wrapper.className = highlight_wrap; wrapEl(pre, pre_wrapper); wrapEl(pre_wrapper, outer_wrapper); } }) /* @@ -63,8 +72,9 @@ wrapOrphanedPreElements(); function codeBlocks() { const markedCodeBlocks = elems('code'); const blocks = Array.from(markedCodeBlocks).filter(function(block){ const marked_code_blocks = elems('code'); const blocks = Array.from(marked_code_blocks).filter(function(block){ addLines(block); return block.closest("pre") && !Array.from(block.classList).includes('noClass'); }).map(function(block){ return block @@ -74,29 +84,29 @@ function codeBlockFits(block) { // return false if codeblock overflows const blockWidth = block.offsetWidth; const highlightBlockWidth = block.closest(`.${highlight}`).offsetWidth; return blockWidth <= highlightBlockWidth ? true : false; const block_width = block.offsetWidth; const highlight_block_width = block.closest(`.${highlight}`).offsetWidth; return block_width <= highlight_block_width ? true : false; } function maxHeightIsSet(elem) { let maxHeight = elem.style.maxHeight; return maxHeight.includes('px') let max_height = elem.style.maxHeight; return max_height.includes('px') } function restrainCodeBlockHeight(lines) { const lastLine = lines[maxLines-1]; let maxCodeBlockHeight = fullHeight; if(lastLine) { const lastLinePos = lastLine.offsetTop; if(lastLinePos !== 0) { maxCodeBlockHeight = `${lastLinePos}px`; const last_line = lines[max_lines-1]; let max_code_block_height = full_height; if(last_line) { const last_line_pos = last_line.offsetTop; if(last_line_pos !== 0) { max_code_block_height = `${last_line_pos}px`; const codeBlock = lines[0].parentNode; const outerBlock = codeBlock.closest(`.${highlight}`); const isExpanded = containsClass(outerBlock, panelExpanded); if(!isExpanded) { codeBlock.dataset.height = maxCodeBlockHeight; codeBlock.style.maxHeight = maxCodeBlockHeight; const outer_block = codeBlock.closest(`.${highlight}`); const is_expanded = containsClass(outer_block, panel_expanded); if(!is_expanded) { codeBlock.dataset.height = max_code_block_height; codeBlock.style.maxHeight = max_code_block_height; } } } @@ -105,23 +115,23 @@ const blocks = codeBlocks(); function collapseCodeBlock(block) { const lines = elems(lineClass, block); const codeLines = lines.length; if (codeLines > maxLines) { const expandDot = createEl() pushClass(expandDot, panelExpand); pushClass(expandDot, panelFrom); expandDot.title = "Toggle code block expand"; expandDot.textContent = "..."; const outerBlock = block.closest('.highlight'); const lines = elems(line_class, block); const code_lines = lines.length; if (code_lines > max_lines) { const expand_dot = createEl() pushClass(expand_dot, panel_expand); pushClass(expand_dot, panel_from); expand_dot.title = "Toggle snippet"; expand_dot.textContent = "..."; const outer_block = block.closest('.highlight'); window.setTimeout(function(){ const expandIcon = outerBlock.nextElementSibling.lastElementChild; deleteClass(expandIcon, panelHide); const expand_icon = outer_block.nextElementSibling.lastElementChild; deleteClass(expand_icon, panel_hide); }, 150) restrainCodeBlockHeight(lines); const highlightElement = block.parentNode.parentNode; highlightElement.appendChild(expandDot); const highlight_element = block.parentNode.parentNode; highlight_element.appendChild(expand_dot); } } @@ -131,15 +141,15 @@ function actionPanel() { const panel = createEl(); panel.className = panelBox; panel.className = panel_box; codeActionButtons.forEach(function(button) { snippet_actions.forEach(function(button) { // create button const btn = createEl('a'); btn.href = '#'; btn.title = button.title; btn.className = `icon panel_icon panel_${button.id}`; button.show ? false : pushClass(btn, panelHide); button.show ? false : pushClass(btn, panel_hide); // load icon inside button loadSvg(button.icon, btn); // append button on panel @@ -151,10 +161,8 @@ function toggleLineNumbers(elems) { if(elems) { elems.forEach(function (elem, index) { // mark the code element when there are no lines modifyClass(elem, 'pre_nolines') }); elems.forEach(elem => modifyClass(elem, 'pre_nolines')); restrainCodeBlockHeight(elems); } } @@ -166,57 +174,56 @@ restrainCodeBlockHeight(lines); } function copyCode(codeElement) { const codeElementClone = codeElement.cloneNode(true); const copyBtn = codeElement.parentNode.parentNode.querySelector(`.${copyId}`); const originalTitle = copyBtn.title; loadSvg('check', copyBtn); copyBtn.title = 'Code Copied'; function copyCode(code_element) { lineNumbers = elems('.ln', codeElementClone); const copy_btn = code_element.parentNode.parentNode.querySelector(`.${copy_id}`); const original_title = copy_btn.title; loadSvg('check', copy_btn); copy_btn.title = copied_text; // remove line numbers before copying if(lineNumbers.length) { lineNumbers.forEach(function(line){ line.remove(); }); } code_element = code_element.cloneNode(true); const line_numbers = elems('.ln', code_element); line_numbers.length ? line_numbers.forEach(line => line.remove()) : false; // remove leading '$' from all shell snippets let lines = elems('span', code_element); lines.forEach(line => { const text = line.textContent.trim(' '); if(text.indexOf('$') === 0) { line.textContent = line.textContent.replace('$ ', ''); } }) const snippet = code_element.textContent.trim(' '); // copy code copyToClipboard(codeElementClone.textContent); copyToClipboard(snippet); setTimeout(function() { copyBtn.title = originalTitle; loadSvg('copy', copyBtn); copy_btn.title = original_title; loadSvg('copy', copy_btn); }, 2250); } function disableCodeLineNumbers(block){ const lines = elems('.ln', block) toggleLineNumbers(lines); } (function codeActions(){ const blocks = codeBlocks(); const highlightWrapId = highlightWrap; const highlight_wrap_id = highlight_wrap; blocks.forEach(function(block){ // disable line numbers if disabled globally showLines === false ? disableCodeLineNumbers(block) : false; show_lines === false ? toggleLineNumbers(elems('.ln', block)) : false; const highlightElement = block.parentNode.parentNode; const highlight_element = block.parentNode.parentNode; // wrap code block in a div const highlightWrapper = createEl(); highlightWrapper.className = highlightWrapId; const highlight_wrapper = createEl(); highlight_wrapper.className = highlight_wrap_id; wrapEl(highlightElement, highlightWrapper); wrapEl(highlight_element, highlight_wrapper); const panel = actionPanel(); // show wrap icon only if the code block needs wrapping const wrapIcon = elem(`.${wrapId}`, panel); codeBlockFits(block) ? false : deleteClass(wrapIcon, panelHide); const wrap_icon = elem(`.${wrap_id}`, panel); codeBlockFits(block) ? false : deleteClass(wrap_icon, panel_hide); // append buttons highlightWrapper.appendChild(panel); highlight_wrapper.appendChild(panel); }); function isItem(target, id) { @@ -225,71 +232,69 @@ } function showActive(target, targetClass) { const targetElement = target.matches(`.${targetClass}`) ? target : target.closest(`.${targetClass}`); const target_element = target.matches(`.${targetClass}`) ? target : target.closest(`.${targetClass}`); deleteClass(targetElement, active); deleteClass(target_element, active); setTimeout(function() { modifyClass(targetElement, active) modifyClass(target_element, active) }, 50) } doc.addEventListener('click', function(event){ // copy code block const target = event.target; const isCopyIcon = isItem(target, copyId); const isWrapIcon = isItem(target, wrapId); const isLinesIcon = isItem(target, linesId); const isExpandIcon = isItem(target, panelExpand); const isActionable = isCopyIcon || isWrapIcon || isLinesIcon || isExpandIcon; const is_copy_icon = isItem(target, copy_id); const is_wrap_icon = isItem(target, wrap_id); const is_lines_icon = isItem(target, lines_id); const is_expand_icon = isItem(target, panel_expand); const is_actionable = is_copy_icon || is_wrap_icon || is_lines_icon || is_expand_icon; if(isActionable) { if(is_actionable) { event.preventDefault(); showActive(target, 'icon'); const codeElement = target.closest(`.${highlightWrapId}`).firstElementChild.firstElementChild; let lineNumbers = elems('.ln', codeElement); const code_element = target.closest(`.${highlight_wrap_id}`).firstElementChild.firstElementChild; let lineNumbers = elems('.ln', code_element); isWrapIcon ? toggleLineWrap(codeElement) : false; is_wrap_icon ? toggleLineWrap(code_element) : false; is_lines_icon ? toggleLineNumbers(lineNumbers) : false; isLinesIcon ? toggleLineNumbers(lineNumbers) : false; if (isExpandIcon) { let thisCodeBlock = codeElement.firstElementChild; const outerBlock = thisCodeBlock.closest('.highlight'); if(maxHeightIsSet(thisCodeBlock)) { thisCodeBlock.style.maxHeight = fullHeight; if (is_expand_icon) { let this_code_block = code_element.firstElementChild; const outer_block = this_code_block.closest('.highlight'); if(maxHeightIsSet(this_code_block)) { this_code_block.style.maxHeight = full_height; // mark code block as expanded pushClass(outerBlock, panelExpanded) pushClass(outer_block, panel_expanded) } else { thisCodeBlock.style.maxHeight = thisCodeBlock.dataset.height; this_code_block.style.maxHeight = this_code_block.dataset.height; // unmark code block as expanded deleteClass(outerBlock, panelExpanded) deleteClass(outer_block, panel_expanded) } } if(isCopyIcon) copyCode(codeElement); is_copy_icon ? copyCode(code_element) : false; } }); (function addLangLabel() { const shell_based = ['sh', 'shell', 'zsh', 'bash']; const blocks = codeBlocks(); blocks.forEach(block => { let label = block.dataset.lang; const is_shell_based = shell_based.includes(label); if(is_shell_based) { const lines = elems(lineClass, block); const lines = elems(line_class, block); Array.from(lines).forEach(line => { pushClass(line, 'shell'); line = line.lastElementChild; let line_contents = line.textContent.trim(' '); line_contents.indexOf('$') !== 0 ? pushClass(line, 'shell') : false; }); } label = label === 'sh' ? 'shell' : label; if(label !== "fallback") { const labelEl = createEl(); labelEl.textContent = label; pushClass(labelEl, 'lang'); block.closest(`.${highlightWrap}`).appendChild(labelEl); const label_el = createEl(); label_el.textContent = label; pushClass(label_el, 'lang'); block.closest(`.${highlight_wrap}`).appendChild(label_el); } }); })(); assets/js/functions.js
@@ -17,8 +17,7 @@ } function elems(selector, parent = document) { let elems = isObj(parent) ? parent.querySelectorAll(selector) : []; return elems.length ? elems : false; return isObj(parent) ? parent.querySelectorAll(selector) : []; } function pushClass(el, targetClass) { @@ -174,13 +173,13 @@ } function loadSvg(file, parent, path = iconsPath) { const link = new URL(`${path}${file}.svg`, rootURL).href; const link = new URL(`${path}${file}.svg`, root_url).href; fetch(link) .then((response) => { return response.text(); }) .then((data) => { parent.innerHTML = data; .then((svg_data) => { parent.innerHTML = svg_data; }); } assets/js/index.js
@@ -1,46 +1,36 @@ (function calcNavHeight(){ const nav = elem('.nav_header'); const navHeight = nav.offsetHeight + 25; return navHeight; return (elem('.nav_header').offsetHeight + 25); })(); function toggleMenu(event) { const target = event.target; const isToggleControl = target.matches(`.${toggleId}`); const isWithToggleControl = target.closest(`.${toggleId}`); const showInstances = elems(`.${showId}`) ? Array.from(elems(`.${showId}`)) : []; const menuInstance = target.closest(`.${menu}`); const is_toggle_control = target.matches(`.${toggle_id}`); const is_with_toggle_control = target.closest(`.${toggle_id}`); const show_instances = elems(`.${show_id}`) ? Array.from(elems(`.${show_id}`)) : []; const menu_instance = target.closest(`.${menu}`); function showOff(target, self = false) { showInstances.forEach(function(showInstance){ if(!self) { deleteClass(showInstance, showId); } if(showInstance !== target.closest(`.${menu}`)) { deleteClass(showInstance, showId); } show_instances.forEach(function(show_instance){ !self ? deleteClass(show_instance, show_id) : false; show_instance !== target.closest(`.${menu}`) ? deleteClass(show_instance, show_id) : false; }); } if(isToggleControl || isWithToggleControl) { const menu = isWithToggleControl ? isWithToggleControl.parentNode.parentNode : target.parentNode.parentNode; if(is_toggle_control || is_with_toggle_control) { const menu = is_with_toggle_control ? is_with_toggle_control.parentNode.parentNode : target.parentNode.parentNode; event.preventDefault(); modifyClass(menu, showId); modifyClass(menu, show_id); } else { if(!menuInstance) { showOff(target); } else { showOff(target, true); } !menu_instance ? showOff(target) : showOff(target, true); } } (function markInlineCodeTags(){ const codeBlocks = elems('code'); if(codeBlocks) { codeBlocks.forEach(function(codeBlock){ if(!hasClasses(codeBlock)) { codeBlock.children.length ? false : pushClass(codeBlock, 'noClass'); const code_blocks = elems('code'); if(code_blocks) { code_blocks.forEach(function(code_block){ if(!hasClasses(code_block)) { code_block.children.length ? false : pushClass(code_block, 'noClass'); } }); } @@ -48,35 +38,35 @@ function featureHeading(){ // show active heading at top. const linkClass = "section_link"; const titleClass = "section_title"; const link_class = "section_link"; const title_class = "section_title"; const parent = elem(".aside"); if(parent) { let activeHeading = elem(`.${linkClass}.${active}`); activeHeading = activeHeading ? activeHeading : elem(`.${titleClass}.${active}`); let active_heading = elem(`.${link_class}.${active}`); active_heading = active_heading ? active_heading : elem(`.${title_class}.${active}`); parent.scroll({ top: activeHeading.offsetTop, top: active_heading.offsetTop, left: 0, // behavior: 'smooth' }); } } function activeHeading(position, listLinks) { let linksToModify = Object.create(null); linksToModify.active = listLinks.filter(function(link) { function activeHeading(position, list_links) { let links_to_modify = Object.create(null); links_to_modify.active = list_links.filter(function(link) { return containsClass(link, active); })[0]; // activeTocLink ? deleteClass linksToModify.new = listLinks.filter(function(link){ links_to_modify.new = list_links.filter(function(link){ return parseInt(link.dataset.position) === position })[0]; if (linksToModify.active != linksToModify.new) { linksToModify.active ? deleteClass(linksToModify.active, active): false; pushClass(linksToModify.new, active); if (links_to_modify.active != links_to_modify.new) { links_to_modify.active ? deleteClass(links_to_modify.active, active): false; pushClass(links_to_modify.new, active); } }; @@ -84,15 +74,14 @@ featureHeading(); }, 50); function loadActions() { (function updateDate() { function updateDate() { const date = new Date(); const year = date.getFullYear(); const yearEl = elem('.year'); yearEl ? year.innerHTML = year : false; })(); const year = date.getFullYear().toString; const year_el = elem('.year'); year_el ? year.textContent = year : false; } (function customizeSidebar(){ function customizeSidebar() { const tocActive = 'toc_active'; const aside = elem('aside'); const tocs = elems('nav', aside); @@ -101,42 +90,42 @@ toc.id = ""; pushClass(toc, 'toc'); if(toc.children.length >= 1) { const tocItems = Array.from(toc.children[0].children); const toc_items = Array.from(toc.children[0].children); const previousHeading = toc.previousElementSibling; previousHeading.matches(`.${active}`) ? pushClass(toc, tocActive) : false; const previous_heading = toc.previousElementSibling; previous_heading.matches(`.${active}`) ? pushClass(toc, tocActive) : false; tocItems.forEach(function(item){ toc_items.forEach(function(item){ pushClass(item, 'toc_item'); pushClass(item.firstElementChild, 'toc_link'); }); } }); const currentToc = elem(`.${tocActive}`); const current_toc = elem(`.${tocActive}`); if(currentToc) { const pageInternalLinks = Array.from(elems('a', currentToc)); if(current_toc) { const page_internal_links = Array.from(elems('a', current_toc)); const pageIds = pageInternalLinks.map(function(link){ const page_ids = page_internal_links.map(function(link){ return link.hash; }); const linkPositions = pageIds.map(function(id){ const link_positions = page_ids.map(function(id){ const heading = document.getElementById(decodeURIComponent(id.replace('#',''))); const position = heading.offsetTop; return position; }); pageInternalLinks.forEach(function(link, index){ link.dataset.position = linkPositions[index] page_internal_links.forEach(function(link, index){ link.dataset.position = link_positions[index] }); window.addEventListener('scroll', function(e) { // this.setTimeout(function(){ let position = window.scrollY; let active = closestInt(position, linkPositions); activeHeading(active, pageInternalLinks); let active = closestInt(position, link_positions); activeHeading(active, page_internal_links); // }, 1500) }); } @@ -146,22 +135,20 @@ if (paragraphs) { paragraphs.forEach(function(p){ const buttons = elems('.button', p); if(buttons.length > 1) { pushClass(p, 'button_grid'); } buttons.length > 1 ? pushClass(p, 'button_grid') : false; }); } })(); } (function markExternalLinks(){ function markExternalLinks() { let links = elems('a'); if(links) { Array.from(links).forEach(function(link){ let target, rel, blank, noopener, attr1, attr2, url, isExternal; let target, rel, blank, noopener, attr1, attr2, url, is_external; url = new URL(link.href); // definition of same origin: RFC 6454, section 4 (https://tools.ietf.org/html/rfc6454#section-4) isExternal = url.host !== location.host || url.protocol !== location.protocol || url.port !== location.port; if(isExternal) { is_external = url.host !== location.host || url.protocol !== location.protocol || url.port !== location.port; if(is_external) { target = 'target'; rel = 'rel'; blank = '_blank'; @@ -174,30 +161,35 @@ } }); } })(); } let headingNodes = [], results, link, icon, current, id, function loadActions() { updateDate(); customizeSidebar(); markExternalLinks(); let heading_nodes = [], results, link, icon, current, id, tags = ['h2', 'h3', 'h4', 'h5', 'h6']; current = document.URL; tags.forEach(function(tag){ results = document.getElementsByTagName(tag); Array.prototype.push.apply(headingNodes, results); Array.prototype.push.apply(heading_nodes, results); }); function sanitizeURL(url) { // removes any existing id on url const hash = '#'; const positionOfHash = url.indexOf(hash); if(positionOfHash > -1 ) { const id = url.substr(positionOfHash, url.length - 1); const position_of_hash = url.indexOf(hash); if(position_of_hash > -1 ) { const id = url.substr(position_of_hash, url.length - 1); url = url.replace(id, ''); } return url } headingNodes.forEach(function(node){ heading_nodes.forEach(function(node){ link = createEl('a'); icon = createEl('img'); icon.src = '{{ absURL "icons/link.svg" }}'; @@ -212,24 +204,24 @@ }); function copyFeedback(parent) { const copyText = document.createElement('div'); const copy_txt = document.createElement('div'); const yanked = 'link_yanked'; copyText.classList.add(yanked); copyText.innerText = 'Link Copied'; copy_txt.classList.add(yanked); copy_txt.innerText = copied_text; if(!elem(`.${yanked}`, parent)) { const icon = parent.getElementsByTagName('img')[0]; const originalSrc = icon.src; const original_src = icon.src; icon.src = '{{ absURL "icons/check.svg" }}'; parent.appendChild(copyText); parent.appendChild(copy_txt); setTimeout(function() { parent.removeChild(copyText) icon.src = originalSrc; parent.removeChild(copy_txt) icon.src = original_src; }, 2250); } } (function copyHeadingLink() { let deeplink, deeplinks, newLink, parent, target; let deeplink, deeplinks, new_link, parent, target; deeplink = 'link'; deeplinks = elems(`.${deeplink}`); if(deeplinks) { @@ -239,21 +231,14 @@ parent = target.parentNode; if (target && containsClass(target, deeplink) || containsClass(parent, deeplink)) { event.preventDefault(); newLink = target.href != undefined ? target.href : target.parentNode.href; copyToClipboard(newLink); new_link = target.href != undefined ? target.href : target.parentNode.href; copyToClipboard(new_link); target.href != undefined ? copyFeedback(target) : copyFeedback(target.parentNode); } }); } })(); const light = 'light'; const dark = 'dark'; const storageKey = 'colorMode'; const key = '--color-mode'; const data = 'data-mode'; const bank = window.localStorage; function prefersColor(mode){ return `(prefers-color-scheme: ${mode})`; } @@ -267,35 +252,32 @@ } function currentMode() { let acceptableChars = light + dark; acceptableChars = [...acceptableChars]; let acceptable_chars = light + dark; acceptable_chars = [...acceptable_chars]; let mode = getComputedStyle(doc).getPropertyValue(key).replace(/\"/g, '').trim(); mode = [...mode].filter(function(letter){ return acceptableChars.includes(letter); return acceptable_chars.includes(letter); }); return mode.join(''); } /** * @param isDarkMode true means from dark to light, false means from light to dark */ function changeMode(isDarkMode) { if(isDarkMode) { function changeMode(is_dark_mode) { if(is_dark_mode) { bank.setItem(storageKey, light) elemAttribute(doc, data, light); elemAttribute(doc, mode_data, light); } else { bank.setItem(storageKey, dark); elemAttribute(doc, data, dark); elemAttribute(doc, mode_data, dark); } } (function lazy() { function lazyLoadMedia(element) { let mediaItems = elems(element); if(mediaItems) { Array.from(mediaItems).forEach(function(item) { let media_items = elems(element); if(media_items) { Array.from(media_items).forEach(function(item) { item.loading = "lazy"; }); } @@ -308,9 +290,9 @@ const tables = elems('table'); if (tables) { tables.forEach(function(table){ const tableWrapper = createEl(); pushClass(tableWrapper, 'scrollable'); wrapEl(table, tableWrapper); const table_wrapper = createEl(); pushClass(table_wrapper, 'scrollable'); wrapEl(table, table_wrapper); }); } })(); @@ -334,59 +316,41 @@ } function setUserColorMode(mode = false) { const isDarkMode = currentMode() == dark; const storedMode = bank.getItem(storageKey); const sysMode = systemMode(); if(storedMode) { if(mode) { changeMode(isDarkMode); const is_dark_mode = currentMode() == dark; const stored_mode = bank.getItem(storageKey); const sys_mode = systemMode(); if(stored_mode) { mode ? changeMode(is_dark_mode) : elemAttribute(doc, mode_data, stored_mode); } else { elemAttribute(doc, data, storedMode); mode === true ? changeMode(is_dark_mode) : changeMode(sys_mode!==dark); } } else { if(mode === true) { changeMode(isDarkMode) } else { changeMode(sysMode!==dark); } } const userMode = doc.dataset.mode; doc.dataset.systemmode = sysMode; if(userMode) { pickModePicture(userMode,sysMode,mode); } const user_mode = doc.dataset.mode; doc.dataset.systemmode = sys_mode; user_mode ? pickModePicture(user_mode,sys_mode,mode) : false; } setUserColorMode(); doc.addEventListener('click', function(event) { let target = event.target; let modeClass = 'color_choice'; let isModeToggle = containsClass(target, modeClass); if(isModeToggle) { setUserColorMode(true); } let mode_class = 'color_choice'; let is_mode_toggle = containsClass(target, mode_class); is_mode_toggle ? setUserColorMode(true) : false; toggleMenu(event); }); (function backToTop(){ const toTop = elem("#toTop"); window.addEventListener("scroll", function(e) { const lastKnownScrollPosition = window.scrollY; if(lastKnownScrollPosition >= 200) { window.addEventListener("scroll", () => { const last_known_scroll_pos = window.scrollY; if(last_known_scroll_pos >= 200) { toTop.style.display = "flex"; const viewPort = window.innerWidth; const maxBodyWidth = 1240; // if(viewPort > maxBodyWidth) { // toTop.style.right = `${((viewPort - maxBodyWidth) / 2)}px`; // } pushClass(toTop, active); } else { deleteClass(toTop, active); } }); })(); } window.addEventListener('load', loadActions()); assets/js/search.js
@@ -1,56 +1,56 @@ function initializeSearch(index) { let searchKeys = ['title', 'id', 'link', 'body', 'section']; searchKeys = searchKeys.concat(otherSearchableFields); let search_keys = ['title', 'id', 'link', 'body', 'section']; search_keys = search_keys.concat(other_searchable_fields); const searchPageElement = elem('#searchpage'); const search_page_element = elem('#searchpage'); const searchOptions = { const search_options = { ignoreLocation: true, findAllMatches: true, includeScore: true, shouldSort: true, keys: searchKeys, keys: search_keys, threshold: 0.5 }; index = new Fuse(index, searchOptions); index = new Fuse(index, search_options); function minQueryLen(query) { query = query.trim(); const queryIsFloat = parseFloat(query); const minimumQueryLength = queryIsFloat ? 1 : 2; return minimumQueryLength; const query_is_float = parseFloat(query); const min_query_length = query_is_float ? 1 : 2; return min_query_length; } function searchResults(results=[], query="", passive = false) { let resultsFragment = new DocumentFragment(); let showResults = elem('.search_results'); let results_fragment = new DocumentFragment(); let show_results = elem('.search_results'); if(passive) { showResults = searchPageElement; show_results = search_page_element; } emptyEl(showResults); emptyEl(show_results); const queryLen = query.length; const requiredQueryLen = minQueryLen(query); const query_len = query.length; const required_query_len = minQueryLen(query); if(results.length && queryLen >= requiredQueryLen) { let resultsTitle = createEl('h3'); resultsTitle.className = 'search_title'; resultsTitle.innerText = quickLinks; if(results.length && query_len >= required_query_len) { let results_title = createEl('h3'); results_title.className = 'search_title'; results_title.innerText = quick_links; let goBackButton = createEl('button'); goBackButton.textContent = 'Go Back'; goBackButton.className = goBackClass; let go_back_button = createEl('button'); go_back_button.textContent = 'Go Back'; go_back_button.className = go_back_class; if(passive) { resultsTitle.innerText = searchResultsLabel; results_title.innerText = search_results_label; } if(!searchPageElement) { if(!search_page_element) { results = results.slice(0,8); } else { resultsFragment.appendChild(goBackButton); results_fragment.appendChild(go_back_button); results = results.slice(0,12); } resultsFragment.appendChild(resultsTitle); results_fragment.appendChild(results_title); results.forEach(function(result){ let item = createEl('a'); @@ -59,50 +59,50 @@ item.style.order = result.score; if(passive) { pushClass(item, 'passive'); let itemTitle = createEl('h3'); itemTitle.textContent = result.title; item.appendChild(itemTitle); let item_title = createEl('h3'); item_title.textContent = result.title; item.appendChild(item_title); let itemDescription = createEl('p'); let item_description = createEl('p'); // position of first search term instance let queryInstance = result.body.indexOf(query); itemDescription.textContent = `${result.body.substring(queryInstance, queryInstance + 200)}`; item.appendChild(itemDescription); let query_instance = result.body.indexOf(query); item_description.textContent = `${result.body.substring(query_instance, query_instance + 200)}`; item.appendChild(item_description); } else { item.textContent = result.title; } resultsFragment.appendChild(item); results_fragment.appendChild(item); }); } if(queryLen >= requiredQueryLen) { if(query_len >= required_query_len) { if (!results.length) { showResults.innerHTML = `<span class="search_result">${noMatchesFound}</span>`; show_results.innerHTML = `<span class="search_result">${no_matches_found}</span>`; } } else { showResults.innerHTML = `<label for="find" class="search_result">${ queryLen > 1 ? shortSearchQuery : typeToSearch }</label>` show_results.innerHTML = `<label for="find" class="search_result">${ query_len > 1 ? short_search_query : type_to_search }</label>` } showResults.appendChild(resultsFragment); show_results.appendChild(results_fragment); } function search(searchTerm, scope = null, passive = false) { if(searchTerm.length) { let rawResults = index.search(searchTerm); rawResults = rawResults.map(function(result){ function search(search_term, scope = null, passive = false) { if(search_term.length) { let raw_results = index.search(search_term); raw_results = raw_results.map(function(result){ const score = result.score; const resultItem = result.item; resultItem.score = (parseFloat(score) * 50).toFixed(0); return resultItem ; const result_item = result.item; result_item.score = (parseFloat(score) * 50).toFixed(0); return result_item; }) if(scope) { rawResults = rawResults.filter(resultItem => { return resultItem.section == scope; raw_results = raw_results.filter(result_item => { return result_item.section == scope; }); } passive ? searchResults(rawResults, searchTerm, true) : searchResults(rawResults, searchTerm); passive ? searchResults(raw_results, search_term, true) : searchResults(raw_results, search_term); } else { passive ? searchResults([], "", true) : searchResults(); @@ -110,21 +110,21 @@ } function liveSearch() { const searchField = elem(searchFieldClass); const search_field = elem(search_field_class); if (searchField) { const searchScope = searchField.dataset.scope; searchField.addEventListener('input', function() { const searchTerm = searchField.value.trim().toLowerCase(); search(searchTerm, searchScope); if (search_field) { const search_scope = search_field.dataset.scope; search_field.addEventListener('input', function() { const search_term = search_field.value.trim().toLowerCase(); search(search_term, search_scope); }); if(!searchPageElement) { searchField.addEventListener('search', function(){ const searchTerm = searchField.value.trim().toLowerCase(); if(searchTerm.length) { const scopeParameter = searchScope ? `&scope=${searchScope}` : ''; window.location.href = new URL(`search/?query=${searchTerm}${ scopeParameter }`, rootURL).href; if(!search_page_element) { search_field.addEventListener('search', function(){ const search_term = search_field.value.trim().toLowerCase(); if(search_term.length) { const scope_parameter = search_scope ? `&scope=${search_scope}` : ''; window.location.href = new URL(`search/?query=${search_term}${ scope_parameter }`, root_url).href; } }); } @@ -132,67 +132,57 @@ } function findQuery(query = 'query') { const urlParams = new URLSearchParams(window.location.search); if(urlParams.has(query)){ let c = urlParams.get(query); return c; } return ""; const url_params = new URLSearchParams(window.location.search); return url_params.has(query) ? url_params.get(query) : ""; } function passiveSearch() { if(searchPageElement) { const searchTerm = findQuery(); const searchScope = findQuery('scope'); if(search_page_element) { const search_term = findQuery(); const search_scope = findQuery('scope'); // search actively after search page has loaded const searchField = elem(searchFieldClass); const search_field = elem(search_field_class); search(searchTerm, searchScope, true); search(search_term, search_scope, true); if(searchField) { searchField.addEventListener('input', function() { const searchTerm = searchField.value.trim().toLowerCase(); search(searchTerm, true); wrapText(searchTerm, main); if(search_field) { search_field.addEventListener('input', function() { const search_term = search_field.value.trim().toLowerCase(); search(search_term, true); wrapText(search_term, main); }); } } } function hasSearchResults() { const searchResults = elem('.results'); if(searchResults) { const body = searchResults.innerHTML.length; return [searchResults, body]; const search_results = elem('.results'); if(search_results) { const body = search_results.innerHTML.length; return [search_results, body]; } return false } function clearSearchResults() { let searchResults = hasSearchResults(); if(searchResults) { searchResults = searchResults[0]; searchResults.innerHTML = ""; let search_results = hasSearchResults(); if(search_results) { search_results = search_results[0]; search_results.innerHTML = ""; // clear search field const searchField = elem(searchFieldClass); searchField.value = ""; const search_field = elem(search_field_class); search_field.value = ""; } } function onEscape(fn){ window.addEventListener('keydown', function(event){ if(event.code === "Escape") { fn(); } }); window.addEventListener('keydown', event => event.code === "Escape" ? fn() : false); } let main = elem('main'); if(!main) { main = elem('.main'); } main = main ? main : elem('.main'); searchPageElement ? false : liveSearch(); search_page_element ? false : liveSearch(); passiveSearch(); wrapText(findQuery(), main); @@ -201,21 +191,19 @@ window.addEventListener('click', function(event){ const target = event.target; const isSearch = target.closest(searchClass) || target.matches(searchClass); if(!isSearch && !searchPageElement) { clearSearchResults(); } const is_search = target.closest(search_class) || target.matches(search_class); !is_search && !search_page_element ? clearSearchResults() : false; }); } window.addEventListener('load', function() { const pageLanguage = document.documentElement.lang; const searchIndex = `${ pageLanguage === 'en' ? '': pageLanguage}/index.json`; fetch(new URL(searchIndex, rootURL).href) const page_language = document.documentElement.lang; const search_index = `${ page_language === 'en' ? '': page_language}/index.json`; fetch(new URL(search_index, root_url).href) .then(response => response.json()) .then(function(data) { data = data.length ? data : []; initializeSearch(data); .then(function(search_data) { search_data = search_data.length ? search_data : []; initializeSearch(search_data); }) .catch((error) => console.error(error)); }); assets/js/variables.js
@@ -1,34 +1,66 @@ 'use strict'; // global variables; const doc = document.documentElement; const toggleId = 'toggle'; const showId = 'show'; const toggle_id = 'toggle'; const show_id = 'show'; const menu = 'menu'; const active = 'active'; // rootURL must end with '/' for relative URLs to work properly const rootURL = '{{ strings.TrimSuffix "/" .Site.BaseURL }}/'; const searchFieldClass = '.search_field'; const searchClass = '.search'; const goBackClass = 'button_back'; const lineClass = '.line'; // root_url must end with '/' for relative URLs to work properly const root_url = '{{ strings.TrimSuffix "/" .Site.BaseURL }}/'; const search_field_class = '.search_field'; const search_class = '.search'; const go_back_class = 'button_back'; const line_class = '.line'; // config defined values const codeBlockConfig = JSON.parse('{{ partial "functions/getCodeConfig" . }}'); const code_block_config = JSON.parse('{{ partial "functions/getCodeConfig" . }}'); const iconsPath = `{{ partialCached "functions/getIconPath" . }}`; // values defined under config/_default/params.toml let otherSearchableFields = '{{ delimit (default slice site.Params.otherSearchableFields) ", " }}' let other_searchable_fields = '{{ delimit (default slice site.Params.otherSearchableFields) ", " }}' if(otherSearchableFields.length > 2) { otherSearchableFields = otherSearchableFields if(other_searchable_fields.length > 2) { other_searchable_fields = other_searchable_fields .split(",") .map(search_value => search_value.toLowerCase().trim()); } else { otherSearchableFields = []; other_searchable_fields = []; } // defined in i18n / translation files const quickLinks = '{{ T "quick_links" }}'; const searchResultsLabel = '{{ T "search_results_label" }}'; const shortSearchQuery = '{{ T "short_search_query" }}' const typeToSearch = '{{ T "type_to_search" }}'; const noMatchesFound = '{{ T "no_matches" }}'; const quick_links = '{{ T "quick_links" }}'; const search_results_label = '{{ T "search_results_label" }}'; const short_search_query = '{{ T "short_search_query" }}' const type_to_search = '{{ T "type_to_search" }}'; const no_matches_found = '{{ T "no_matches" }}'; const copy_text = '{{ T "copy" }}'; const copied_text = '{{ T "copied" }}'; const toggle_line_numbers_text = '{{ T "toggle_line_numbers" }}'; const toggle_line_wrap_text = '{{ T "toggle_line_wrap" }}'; const resize_snippet = '{{ T "resize_snippet" }}'; const not_set = '{{ T "not_set" }}'; const shell_based = ['sh', 'shell', 'zsh', 'bash']; const body = elem('body'); const max_lines = code_block_config.maximum; const show_lines = code_block_config.show; const copy_id = 'panel_copy'; const wrap_id = 'panel_wrap'; const lines_id = 'panel_lines'; const panel_expand = 'panel_expand'; const panel_expanded = 'panel_expanded'; const panel_box = 'panel_box'; const panel_hide = 'panel_hide'; const panel_from = 'panel_from'; const full_height = 'initial'; const highlight = 'highlight'; const highlight_wrap = 'highlight_wrap' const light = 'light'; const dark = 'dark'; const storageKey = 'colorMode'; const key = '--color-mode'; const mode_data = 'data-mode'; const bank = window.localStorage;