/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ /* * This file is part of the LibreOffice project. * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ // Pagination and bookmark search var url = window.location.pathname; var moduleRegex = new RegExp('text\\/(\\w+)\\/'); var regexArray = moduleRegex.exec(url); var userModule = currentModule(); var modules = ['CALC', 'WRITER', 'IMPRESS', 'DRAW', 'BASE', 'MATH', 'CHART', 'BASIC', 'SHARED']; var indexEl = document.getElementsByClassName("index")[0]; var fullLinks = fullLinkify(indexEl, bookmarks, modules, userModule); var search = document.getElementById('search-bar'); search.addEventListener('keyup', debounce(filter, 100, indexEl)); var flexIndex = new FlexSearch.Document({ document: { // Only the text content gets indexed, the others get stored as-is index: [{ field: 'text', tokenize: 'full' }], store: ['url','app','text'] } }); // Populate FlexSearch index loadSearch(); // Render the unfiltered index list on page load fillIndex(indexEl, fullLinks, modules); // Preserve search input value during the session search.value = sessionStorage.getItem('searchsave'); if (search.value !== undefined) { filter(indexEl); } window.addEventListener('unload', function(event) { sessionStorage.setItem('searchsave', search.value); }); function getQuery(q) { var pattern = new RegExp('[?&]' + q + '=([^&]+)'); var param = window.location.search.match(pattern); if (param) { return param[1]; } return null; } function currentModule() { // We need to know the module that the user is using when they call for help let module = getQuery('DbPAR'); let moduleFromURL = regexArray[1].toUpperCase(); if (module == null) { // first deal with snowflake Base if(url.indexOf('/sdatabase/') !== -1) { module = 'BASE'; } else { if (null === regexArray || moduleFromURL === 'SHARED') { // comes from search or elsewhere, no defined module in URL module = 'SHARED' } else { // drop the 's' from the start module = moduleFromURL.substring(1); } } } return module; }; function fullLinkify(indexEl, bookmarks, modules, currentModule) { var fullLinkified = ''; // if user is not on a shared category page, limit the index to the current module + shared if(currentModule !== 'SHARED') { bookmarks = bookmarks.filter(function(obj) { return obj['app'] === currentModule || obj['app'] === 'SHARED'; }); } bookmarks.forEach(function(obj) { fullLinkified += '' + obj['text'] + ''; }); return fullLinkified; } function loadSearch() { bookmarks.forEach((el, i) => { flexIndex.add(i, el); }); } function fillIndex(indexEl, content, modules) { indexEl.innerHTML = content; var indexKids = indexEl.children; for (var i = 0, len = indexKids.length; i < len; i++) { indexKids[i].removeAttribute("id"); } modules.forEach(function(module) { var moduleHeader = indexEl.getElementsByClassName(module)[0]; if (typeof moduleHeader !== 'undefined') { // let's wrap the header in a span, so the ::before element will not become a link moduleHeader.outerHTML = '' + moduleHeader.outerHTML + ''; } }); Paginator(indexEl); } // filter the index list based on search field input function filter(indexList) { let group = []; let target = search.value.trim(); let filtered = ''; if (target.length < 1) { fillIndex(indexEl, fullLinks, modules); return; } // Regex for highlighting the match let regex = new RegExp(target.split(/\s+/).filter((i) => i?.length).join("|"), 'gi'); let results = flexIndex.search(target, { pluck: "text", enrich: true, limit: 1000 }); // Similarly to fullLinkify(), limit search results to the user's current module + shared // unless they're somehow not coming from a module. if(userModule !== 'SHARED') { resultModules = [userModule, 'SHARED']; } else { resultModules = modules; } // tdf#123506 - Group the filtered list into module groups, keeping the ordering modules.forEach(function(module) { group[module] = ''; }); results.forEach(function(result) { group[result.doc.app] += '' + result.doc.text.replace(regex, (match) => `${match}`) + ''; }); resultModules.forEach(function(module) { if (group[module].length > 0) { filtered += group[module]; } }); fillIndex(indexList, filtered, modules); }; // delay the rendering of the filtered results while user is typing function debounce(fn, wait, indexList) { var timeout; return function() { clearTimeout(timeout); timeout = setTimeout(function() { fn.call(this, indexList); }, (wait || 150)); }; } // copy pycode, sqlcode and bascode to clipboard on mouse click // Show border when copy is done divcopyable(document.getElementsByClassName("bascode")); divcopyable(document.getElementsByClassName("pycode")); divcopyable(document.getElementsByClassName("sqlcode")); function divcopyable(itemcopyable){ for (var i = 0, len = itemcopyable.length; i < len; i++) { (function() { var item = itemcopyable[i]; function changeBorder(item, color) { var saveBorder = item.style.border; item.style.borderColor = color; setTimeout(function() { item.style.border = saveBorder; }, 150); } item.onclick = function() { document.execCommand("copy"); changeBorder(item, "#18A303"); }; item.addEventListener("copy", function(event) { event.preventDefault(); if (event.clipboardData) { event.clipboardData.setData("text/plain", item.textContent); } }); }()); } } // copy useful content to clipboard on mouse click var copyable = document.getElementsByClassName("input"); for (var i = 0, len = copyable.length; i < len; i++) { (function() { var item = copyable[i]; function changeColor(item, color, colorToChangeBackTo) { item.style.backgroundColor = color; setTimeout(function() { item.style.backgroundColor = colorToChangeBackTo; }, 150); } item.onclick = function() { document.execCommand("copy"); changeColor(item, "#18A303", "transparent"); }; item.addEventListener("copy", function(event) { event.preventDefault(); if (event.clipboardData) { event.clipboardData.setData("text/plain", item.textContent); } }); }()); } // auto-expand contents per subitem var pathname = window.location.pathname; var pathRegex = /text\/.*\.html$/; var linkIndex = 0; var contentMatch = pathname.match(pathRegex); function linksMatch(content) { var linkMatch = new RegExp(content); var links = document.getElementById("Contents").getElementsByTagName("a"); for (var i = 0, len = links.length; i < len; i++) { if (links[i].href.match(linkMatch)) { return i; } } } linkIndex = linksMatch(contentMatch); if (typeof linkIndex !== "undefined") { var current = document.getElementById("Contents").getElementsByTagName("a")[linkIndex]; var cItem = current.parentElement; var parents = []; while (cItem.parentElement && !cItem.parentElement.matches("#Contents") && parents.indexOf(cItem.parentElement) == -1) { parents.push(cItem = cItem.parentElement); } var liParents = [].filter.call(parents, function(item) { return item.matches("li"); }); for (var i = 0, len = liParents.length; i < len; i++) { var input = liParents[i].querySelectorAll(':scope > input'); document.getElementById(input[0].id).checked = true; } current.classList.add('contents-current'); } // close navigation menus when clicking anywhere on the page // (ignoring menu button clicks and mobile browsing) document.addEventListener('click', function(event) { let a11yButton = event.target.getAttribute("data-a11y-toggle"); let vw = Math.max(document.documentElement.clientWidth || 0, window.innerWidth || 0); if (!a11yButton && vw >= 960) { document.querySelectorAll("[data-a11y-toggle] + nav").forEach((el) => { el.setAttribute("aria-hidden", true); }); } }); // YouTube consent click. This only works for a single video. let youtubePlaceholder = document.querySelector(".youtube_placeholder"); if (youtubePlaceholder) { youtubePlaceholder.prepend(...document.querySelectorAll(".youtube_consent")); } function youtubeLoader(ytId, width, height) { let iframeMarkup = ``; let placeholder = document.getElementById(ytId); placeholder.innerHTML = iframeMarkup; placeholder.removeAttribute("style"); } /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */