let expiryTabBuffer = 1800000; // Create variables let localStorageTabPrefix = "tab-menu-data"; let categoriesTabPrefix = "tab-menu-category"; let sectionsTabPrefix = "tab-menu-section"; let articleTabPrefix = "tab-menu-article"; let currentTabItemClass = "current-item"; let currentTabItemParentClass = "current-item-parent"; let mainTabParent = null; // Fetch data from url async function fetchDataFromUrl(url, dataField){ let returnData = {}; let response = await fetch(url); let responseJson = await response.json(); responseJson[dataField].map(dataSingle=>{ returnData[dataSingle.id] = dataSingle; }); if (responseJson.next_page) { let nextPage = await fetchDataFromUrl(responseJson.next_page,dataField); return {...returnData,...nextPage}; } else { return returnData; } } // Setting all retrieved data from URL async function setRequiredData(locale = 'en-us'){ let categoriesPromise = fetchDataFromUrl(`/api/v2/help_center/${locale}/categories`,'categories'); let sectionsPromise = fetchDataFromUrl(`/api/v2/help_center/${locale}/sections`,'sections'); // let articlesPromise = fetchDataFromUrl(`/api/v2/help_center/${locale}/articles`,'articles'); let [categories,sections] = await Promise.all([categoriesPromise,sectionsPromise]).catch(err=>{ console.error("Error occured in fetching data",err); }); let subSections = {}; let subSubSections = {}; let subSubSubSections = {}; let subSubSubSubSections = {}; for (let [key, value] of Object.entries(sections)) { if(value.parent_section_id){ subSections[value.id] = value; delete sections[key]; } } for (let [key, value] of Object.entries(subSections)) { if(value.parent_section_id && subSections[value.parent_section_id]){ subSubSections[value.id] = value; delete subSections[key]; } } for (let [key, value] of Object.entries(subSubSections)) { if(value.parent_section_id && subSubSections[value.parent_section_id]){ subSubSubSections[value.id] = value; delete subSubSections[key]; } } for (let [key, value] of Object.entries(subSubSubSections)) { if(value.parent_section_id && subSubSubSections[value.parent_section_id]){ subSubSubSubSections[value.id] = value; delete subSubSubSections[key]; } } let now = new Date(); let storageData = { categories, sections, subSections, subSubSections, subSubSubSections, subSubSubSubSections, expiry : now.getTime() + expiryTabBuffer } localStorage.setItem(`${localStorageTabPrefix}-${locale}`, JSON.stringify(storageData)); return storageData; } // Function for getting URL data and return its type and ID function fetchCurrentUrlData(){ let returnData = { type : null, id : null }; let pathArray = window.location.pathname.split("/"); pathArray = pathArray.slice(3); if(pathArray[0] && pathArray[1]){ // Get current page ID to mark the active element let currentId = document.getElementById('current-id') if (currentId) { currentId = currentId.dataset.id } else { currentId = parseInt(pathArray[1].replace(/(^\d+)/i,'$1')) } returnData.type = pathArray[0]; returnData.id = currentId; } return returnData; } // Function for getting breadcrumb data and return its type and ID function fetchCurrentBreadcrumbData() { let breadcrumb = document.querySelector('.sub-nav ol.breadcrumbs') if (breadcrumb) { let returnData = {} let pathElement = breadcrumb.querySelector('li:last-child') let pathUrl = pathElement.querySelector('a').href let pathArray = pathUrl.split("/"); pathArray = pathArray.slice(5) if (pathArray[0] && pathArray[1]) { let pathType = pathArray[0] switch (pathType) { case "categories": pathType = "category" break; case "sections": pathType = "section" } returnData.type = pathType; returnData.id = parseInt(pathArray[1].replace(/(^\d+)/i,'$1')) } return returnData; } } function setRequiredLi(urlData, locale) { let prefix = null; // set prefix from URL if(urlData.type == 'categories'){ prefix = categoriesTabPrefix; } else if(urlData.type == 'sections'){ prefix = sectionsTabPrefix; } else if (urlData.type == 'articles'){ prefix = articleTabPrefix; } if(prefix){ let currentItem = document.getElementById(`${prefix}-link-${urlData.id}`); // Check if current item are fetched from API or not if(currentItem){ // If present, add current-item class to element currentItem.classList.add(currentTabItemClass); let currentItemParent; while(currentItemParent = currentItem.parentNode.closest("li")){ currentItem = currentItemParent currentItem.classList.add(currentTabItemParentClass); } } if (prefix == articleTabPrefix || prefix == sectionsTabPrefix) { let breadcrumbData = fetchCurrentBreadcrumbData() // Get current sidebar parent list from breadcrumb let currentSidebar = document.getElementById(`menu-tab-${breadcrumbData.type}-link-${breadcrumbData.id}`) if (currentSidebar) { let currentSidebarParent; while (currentSidebarParent = currentSidebar.parentNode.closest("li")) { currentSidebar = currentSidebarParent // Fetch article if current item or article parent not present if (!currentItem) { if (!currentSidebar.classList.contains('tab-menu-category')) { fetchTabArticleOnClick(currentSidebar, locale) } } else if (currentSidebar.querySelector('.tab-menu-article') == null) { if (!currentSidebar.classList.contains('tab-menu-category')) { fetchTabArticleOnClick(currentSidebar, locale) } } currentSidebar.querySelector("a").click() currentSidebar.classList.add(currentTabItemParentClass) } } } } } function fetchMenuTabData(key) { const itemStr = localStorage.getItem(key) // if the item doesn't exist, return null if (!itemStr) { return null } const item = JSON.parse(itemStr) const now = new Date() // compare the expiry time of the item with the current time if (now.getTime() > item.expiry) { // If the item is expired, delete the item from storage // and return null localStorage.removeItem(key) return null } return item } function createTabHeader(parent, prefix, data){ let parentNode = document.getElementById(parent); if(parentNode){ let parentUl = parentNode.getElementsByTagName("ul")[0]; if(!parentUl){ parentUl = document.createElement("ul"); if((prefix == sectionsTabPrefix) && data.parent_section_id){ parentUl.className = `${articleTabPrefix}-header`; } else { parentUl.className = `${prefix}-header`; } parentNode.appendChild(parentUl); } let elementLi = document.createElement("li"); elementLi.className = `${prefix}-header-wrapper`; parentUl.appendChild(elementLi); let elementLink = document.createElement("a"); elementLink.className = `${prefix}-header-link`; let elementSpan = document.createElement('span') if (prefix == categoriesTabPrefix) { elementLink.dataset.target = `#${categoriesTabPrefix}-${data.id}`; elementLink.dataset.toggle = 'tab' elementSpan.innerHTML = data.name elementLink.appendChild(elementSpan) } else if (prefix == sectionsTabPrefix) { elementLink.dataset.target = `#${sectionsTabPrefix}-${data.id}`; elementLink.dataset.toggle = 'tab' elementSpan.innerHTML = data.name elementLink.appendChild(elementSpan) } else if (prefix == articleTabPrefix) { elementLink.href = data.html_url; elementLink.innerHTML = data.name; } else { elementLink.dataset.target = `#${data.id}`; } elementLi.appendChild(elementLink); } } function createDummyTabHeader(parent, prefix, data, isCollapsible){ let parentNode = document.getElementById(parent); // console.log(prefix) if(parentNode){ let parentDiv = parentNode.getElementsByTagName("div")[0]; if(!parentDiv){ parentDiv = document.createElement("div"); if((prefix == sectionsTabPrefix) && data.parent_section_id){ parentDiv.className = `${articleTabPrefix}-content`; } else { parentDiv.className = `${prefix}-content`; } if (data.parent_section_id) { parentDiv.id = `${prefix}-collapse-${data.parent_section_id}`; if (isCollapsible) { parentDiv.classList.add('collapse') } } else if (prefix == articleTabPrefix) { parentDiv.id = `${sectionsTabPrefix}-collapse-${data.section_id}` if (isCollapsible) { parentDiv.classList.add('collapse') } } else { // parentDiv.id = `${articleTabPrefix}-collapse-${data.section_id}`; } parentNode.appendChild(parentDiv); } // Create div tag inside parentDiv let elementDiv = document.createElement("div"); elementDiv.id = `${prefix}-${data.id}`; elementDiv.className = prefix; // Create anchor tag inside elementDiv let elementLink = document.createElement("a"); elementLink.id = `${prefix}-link-${data.id}`; elementLink.dataset.id = data.id; elementLink.className = `${prefix}-content-link`; let elementSpan = document.createElement('span') let elementArrow = document.createElement('i') elementArrow.className = 'fa fa-angle-down' if (prefix == categoriesTabPrefix) { elementSpan.innerHTML = data.name elementLink.appendChild(elementSpan) } else if (prefix == sectionsTabPrefix) { elementLink.dataset.target = `#${sectionsTabPrefix}-collapse-${data.id}` elementLink.dataset.toggle = 'collapse' elementLink.ariaExpanded = false; elementSpan.innerHTML = data.name elementLink.appendChild(elementSpan) elementLink.appendChild(elementArrow) elementDiv.appendChild(elementLink); } else if (prefix == articleTabPrefix) { elementLink.href = data.html_url; elementLink.innerHTML = data.name; if (data.user_type == "staff") { let svgElement = ` ` elementLink.innerHTML = `${data.name} ${svgElement}` } if (data.promoted == true) { let svgPromotedElement = ` ` elementLink.innerHTML = `${svgPromotedElement} ${data.name}` } if ((data.promoted == true) && ( data.user_type == "staff")) { let svgElement = ` ` let svgPromotedElement = ` ` elementLink.innerHTML = `${svgPromotedElement} ${data.name} ${svgElement}` } elementDiv.appendChild(elementLink); } else { elementLink.dataset.target = `#${data.id}`; } parentDiv.appendChild(elementDiv); } } async function fetchUserSegment(id) { let userSegment = await fetch(`/api/v2/help_center/user_segments/${id}`) let response = await userSegment.json() return response.user_segment } // Helper function to create article element on section click function createTabArticleElement(parent, data) { // console.log(data) let prefix = "tab-menu-article" let currentItem = fetchCurrentUrlData() let currentId = currentItem.id let parentNode = document.getElementById(parent) let parentDiv = parentNode.getElementsByTagName("div")[0]; if(!parentDiv){ parentDiv = document.createElement("div"); } parentDiv.className = `${prefix}-content collapse in`; parentDiv.id = `${sectionsTabPrefix}-collapse-${data.section_id}` parentNode.appendChild(parentDiv); let elementDiv = document.createElement("div"); elementDiv.id = `${prefix}-${data.id}`; elementDiv.className = prefix; if (data.id == currentId) { elementDiv.classList.add(currentTabItemParentClass) } parentDiv.appendChild(elementDiv); // Create anchor tag inside elementDiv let elementLink = document.createElement("a"); elementLink.id = `${prefix}-link-${data.id}`; elementLink.dataset.id = `${prefix}-${data.id}`; elementLink.className = `${prefix}-content-link`; if (data.id == currentId) { elementLink.classList.add(currentTabItemClass) } elementLink.href = data.html_url; elementLink.innerHTML = data.name; if (data.user_type == "staff") { let svgElement = ` ` elementLink.innerHTML = `${data.name} ${svgElement}` } if (data.promoted == true) { let svgPromotedElement = ` ` elementLink.innerHTML = `${svgPromotedElement} ${data.name}` } if ((data.promoted == true) && ( data.user_type == "staff")) { let svgElement = ` ` let svgPromotedElement = ` ` elementLink.innerHTML = `${svgPromotedElement} ${data.name} ${svgElement}` } elementLink.dataset.target = `#${data.id}`; elementLink.ariaExpanded = false; elementDiv.appendChild(elementLink); } // Function for fetching article on section click async function fetchTabArticleOnClick(element, locale) { let sectionElement = $(element) let sectionId = $(element) .find('a') .attr('data-id') let parent = $(element).attr('id') let url = `/api/v2/help_center/${locale}/sections/${sectionId}/articles?per_page=100` let articleData = await fetchDataFromUrl(url, 'articles') let [articlesPromise] = await Promise.all([articleData]) .then($(sectionElement).removeClass('is-loading')) .catch(err=>{ console.error("Error occured in fetching data",err); }); if (Object.keys(articlesPromise).length != 0) { $(element).find('a').eq(0).attr('aria-expanded', true) for (let [key, value] of Object.entries(articlesPromise)) { if (HelpCenter.user.role !== 'end_user') { if (value.user_segment_id !== null) { let userSegmentId = value.user_segment_id let userSegment = await fetchUserSegment(userSegmentId) if (userSegment.user_type == 'staff') { value.user_type = "staff" } } } createTabArticleElement(parent, value) } } // Get old localstorage data let oldStorage = fetchMenuTabData(`${localStorageTabPrefix}-${locale}`) // Assign new promise with old data to new array let articles = Object.assign(articlesPromise, oldStorage["articles"]) let storageData = { ...oldStorage, articles } localStorage.setItem(`${localStorageTabPrefix}-${locale}`, JSON.stringify(storageData)) } async function createMenuTab(sidebar, locale = "en-us") { let menuTree = document.getElementById(sidebar); if(menuTree){ let MenuTabData = fetchMenuTabData(`${localStorageTabPrefix}-${locale}`); if(!MenuTabData){ MenuTabData = await setRequiredData(locale); } let categoriesLength = Object.keys(MenuTabData.categories).length if (categoriesLength >= 1) { for (let [key, value] of Object.entries(MenuTabData.categories)) { // Fetch categories data using category classname createTabHeader(sidebar,categoriesTabPrefix,value); } for (let [key, value] of Object.entries(MenuTabData.categories)) { // Fetch categories data using category classname for dummy createDummyTabHeader(sidebar,categoriesTabPrefix,value); } for (let [key, value] of Object.entries(MenuTabData.sections)) { createDummyTabHeader(`${categoriesTabPrefix}-${value.category_id}`, sectionsTabPrefix, value, true); } for (let [key, value] of Object.entries(MenuTabData.subSections)) { createDummyTabHeader(`${sectionsTabPrefix}-${value.parent_section_id}`,sectionsTabPrefix,value, true); } for (let [key, value] of Object.entries(MenuTabData.subSubSections)) { createDummyTabHeader(`${sectionsTabPrefix}-${value.parent_section_id}`,sectionsTabPrefix,value, true); } for (let [key, value] of Object.entries(MenuTabData.subSubSubSections)) { createDummyTabHeader(`${sectionsTabPrefix}-${value.parent_section_id}`,sectionsTabPrefix,value, true); } for (let [key, value] of Object.entries(MenuTabData.subSubSubSubSections)) { createDummyTabHeader(`${sectionsTabPrefix}-${value.parent_section_id}`,sectionsTabPrefix,value, true); } } if (MenuTabData.articles) { for (let [key, value] of Object.entries(MenuTabData.articles)) { createDummyTabHeader(`${sectionsTabPrefix}-${value.section_id}`,articleTabPrefix,value, true); } } // Get current page data from URL in case no breadcrumb present (eg: homepage) let urlData = fetchCurrentUrlData(); // Then set the active list based on urlData if(urlData.type){ setRequiredLi(urlData, locale); } let element = document.getElementsByClassName('tab-menu-section') for (i = 0; i < element.length; i++) { if ($(element[i]).attr('aria-expanded', 'false')) { if (!$(element[i]).hasClass('current-item-parent')) { if ($(element[i]).find('.tab-menu-article').eq(0).length == 0) { element[i].addEventListener('click', function(e) { fetchTabArticleOnClick(this, locale) }, {once: true}) } } } else { return null } } // console.log(MenuTabData) } }