mirror of https://github.com/onweru/compose.git

weru
23.16.2023 52b768452217264386ab76eb37c4d121dea9c0ee
refactor script

Signed-off-by: weru <fromweru@gmail.com>
5 files modified
884 ■■■■ changed files
assets/js/code.js 261 ●●●● patch | view | raw | blame | history
assets/js/functions.js 9 ●●●●● patch | view | raw | blame | history
assets/js/index.js 348 ●●●●● patch | view | raw | blame | history
assets/js/search.js 198 ●●●● patch | view | raw | blame | history
assets/js/variables.js 68 ●●●● 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')
    });
    // mark the code element when there are no lines
    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,120 +74,122 @@
  featureHeading();
}, 50);
function loadActions() {
  (function updateDate() {
    const date = new Date();
    const year = date.getFullYear();
    const yearEl = elem('.year');
    yearEl ? year.innerHTML = year : false;
  })();
function updateDate() {
  const date = new Date();
  const year = date.getFullYear().toString;
  const year_el = elem('.year');
  year_el ? year.textContent = year : false;
}
  (function customizeSidebar(){
    const tocActive = 'toc_active';
    const aside = elem('aside');
    const tocs = elems('nav', aside);
    if(tocs) {
      tocs.forEach(function(toc){
        toc.id = "";
        pushClass(toc, 'toc');
        if(toc.children.length >= 1) {
          const tocItems = Array.from(toc.children[0].children);
function customizeSidebar() {
  const tocActive = 'toc_active';
  const aside = elem('aside');
  const tocs = elems('nav', aside);
  if(tocs) {
    tocs.forEach(function(toc){
      toc.id = "";
      pushClass(toc, 'toc');
      if(toc.children.length >= 1) {
        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){
            pushClass(item, 'toc_item');
            pushClass(item.firstElementChild, 'toc_link');
          });
        }
      });
      const currentToc = elem(`.${tocActive}`);
      if(currentToc) {
        const pageInternalLinks = Array.from(elems('a', currentToc));
        const pageIds = pageInternalLinks.map(function(link){
          return link.hash;
        });
        const linkPositions = pageIds.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]
        });
        window.addEventListener('scroll', function(e) {
          // this.setTimeout(function(){
          let position = window.scrollY;
          let active = closestInt(position, linkPositions);
          activeHeading(active, pageInternalLinks);
          // }, 1500)
        toc_items.forEach(function(item){
          pushClass(item, 'toc_item');
          pushClass(item.firstElementChild, 'toc_link');
        });
      }
    }
    });
    const paragraphs = elems('p');
    if (paragraphs) {
      paragraphs.forEach(function(p){
        const buttons = elems('.button', p);
        if(buttons.length > 1) {
          pushClass(p, 'button_grid');
        }
    const current_toc = elem(`.${tocActive}`);
    if(current_toc) {
      const page_internal_links = Array.from(elems('a', current_toc));
      const page_ids = page_internal_links.map(function(link){
        return link.hash;
      });
      const link_positions = page_ids.map(function(id){
        const heading = document.getElementById(decodeURIComponent(id.replace('#','')));
        const position = heading.offsetTop;
        return position;
      });
      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, link_positions);
        activeHeading(active, page_internal_links);
        // }, 1500)
      });
    }
  })();
  }
  (function markExternalLinks(){
    let links = elems('a');
    if(links) {
      Array.from(links).forEach(function(link){
        let target, rel, blank, noopener, attr1, attr2, url, isExternal;
        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) {
          target = 'target';
          rel = 'rel';
          blank = '_blank';
          noopener = 'noopener';
          attr1 = elemAttribute(link, target);
          attr2 = elemAttribute(link, noopener);
  const paragraphs = elems('p');
  if (paragraphs) {
    paragraphs.forEach(function(p){
      const buttons = elems('.button', p);
      buttons.length > 1 ? pushClass(p, 'button_grid') : false;
    });
  }
}
          attr1 ? false : elemAttribute(link, target, blank);
          attr2 ? false : elemAttribute(link, rel, noopener);
        }
      });
    }
  })();
function markExternalLinks() {
  let links = elems('a');
  if(links) {
    Array.from(links).forEach(function(link){
      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)
      is_external = url.host !== location.host || url.protocol !== location.protocol || url.port !== location.port;
      if(is_external) {
        target = 'target';
        rel = 'rel';
        blank = '_blank';
        noopener = 'noopener';
        attr1 = elemAttribute(link, target);
        attr2 = elemAttribute(link, noopener);
  let headingNodes = [], results, link, icon, current, id,
        attr1 ? false : elemAttribute(link, target, blank);
        attr2 ? false : elemAttribute(link, rel, noopener);
      }
    });
  }
}
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);
      } else {
        elemAttribute(doc, data, storedMode);
      }
    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 {
      if(mode === true) {
        changeMode(isDarkMode)
      } else {
        changeMode(sysMode!==dark);
      }
      mode === true ? changeMode(is_dark_mode) : changeMode(sys_mode!==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;