Frooodle/license (#1994)
This commit is contained in:
File diff suppressed because one or more lines are too long
@@ -77,7 +77,7 @@ label {
|
||||
flex-direction: column;
|
||||
padding: 1rem;
|
||||
border-radius: 25px;
|
||||
overflow-y: hidden;
|
||||
overflow-y: auto;
|
||||
overflow-x: auto;
|
||||
min-height: 275px;
|
||||
margin: 0 0 30px 0;
|
||||
|
||||
@@ -89,6 +89,14 @@
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.close-icon {
|
||||
color: var(--md-sys-color-secondary);
|
||||
}
|
||||
|
||||
.close-icon:hover {
|
||||
transform: scale(1.15);
|
||||
}
|
||||
|
||||
span.icon-text::after {
|
||||
content: attr(data-text);
|
||||
content: attr(data-text) / "";
|
||||
@@ -320,3 +328,26 @@ span.icon-text::after {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.go-pro-link {
|
||||
position: relative;
|
||||
padding: 0.5rem 1rem;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.go-pro-badge {
|
||||
display: inline-block;
|
||||
padding: 0.25rem 0.5rem;
|
||||
font-size: 0.75rem;
|
||||
font-weight: bold;
|
||||
color: #ffffff;
|
||||
background-color: #007bff;
|
||||
border-radius: 0.25rem;
|
||||
text-transform: uppercase;
|
||||
transition: all 0.3s ease;
|
||||
}
|
||||
|
||||
.go-pro-link:hover .go-pro-badge {
|
||||
background-color: #0056b3;
|
||||
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
@@ -27,3 +27,16 @@
|
||||
display: flex;
|
||||
justify-content: space-around;
|
||||
}
|
||||
|
||||
#pdf-preview-large {
|
||||
margin: 0 auto;
|
||||
display: block;
|
||||
max-width: calc(100% - 30px);
|
||||
max-height: calc(100% - 30px);
|
||||
box-shadow: 0 0 4px rgba(100, 100, 100, 0.25);
|
||||
transition: rotate 0.3s;
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
translate: -50% -50%;
|
||||
}
|
||||
|
||||
@@ -5,6 +5,22 @@ function showErrorBanner(message, stackTrace) {
|
||||
document.querySelector("#errorContainer p").textContent = message;
|
||||
document.querySelector("#traceContent").textContent = stackTrace;
|
||||
}
|
||||
|
||||
function showSessionExpiredPrompt() {
|
||||
const errorContainer = document.getElementById("errorContainer");
|
||||
errorContainer.style.display = "block";
|
||||
document.querySelector("#errorContainer .alert-heading").textContent = sessionExpired;
|
||||
document.querySelector("#errorContainer p").textContent = sessionExpired;
|
||||
document.querySelector("#traceContent").textContent = "";
|
||||
|
||||
// Optional: Add a refresh button
|
||||
const refreshButton = document.createElement("button");
|
||||
refreshButton.textContent = "Refresh Page";
|
||||
refreshButton.className = "btn btn-primary mt-3";
|
||||
refreshButton.onclick = () => location.reload();
|
||||
errorContainer.appendChild(refreshButton);
|
||||
}
|
||||
|
||||
let firstErrorOccurred = false;
|
||||
|
||||
$(document).ready(function () {
|
||||
@@ -79,6 +95,11 @@ async function handleSingleDownload(url, formData, isMulti = false, isZip = fals
|
||||
const contentType = response.headers.get("content-type");
|
||||
|
||||
if (!response.ok) {
|
||||
if (response.status === 401) {
|
||||
// Handle 401 Unauthorized error
|
||||
showSessionExpiredPrompt();
|
||||
return;
|
||||
}
|
||||
if (contentType && contentType.includes("application/json")) {
|
||||
console.error("Throwing error banner, response was not okay");
|
||||
return handleJsonResponse(response);
|
||||
@@ -97,7 +118,7 @@ async function handleSingleDownload(url, formData, isMulti = false, isZip = fals
|
||||
}
|
||||
} catch (error) {
|
||||
console.error("Error in handleSingleDownload:", error);
|
||||
throw error; // Re-throw the error if you want it to be handled higher up.
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,45 +1,73 @@
|
||||
function updateFavoritesDropdown() {
|
||||
var dropdown = document.querySelector("#favoritesDropdown");
|
||||
|
||||
// Check if dropdown exists
|
||||
if (!dropdown) {
|
||||
console.error('Dropdown element with ID "favoritesDropdown" not found!');
|
||||
return; // Exit the function
|
||||
return;
|
||||
}
|
||||
dropdown.innerHTML = ""; // Clear the current favorites
|
||||
dropdown.innerHTML = "";
|
||||
|
||||
var hasFavorites = false;
|
||||
var addedFeatures = new Set();
|
||||
|
||||
for (var i = 0; i < localStorage.length; i++) {
|
||||
var key = localStorage.key(i);
|
||||
if (localStorage.getItem(key) === "favorite") {
|
||||
// Find the corresponding navbar entry
|
||||
var value = localStorage.getItem(key);
|
||||
|
||||
if (value === "favorite") {
|
||||
var navbarEntry = document.querySelector(`a[href='${key}']`);
|
||||
if (navbarEntry) {
|
||||
// Create a new dropdown entry
|
||||
var dropdownItem = document.createElement("a");
|
||||
dropdownItem.className = "dropdown-item";
|
||||
dropdownItem.href = navbarEntry.href;
|
||||
dropdownItem.innerHTML = navbarEntry.innerHTML;
|
||||
dropdown.appendChild(dropdownItem);
|
||||
hasFavorites = true;
|
||||
var featureName = navbarEntry.textContent.trim();
|
||||
|
||||
if (!addedFeatures.has(featureName)) {
|
||||
var dropdownItem = document.createElement("div");
|
||||
dropdownItem.className = "dropdown-item d-flex justify-content-between align-items-center";
|
||||
|
||||
// Create a wrapper for the original content
|
||||
var contentWrapper = document.createElement("div");
|
||||
contentWrapper.className = "d-flex align-items-center flex-grow-1";
|
||||
contentWrapper.style.textDecoration = "none";
|
||||
contentWrapper.style.color = "inherit";
|
||||
|
||||
// Clone the original content
|
||||
var originalContent = navbarEntry.querySelector('div').cloneNode(true);
|
||||
contentWrapper.appendChild(originalContent);
|
||||
|
||||
// Create the remove button
|
||||
var removeButton = document.createElement("button");
|
||||
removeButton.className = "btn btn-sm btn-link p-0 ml-2";
|
||||
removeButton.innerHTML = '<i class="material-symbols-rounded close-icon" style="font-size: 18px;">close</i>';
|
||||
removeButton.onclick = function(itemKey, event) {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
localStorage.removeItem(itemKey);
|
||||
updateFavoritesSection();
|
||||
updateFavoritesDropdown();
|
||||
filterCards();
|
||||
}.bind(null, key);
|
||||
|
||||
// Add click event to the content wrapper
|
||||
contentWrapper.onclick = function(itemHref, event) {
|
||||
event.preventDefault();
|
||||
window.location.href = itemHref;
|
||||
}.bind(null, navbarEntry.href);
|
||||
|
||||
dropdownItem.appendChild(contentWrapper);
|
||||
dropdownItem.appendChild(removeButton);
|
||||
dropdown.appendChild(dropdownItem);
|
||||
hasFavorites = true;
|
||||
addedFeatures.add(featureName);
|
||||
}
|
||||
} else {
|
||||
console.warn(`Navbar entry not found for key: ${key}`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Show or hide the default item based on whether there are any favorites
|
||||
if (!hasFavorites) {
|
||||
var defaultItem = document.createElement("a");
|
||||
defaultItem.className = "dropdown-item";
|
||||
defaultItem.textContent = noFavourites;
|
||||
defaultItem.textContent = noFavourites || "No favorites added";
|
||||
dropdown.appendChild(defaultItem);
|
||||
}
|
||||
}
|
||||
|
||||
// Ensure that the DOM content has been fully loaded before calling the function
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
console.log("DOMContentLoaded event fired");
|
||||
updateFavoritesDropdown();
|
||||
});
|
||||
|
||||
@@ -25,29 +25,38 @@ function filterCards() {
|
||||
function updateFavoritesSection() {
|
||||
const favoritesContainer = document.getElementById("groupFavorites").querySelector(".feature-group-container");
|
||||
favoritesContainer.style.maxHeight = "none";
|
||||
favoritesContainer.innerHTML = "";
|
||||
const cards = Array.from(document.querySelectorAll(".feature-card"));
|
||||
favoritesContainer.innerHTML = ""; // Clear the container first
|
||||
const cards = Array.from(document.querySelectorAll(".feature-card:not(.duplicate)"));
|
||||
const addedCardIds = new Set(); // To keep track of added card IDs
|
||||
let favoritesAmount = 0;
|
||||
|
||||
cards.forEach(card => {
|
||||
if (localStorage.getItem(card.id) === "favorite") {
|
||||
if (localStorage.getItem(card.id) === "favorite" && !addedCardIds.has(card.id)) {
|
||||
const duplicate = card.cloneNode(true);
|
||||
duplicate.classList.add("duplicate");
|
||||
favoritesContainer.appendChild(duplicate);
|
||||
addedCardIds.add(card.id); // Mark this card as added
|
||||
favoritesAmount++;
|
||||
}
|
||||
});
|
||||
|
||||
if (favoritesAmount === 0) {
|
||||
document.getElementById("groupFavorites").style.display = "none";
|
||||
} else {
|
||||
document.getElementById("groupFavorites").style.display = "flex";
|
||||
};
|
||||
}
|
||||
reorderCards(favoritesContainer);
|
||||
favoritesContainer.style.maxHeight = favoritesContainer.scrollHeight + "px";
|
||||
};
|
||||
}
|
||||
|
||||
function toggleFavorite(element) {
|
||||
var span = element.querySelector("span.material-symbols-rounded");
|
||||
var card = element.closest(".feature-card");
|
||||
var cardId = card.id;
|
||||
|
||||
// Prevent the event from bubbling up to parent elements
|
||||
event.stopPropagation();
|
||||
|
||||
if (span.classList.contains("no-fill")) {
|
||||
span.classList.remove("no-fill");
|
||||
span.classList.add("fill");
|
||||
@@ -59,7 +68,31 @@ function toggleFavorite(element) {
|
||||
card.classList.remove("favorite");
|
||||
localStorage.removeItem(cardId);
|
||||
}
|
||||
reorderCards(card.parentNode);
|
||||
|
||||
// Use setTimeout to ensure this runs after the current call stack is clear
|
||||
setTimeout(() => {
|
||||
reorderCards(card.parentNode);
|
||||
updateFavoritesSection();
|
||||
updateFavoritesDropdown();
|
||||
filterCards();
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function syncFavorites() {
|
||||
const cards = Array.from(document.querySelectorAll(".feature-card"));
|
||||
cards.forEach(card => {
|
||||
const isFavorite = localStorage.getItem(card.id) === "favorite";
|
||||
const starIcon = card.querySelector(".favorite-icon span.material-symbols-rounded");
|
||||
if (isFavorite) {
|
||||
starIcon.classList.remove("no-fill");
|
||||
starIcon.classList.add("fill");
|
||||
card.classList.add("favorite");
|
||||
} else {
|
||||
starIcon.classList.remove("fill");
|
||||
starIcon.classList.add("no-fill");
|
||||
card.classList.remove("favorite");
|
||||
}
|
||||
});
|
||||
updateFavoritesSection();
|
||||
updateFavoritesDropdown();
|
||||
filterCards();
|
||||
@@ -181,7 +214,10 @@ function expandCollapseAll(expandAll) {
|
||||
})
|
||||
}
|
||||
|
||||
window.onload = initializeCards;
|
||||
window.onload = function() {
|
||||
initializeCards();
|
||||
syncFavorites(); // Ensure everything is in sync on page load
|
||||
};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
const materialIcons = new FontFaceObserver('Material Symbols Rounded');
|
||||
@@ -223,7 +259,5 @@ document.addEventListener("DOMContentLoaded", function () {
|
||||
})
|
||||
}, 500);
|
||||
|
||||
|
||||
|
||||
showFavoritesOnly();
|
||||
});
|
||||
});
|
||||
@@ -192,6 +192,7 @@ class PdfActionsManager {
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default PdfActionsManager;
|
||||
|
||||
@@ -117,6 +117,7 @@ class PdfContainer {
|
||||
const newAngle = lastAngle + deg;
|
||||
|
||||
element.style.rotate = newAngle + "deg";
|
||||
|
||||
}
|
||||
|
||||
async addPdfFile(file, nextSiblingElement) {
|
||||
@@ -326,6 +327,9 @@ class PdfContainer {
|
||||
page.setRotation(PDFLib.degrees(page.getRotation().angle + rotationAngle));
|
||||
}
|
||||
}
|
||||
pdfDoc.setCreator(stirlingPDFLabel);
|
||||
pdfDoc.setProducer(stirlingPDFLabel);
|
||||
|
||||
const pdfBytes = await pdfDoc.save();
|
||||
const pdfBlob = new Blob([pdfBytes], { type: "application/pdf" });
|
||||
|
||||
|
||||
@@ -1,27 +1,32 @@
|
||||
const scrollDivHorizontally = (id) => {
|
||||
var scrollDelta = 0; // variable to store the accumulated scroll delta
|
||||
var scrollDeltaX = 0; // variable to store the accumulated horizontal scroll delta
|
||||
var scrollDeltaY = 0; // variable to store the accumulated vertical scroll delta
|
||||
var isScrolling = false; // variable to track if scroll is already in progress
|
||||
const divToScrollHorizontally = document.getElementById(id);
|
||||
const divToScroll = document.getElementById(id);
|
||||
|
||||
function scrollLoop() {
|
||||
// Scroll the div horizontally by a fraction of the accumulated scroll delta
|
||||
divToScrollHorizontally.scrollLeft += scrollDelta * 0.1;
|
||||
// Scroll the div horizontally and vertically by a fraction of the accumulated scroll delta
|
||||
divToScroll.scrollLeft += scrollDeltaX * 0.1;
|
||||
divToScroll.scrollTop += scrollDeltaY * 0.1;
|
||||
|
||||
// Reduce the accumulated scroll delta by a fraction
|
||||
scrollDelta *= 0.9;
|
||||
scrollDeltaX *= 0.9;
|
||||
scrollDeltaY *= 0.9;
|
||||
|
||||
// If scroll delta is still significant, continue the scroll loop
|
||||
if (Math.abs(scrollDelta) > 0.1) {
|
||||
if (Math.abs(scrollDeltaX) > 0.1 || Math.abs(scrollDeltaY) > 0.1) {
|
||||
requestAnimationFrame(scrollLoop);
|
||||
} else {
|
||||
isScrolling = false; // Reset scroll in progress flag
|
||||
}
|
||||
}
|
||||
|
||||
divToScrollHorizontally.addEventListener("wheel", function (e) {
|
||||
divToScroll.addEventListener("wheel", function (e) {
|
||||
e.preventDefault(); // prevent default mousewheel behavior
|
||||
|
||||
// Accumulate the horizontal scroll delta
|
||||
scrollDelta -= e.deltaX || e.wheelDeltaX || -e.deltaY || -e.wheelDeltaY;
|
||||
// Accumulate the horizontal and vertical scroll delta
|
||||
scrollDeltaX -= e.deltaX || e.wheelDeltaX || -e.deltaY || -e.wheelDeltaY;
|
||||
scrollDeltaY -= e.deltaY || e.wheelDeltaY || -e.deltaX || -e.wheelDeltaX;
|
||||
|
||||
// If scroll is not already in progress, start the scroll loop
|
||||
if (!isScrolling) {
|
||||
@@ -31,4 +36,4 @@ const scrollDivHorizontally = (id) => {
|
||||
});
|
||||
};
|
||||
|
||||
export default scrollDivHorizontally;
|
||||
export default scrollDivHorizontally;
|
||||
Reference in New Issue
Block a user