build based on 57c8db5

This commit is contained in:
Documenter.jl
2025-08-27 09:46:20 +00:00
parent 4be9a0d169
commit 2c03eb8f46
59 changed files with 395 additions and 287 deletions

View File

@@ -104,7 +104,7 @@ $(document).on(
.prop("title", articleToggleTitle);
parent.siblings("section").slideToggle();
});
}
},
);
$(document).on("click", ".docs-article-toggle-button", function (event) {
@@ -239,6 +239,20 @@ $(document).ready(function () {
type: "click",
noToggleAnimation: true,
});
setTimeout(function () {
if (window.location.hash) {
const targetId = window.location.hash.substring(1);
const targetElement = document.getElementById(targetId);
if (targetElement) {
targetElement.scrollIntoView({
behavior: "smooth",
block: "center",
});
}
}
}, 100);
}
});
@@ -312,7 +326,7 @@ update_search
function worker_function(documenterSearchIndex, documenterBaseURL, filters) {
importScripts(
"https://cdn.jsdelivr.net/npm/minisearch@6.1.0/dist/umd/index.min.js"
"https://cdn.jsdelivr.net/npm/minisearch@6.1.0/dist/umd/index.min.js",
);
let data = documenterSearchIndex.map((x, key) => {
@@ -523,8 +537,8 @@ function worker_function(documenterSearchIndex, documenterBaseURL, filters) {
Math.max(textindex.index - 100, 0),
Math.min(
textindex.index + querystring.length + 100,
result.text.length
)
result.text.length,
),
)
: ""; // cut-off text before and after from the match
@@ -534,7 +548,7 @@ function worker_function(documenterSearchIndex, documenterBaseURL, filters) {
? "..." +
text.replace(
new RegExp(`${escape(searchstring)}`, "i"), // For first occurrence
'<span class="search-result-highlight py-1">$&</span>'
'<span class="search-result-highlight py-1">$&</span>',
) +
"..."
: ""; // highlights the match
@@ -547,7 +561,7 @@ function worker_function(documenterSearchIndex, documenterBaseURL, filters) {
// We encode the full url to escape some special characters which can lead to broken links
let result_div = `
<a href="${encodeURI(
documenterBaseURL + "/" + result.location
documenterBaseURL + "/" + result.location,
)}" class="search-result-link w-100 is-flex is-flex-direction-column gap-2 px-4 py-2">
<div class="w-100 is-flex is-flex-wrap-wrap is-justify-content-space-between is-align-items-flex-start">
<div class="search-result-title has-text-weight-bold ${
@@ -612,176 +626,256 @@ function worker_function(documenterSearchIndex, documenterBaseURL, filters) {
};
}
// `worker = Threads.@spawn worker_function(documenterSearchIndex)`, but in JavaScript!
const filters = [
...new Set(documenterSearchIndex["docs"].map((x) => x.category)),
];
const worker_str =
"(" +
worker_function.toString() +
")(" +
JSON.stringify(documenterSearchIndex["docs"]) +
"," +
JSON.stringify(documenterBaseURL) +
"," +
JSON.stringify(filters) +
")";
const worker_blob = new Blob([worker_str], { type: "text/javascript" });
const worker = new Worker(URL.createObjectURL(worker_blob));
/////// SEARCH MAIN ///////
// Whether the worker is currently handling a search. This is a boolean
// as the worker only ever handles 1 or 0 searches at a time.
var worker_is_running = false;
function runSearchMainCode() {
// `worker = Threads.@spawn worker_function(documenterSearchIndex)`, but in JavaScript!
const filters = [
...new Set(documenterSearchIndex["docs"].map((x) => x.category)),
];
const worker_str =
"(" +
worker_function.toString() +
")(" +
JSON.stringify(documenterSearchIndex["docs"]) +
"," +
JSON.stringify(documenterBaseURL) +
"," +
JSON.stringify(filters) +
")";
const worker_blob = new Blob([worker_str], { type: "text/javascript" });
const worker = new Worker(URL.createObjectURL(worker_blob));
// The last search text that was sent to the worker. This is used to determine
// if the worker should be launched again when it reports back results.
var last_search_text = "";
// Whether the worker is currently handling a search. This is a boolean
// as the worker only ever handles 1 or 0 searches at a time.
var worker_is_running = false;
// The results of the last search. This, in combination with the state of the filters
// in the DOM, is used compute the results to display on calls to update_search.
var unfiltered_results = [];
// The last search text that was sent to the worker. This is used to determine
// if the worker should be launched again when it reports back results.
var last_search_text = "";
// Which filter is currently selected
var selected_filter = "";
// The results of the last search. This, in combination with the state of the filters
// in the DOM, is used compute the results to display on calls to update_search.
var unfiltered_results = [];
$(document).on("input", ".documenter-search-input", function (event) {
if (!worker_is_running) {
launch_search();
}
});
// Which filter is currently selected
var selected_filter = "";
function launch_search() {
worker_is_running = true;
last_search_text = $(".documenter-search-input").val();
worker.postMessage(last_search_text);
}
worker.onmessage = function (e) {
if (last_search_text !== $(".documenter-search-input").val()) {
launch_search();
} else {
worker_is_running = false;
}
unfiltered_results = e.data;
update_search();
};
$(document).on("click", ".search-filter", function () {
if ($(this).hasClass("search-filter-selected")) {
document.addEventListener("reset-filter", function () {
selected_filter = "";
} else {
selected_filter = $(this).text().toLowerCase();
}
update_search();
});
// This updates search results and toggles classes for UI:
update_search();
});
//update the url with search query
function updateSearchURL(query) {
const url = new URL(window.location);
/**
* Make/Update the search component
*/
function update_search() {
let querystring = $(".documenter-search-input").val();
if (querystring.trim()) {
if (selected_filter == "") {
results = unfiltered_results;
if (query && query.trim() !== "") {
url.searchParams.set("q", query);
} else {
results = unfiltered_results.filter((result) => {
return selected_filter == result.category.toLowerCase();
});
// remove the 'q' param if it exists
if (url.searchParams.has("q")) {
url.searchParams.delete("q");
}
}
let search_result_container = ``;
let modal_filters = make_modal_body_filters();
let search_divider = `<div class="search-divider w-100"></div>`;
if (results.length) {
let links = [];
let count = 0;
let search_results = "";
for (var i = 0, n = results.length; i < n && count < 200; ++i) {
let result = results[i];
if (result.location && !links.includes(result.location)) {
search_results += result.div;
count++;
links.push(result.location);
}
// Add or remove the filter parameter based on selected_filter
if (selected_filter && selected_filter.trim() !== "") {
url.searchParams.set("filter", selected_filter);
} else {
// remove the 'filter' param if it exists
if (url.searchParams.has("filter")) {
url.searchParams.delete("filter");
}
}
if (count == 1) {
count_str = "1 result";
} else if (count == 200) {
count_str = "200+ results";
// Only update history if there are parameters, otherwise use the base URL
if (url.search) {
window.history.replaceState({}, "", url);
} else {
window.history.replaceState({}, "", url.pathname + url.hash);
}
}
$(document).on("input", ".documenter-search-input", function (event) {
if (!worker_is_running) {
launch_search();
}
});
function launch_search() {
worker_is_running = true;
last_search_text = $(".documenter-search-input").val();
updateSearchURL(last_search_text);
worker.postMessage(last_search_text);
}
worker.onmessage = function (e) {
if (last_search_text !== $(".documenter-search-input").val()) {
launch_search();
} else {
worker_is_running = false;
}
unfiltered_results = e.data;
update_search();
};
$(document).on("click", ".search-filter", function () {
let search_input = $(".documenter-search-input");
let cursor_position = search_input[0].selectionStart;
if ($(this).hasClass("search-filter-selected")) {
selected_filter = "";
} else {
selected_filter = $(this).text().toLowerCase();
}
// This updates search results and toggles classes for UI:
update_search();
search_input.focus();
search_input.setSelectionRange(cursor_position, cursor_position);
});
/**
* Make/Update the search component
*/
function update_search() {
let querystring = $(".documenter-search-input").val();
updateSearchURL(querystring);
if (querystring.trim()) {
if (selected_filter == "") {
results = unfiltered_results;
} else {
count_str = count + " results";
results = unfiltered_results.filter((result) => {
return selected_filter == result.category.toLowerCase();
});
}
let result_count = `<div class="is-size-6">${count_str}</div>`;
search_result_container = `
let search_result_container = ``;
let modal_filters = make_modal_body_filters();
let search_divider = `<div class="search-divider w-100"></div>`;
if (results.length) {
let links = [];
let count = 0;
let search_results = "";
for (var i = 0, n = results.length; i < n && count < 200; ++i) {
let result = results[i];
if (result.location && !links.includes(result.location)) {
search_results += result.div;
count++;
links.push(result.location);
}
}
if (count == 1) {
count_str = "1 result";
} else if (count == 200) {
count_str = "200+ results";
} else {
count_str = count + " results";
}
let result_count = `<div class="is-size-6">${count_str}</div>`;
search_result_container = `
<div class="is-flex is-flex-direction-column gap-2 is-align-items-flex-start">
${modal_filters}
${search_divider}
${result_count}
<div class="is-clipped w-100 is-flex is-flex-direction-column gap-2 is-align-items-flex-start has-text-justified mt-1">
${search_results}
</div>
</div>
`;
} else {
search_result_container = `
<div class="is-flex is-flex-direction-column gap-2 is-align-items-flex-start">
${modal_filters}
${search_divider}
${result_count}
<div class="is-clipped w-100 is-flex is-flex-direction-column gap-2 is-align-items-flex-start has-text-justified mt-1">
${search_results}
</div>
</div>
<div class="is-size-6">0 result(s)</div>
</div>
<div class="has-text-centered my-5 py-5">No result found!</div>
`;
}
if ($(".search-modal-card-body").hasClass("is-justify-content-center")) {
$(".search-modal-card-body").removeClass("is-justify-content-center");
}
$(".search-modal-card-body").html(search_result_container);
} else {
search_result_container = `
<div class="is-flex is-flex-direction-column gap-2 is-align-items-flex-start">
${modal_filters}
${search_divider}
<div class="is-size-6">0 result(s)</div>
</div>
<div class="has-text-centered my-5 py-5">No result found!</div>
`;
if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) {
$(".search-modal-card-body").addClass("is-justify-content-center");
}
$(".search-modal-card-body").html(`
<div class="has-text-centered my-5 py-5">Type something to get started!</div>
`);
}
}
//url param checking
function checkURLForSearch() {
const urlParams = new URLSearchParams(window.location.search);
const searchQuery = urlParams.get("q");
const filterParam = urlParams.get("filter");
// Set the selected filter if present in URL
if (filterParam) {
selected_filter = filterParam.toLowerCase();
}
if ($(".search-modal-card-body").hasClass("is-justify-content-center")) {
$(".search-modal-card-body").removeClass("is-justify-content-center");
// Trigger input event if there's a search query to perform the search
if (searchQuery) {
$(".documenter-search-input").val(searchQuery).trigger("input");
}
}
setTimeout(checkURLForSearch, 100);
$(".search-modal-card-body").html(search_result_container);
} else {
if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) {
$(".search-modal-card-body").addClass("is-justify-content-center");
}
/**
* Make the modal filter html
*
* @returns string
*/
function make_modal_body_filters() {
let str = filters
.map((val) => {
if (selected_filter == val.toLowerCase()) {
return `<a href="javascript:;" class="search-filter search-filter-selected"><span>${val}</span></a>`;
} else {
return `<a href="javascript:;" class="search-filter"><span>${val}</span></a>`;
}
})
.join("");
$(".search-modal-card-body").html(`
<div class="has-text-centered my-5 py-5">Type something to get started!</div>
`);
return `
<div class="is-flex gap-2 is-flex-wrap-wrap is-justify-content-flex-start is-align-items-center search-filters">
<span class="is-size-6">Filters:</span>
${str}
</div>`;
}
}
/**
* Make the modal filter html
*
* @returns string
*/
function make_modal_body_filters() {
let str = filters
.map((val) => {
if (selected_filter == val.toLowerCase()) {
return `<a href="javascript:;" class="search-filter search-filter-selected"><span>${val}</span></a>`;
} else {
return `<a href="javascript:;" class="search-filter"><span>${val}</span></a>`;
}
})
.join("");
return `
<div class="is-flex gap-2 is-flex-wrap-wrap is-justify-content-flex-start is-align-items-center search-filters">
<span class="is-size-6">Filters:</span>
${str}
</div>`;
function waitUntilSearchIndexAvailable() {
// It is possible that the documenter.js script runs before the page
// has finished loading and documenterSearchIndex gets defined.
// So we need to wait until the search index actually loads before setting
// up all the search-related stuff.
if (typeof documenterSearchIndex !== "undefined") {
runSearchMainCode();
} else {
console.warn("Search Index not available, waiting");
setTimeout(waitUntilSearchIndexAvailable, 1000);
}
}
// The actual entry point to the search code
waitUntilSearchIndexAvailable();
})
////////////////////////////////////////////////////////////////////////////////
require(['jquery'], function($) {
@@ -812,8 +906,9 @@ $(document).ready(function () {
<div class="field mb-0 w-100">
<p class="control has-icons-right">
<input class="input documenter-search-input" type="text" placeholder="Search" />
<span class="icon is-small is-right has-text-primary-dark">
<i class="fas fa-magnifying-glass"></i>
<span class="icon is-small is-right has-text-primary-dark gap-2">
<i class="fas fa-link link-icon is-clickable"></i>
<i class="fas fa-magnifying-glass mr-4"></i>
</span>
</p>
</div>
@@ -849,9 +944,22 @@ $(document).ready(function () {
${search_modal_footer}
</div>
</div>
`
`,
);
function checkURLForSearch() {
const urlParams = new URLSearchParams(window.location.search);
const searchQuery = urlParams.get("q");
if (searchQuery) {
//only if there is a search query, open the modal
openModal();
}
}
//this function will be called whenever the page will load
checkURLForSearch();
document.querySelector(".docs-search-query").addEventListener("click", () => {
openModal();
});
@@ -876,6 +984,25 @@ $(document).ready(function () {
return false;
});
//event listener for the link icon to copy the URL
$(document).on("click", ".link-icon", function () {
const currentUrl = window.location.href;
navigator.clipboard
.writeText(currentUrl)
.then(() => {
const $linkIcon = $(this);
$linkIcon.removeClass("fa-link").addClass("fa-check");
setTimeout(() => {
$linkIcon.removeClass("fa-check").addClass("fa-link");
}, 1000);
})
.catch((err) => {
console.error("Failed to copy URL: ", err);
});
});
// Functions to open and close a modal
function openModal() {
let searchModal = document.querySelector("#search-modal");
@@ -890,15 +1017,17 @@ $(document).ready(function () {
<div class="has-text-centered my-5 py-5">Type something to get started!</div>
`;
$(".documenter-search-input").val("");
$(".search-modal-card-body").html(initial_search_body);
document.dispatchEvent(new CustomEvent("reset-filter"));
searchModal.classList.remove("is-active");
document.querySelector(".documenter-search-input").blur();
if (!$(".search-modal-card-body").hasClass("is-justify-content-center")) {
$(".search-modal-card-body").addClass("is-justify-content-center");
}
$(".documenter-search-input").val("");
$(".search-modal-card-body").html(initial_search_body);
}
document
@@ -1027,7 +1156,7 @@ $(document).ready(function () {
var option = $(
"<option value='#' selected='selected'>" +
DOCUMENTER_CURRENT_VERSION +
"</option>"
"</option>",
);
version_selector_select.append(option);
}
@@ -1044,7 +1173,7 @@ $(document).ready(function () {
// otherwise update the old option with the URL and enable it
if (existing_id == -1) {
var option = $(
"<option value='" + version_url + "'>" + each + "</option>"
"<option value='" + version_url + "'>" + each + "</option>",
);
version_selector_select.append(option);
} else {