mirror of
https://github.com/Frooodle/Stirling-PDF.git
synced 2025-08-16 13:47:28 +02:00
refactor: formatting, indentation
This commit is contained in:
parent
538e1534d5
commit
139c6ccfca
@ -1,12 +1,12 @@
|
|||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener("DOMContentLoaded", function () {
|
||||||
const bookmarksContainer = document.getElementById('bookmarks-container');
|
const bookmarksContainer = document.getElementById("bookmarks-container");
|
||||||
const addBookmarkBtn = document.getElementById('addBookmarkBtn');
|
const addBookmarkBtn = document.getElementById("addBookmarkBtn");
|
||||||
const bookmarkDataInput = document.getElementById('bookmarkData');
|
const bookmarkDataInput = document.getElementById("bookmarkData");
|
||||||
let bookmarks = [];
|
let bookmarks = [];
|
||||||
let counter = 0; // Used for generating unique IDs
|
let counter = 0; // Used for generating unique IDs
|
||||||
|
|
||||||
// Add event listener to the file input to extract existing bookmarks
|
// Add event listener to the file input to extract existing bookmarks
|
||||||
document.getElementById('fileInput-input').addEventListener('change', async function(e) {
|
document.getElementById("fileInput-input").addEventListener("change", async function (e) {
|
||||||
if (!e.target.files || e.target.files.length === 0) {
|
if (!e.target.files || e.target.files.length === 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -16,16 +16,16 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
updateBookmarksUI();
|
updateBookmarksUI();
|
||||||
|
|
||||||
const formData = new FormData();
|
const formData = new FormData();
|
||||||
formData.append('file', e.target.files[0]);
|
formData.append("file", e.target.files[0]);
|
||||||
|
|
||||||
// Show loading indicator
|
// Show loading indicator
|
||||||
showLoadingIndicator();
|
showLoadingIndicator();
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Call the API to extract bookmarks using fetchWithCsrf for CSRF protection
|
// Call the API to extract bookmarks using fetchWithCsrf for CSRF protection
|
||||||
const response = await fetchWithCsrf('/api/v1/general/extract-bookmarks', {
|
const response = await fetchWithCsrf("/api/v1/general/extract-bookmarks", {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
body: formData
|
body: formData,
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!response.ok) {
|
if (!response.ok) {
|
||||||
@ -42,7 +42,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
// Show error message
|
// Show error message
|
||||||
showErrorMessage('Failed to extract bookmarks. You can still create new ones.');
|
showErrorMessage("Failed to extract bookmarks. You can still create new ones.");
|
||||||
|
|
||||||
// Add a default bookmark if no bookmarks and error
|
// Add a default bookmark if no bookmarks and error
|
||||||
if (bookmarks.length === 0) {
|
if (bookmarks.length === 0) {
|
||||||
@ -58,31 +58,31 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function showLoadingIndicator() {
|
function showLoadingIndicator() {
|
||||||
const loadingEl = document.createElement('div');
|
const loadingEl = document.createElement("div");
|
||||||
loadingEl.className = 'alert alert-info';
|
loadingEl.className = "alert alert-info";
|
||||||
loadingEl.textContent = 'Loading bookmarks from PDF...';
|
loadingEl.textContent = "Loading bookmarks from PDF...";
|
||||||
loadingEl.id = 'loading-bookmarks';
|
loadingEl.id = "loading-bookmarks";
|
||||||
bookmarksContainer.innerHTML = '';
|
bookmarksContainer.innerHTML = "";
|
||||||
bookmarksContainer.appendChild(loadingEl);
|
bookmarksContainer.appendChild(loadingEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
function removeLoadingIndicator() {
|
function removeLoadingIndicator() {
|
||||||
const loadingEl = document.getElementById('loading-bookmarks');
|
const loadingEl = document.getElementById("loading-bookmarks");
|
||||||
if (loadingEl) {
|
if (loadingEl) {
|
||||||
loadingEl.remove();
|
loadingEl.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function showErrorMessage(message) {
|
function showErrorMessage(message) {
|
||||||
const errorEl = document.createElement('div');
|
const errorEl = document.createElement("div");
|
||||||
errorEl.className = 'alert alert-danger';
|
errorEl.className = "alert alert-danger";
|
||||||
errorEl.textContent = message;
|
errorEl.textContent = message;
|
||||||
bookmarksContainer.appendChild(errorEl);
|
bookmarksContainer.appendChild(errorEl);
|
||||||
}
|
}
|
||||||
|
|
||||||
function showEmptyState() {
|
function showEmptyState() {
|
||||||
const emptyStateEl = document.createElement('div');
|
const emptyStateEl = document.createElement("div");
|
||||||
emptyStateEl.className = 'empty-bookmarks mb-3';
|
emptyStateEl.className = "empty-bookmarks mb-3";
|
||||||
emptyStateEl.innerHTML = `
|
emptyStateEl.innerHTML = `
|
||||||
<span class="material-symbols-rounded mb-2" style="font-size: 48px;">bookmark_add</span>
|
<span class="material-symbols-rounded mb-2" style="font-size: 48px;">bookmark_add</span>
|
||||||
<h5>No bookmarks found</h5>
|
<h5>No bookmarks found</h5>
|
||||||
@ -93,8 +93,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
`;
|
`;
|
||||||
|
|
||||||
// Add event listener to the "Add First Bookmark" button
|
// Add event listener to the "Add First Bookmark" button
|
||||||
emptyStateEl.querySelector('.btn-add-first-bookmark').addEventListener('click', function() {
|
emptyStateEl.querySelector(".btn-add-first-bookmark").addEventListener("click", function () {
|
||||||
addBookmark(null, 'New Bookmark', 1);
|
addBookmark(null, "New Bookmark", 1);
|
||||||
emptyStateEl.remove();
|
emptyStateEl.remove();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -106,15 +106,15 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
counter++;
|
counter++;
|
||||||
const result = {
|
const result = {
|
||||||
id: Date.now() + counter, // Generate a unique ID
|
id: Date.now() + counter, // Generate a unique ID
|
||||||
title: bookmark.title || 'Untitled Bookmark',
|
title: bookmark.title || "Untitled Bookmark",
|
||||||
pageNumber: bookmark.pageNumber || 1,
|
pageNumber: bookmark.pageNumber || 1,
|
||||||
children: [],
|
children: [],
|
||||||
expanded: false // All bookmarks start collapsed for better visibility
|
expanded: false, // All bookmarks start collapsed for better visibility
|
||||||
};
|
};
|
||||||
|
|
||||||
// Convert children recursively
|
// Convert children recursively
|
||||||
if (bookmark.children && bookmark.children.length > 0) {
|
if (bookmark.children && bookmark.children.length > 0) {
|
||||||
result.children = bookmark.children.map(child => {
|
result.children = bookmark.children.map((child) => {
|
||||||
return convertExtractedBookmark(child);
|
return convertExtractedBookmark(child);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -123,24 +123,24 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add bookmark button click handler
|
// Add bookmark button click handler
|
||||||
addBookmarkBtn.addEventListener('click', function(e) {
|
addBookmarkBtn.addEventListener("click", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
addBookmark();
|
addBookmark();
|
||||||
});
|
});
|
||||||
|
|
||||||
// Add form submit handler to update JSON data
|
// Add form submit handler to update JSON data
|
||||||
document.getElementById('editTocForm').addEventListener('submit', function() {
|
document.getElementById("editTocForm").addEventListener("submit", function () {
|
||||||
updateBookmarkData();
|
updateBookmarkData();
|
||||||
});
|
});
|
||||||
|
|
||||||
function addBookmark(parent = null, title = '', pageNumber = 1) {
|
function addBookmark(parent = null, title = "", pageNumber = 1) {
|
||||||
counter++;
|
counter++;
|
||||||
const newBookmark = {
|
const newBookmark = {
|
||||||
id: Date.now() + counter,
|
id: Date.now() + counter,
|
||||||
title: title || 'New Bookmark',
|
title: title || "New Bookmark",
|
||||||
pageNumber: pageNumber || 1,
|
pageNumber: pageNumber || 1,
|
||||||
children: [],
|
children: [],
|
||||||
expanded: false // New bookmarks start collapsed
|
expanded: false, // New bookmarks start collapsed
|
||||||
};
|
};
|
||||||
|
|
||||||
if (parent === null) {
|
if (parent === null) {
|
||||||
@ -162,13 +162,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
const newElement = document.querySelector(`[data-id="${newBookmark.id}"]`);
|
const newElement = document.querySelector(`[data-id="${newBookmark.id}"]`);
|
||||||
if (newElement) {
|
if (newElement) {
|
||||||
const titleInput = newElement.querySelector('.bookmark-title');
|
const titleInput = newElement.querySelector(".bookmark-title");
|
||||||
if (titleInput) {
|
if (titleInput) {
|
||||||
titleInput.focus();
|
titleInput.focus();
|
||||||
titleInput.select();
|
titleInput.select();
|
||||||
}
|
}
|
||||||
// Scroll to the new element
|
// Scroll to the new element
|
||||||
newElement.scrollIntoView({ behavior: 'smooth', block: 'center' });
|
newElement.scrollIntoView({ behavior: "smooth", block: "center" });
|
||||||
}
|
}
|
||||||
}, 50);
|
}, 50);
|
||||||
}
|
}
|
||||||
@ -203,7 +203,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
function removeBookmark(id) {
|
function removeBookmark(id) {
|
||||||
// Remove from top level
|
// Remove from top level
|
||||||
const index = bookmarks.findIndex(b => b.id === id);
|
const index = bookmarks.findIndex((b) => b.id === id);
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
bookmarks.splice(index, 1);
|
bookmarks.splice(index, 1);
|
||||||
updateBookmarksUI();
|
updateBookmarksUI();
|
||||||
@ -213,7 +213,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
// Remove from children
|
// Remove from children
|
||||||
function removeFromChildren(bookmarkArray, id) {
|
function removeFromChildren(bookmarkArray, id) {
|
||||||
for (const bookmark of bookmarkArray) {
|
for (const bookmark of bookmarkArray) {
|
||||||
const childIndex = bookmark.children.findIndex(b => b.id === id);
|
const childIndex = bookmark.children.findIndex((b) => b.id === id);
|
||||||
if (childIndex !== -1) {
|
if (childIndex !== -1) {
|
||||||
bookmark.children.splice(childIndex, 1);
|
bookmark.children.splice(childIndex, 1);
|
||||||
return true;
|
return true;
|
||||||
@ -253,7 +253,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
return {
|
return {
|
||||||
title: bookmark.title,
|
title: bookmark.title,
|
||||||
pageNumber: bookmark.pageNumber,
|
pageNumber: bookmark.pageNumber,
|
||||||
children: bookmark.children.map(cleanBookmark)
|
children: bookmark.children.map(cleanBookmark),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -263,22 +263,22 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Only clear the container if there are no error messages or loading indicators
|
// Only clear the container if there are no error messages or loading indicators
|
||||||
if (!document.querySelector('#bookmarks-container .alert')) {
|
if (!document.querySelector("#bookmarks-container .alert")) {
|
||||||
bookmarksContainer.innerHTML = '';
|
bookmarksContainer.innerHTML = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if there are bookmarks to display
|
// Check if there are bookmarks to display
|
||||||
if (bookmarks.length === 0 && !document.querySelector('.empty-bookmarks')) {
|
if (bookmarks.length === 0 && !document.querySelector(".empty-bookmarks")) {
|
||||||
showEmptyState();
|
showEmptyState();
|
||||||
} else {
|
} else {
|
||||||
// Remove empty state if it exists and there are bookmarks
|
// Remove empty state if it exists and there are bookmarks
|
||||||
const emptyState = document.querySelector('.empty-bookmarks');
|
const emptyState = document.querySelector(".empty-bookmarks");
|
||||||
if (emptyState && bookmarks.length > 0) {
|
if (emptyState && bookmarks.length > 0) {
|
||||||
emptyState.remove();
|
emptyState.remove();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create bookmark elements
|
// Create bookmark elements
|
||||||
bookmarks.forEach(bookmark => {
|
bookmarks.forEach((bookmark) => {
|
||||||
const bookmarkElement = createBookmarkElement(bookmark);
|
const bookmarkElement = createBookmarkElement(bookmark);
|
||||||
bookmarksContainer.appendChild(bookmarkElement);
|
bookmarksContainer.appendChild(bookmarkElement);
|
||||||
});
|
});
|
||||||
@ -287,15 +287,15 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
updateBookmarkData();
|
updateBookmarkData();
|
||||||
|
|
||||||
// Initialize tooltips for dynamically added elements
|
// Initialize tooltips for dynamically added elements
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== "undefined") {
|
||||||
$('[data-bs-toggle="tooltip"]').tooltip();
|
$('[data-bs-toggle="tooltip"]').tooltip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create the main bookmark element with collapsible interface
|
// Create the main bookmark element with collapsible interface
|
||||||
function createBookmarkElement(bookmark, level = 0) {
|
function createBookmarkElement(bookmark, level = 0) {
|
||||||
const bookmarkEl = document.createElement('div');
|
const bookmarkEl = document.createElement("div");
|
||||||
bookmarkEl.className = 'bookmark-item';
|
bookmarkEl.className = "bookmark-item";
|
||||||
bookmarkEl.dataset.id = bookmark.id;
|
bookmarkEl.dataset.id = bookmark.id;
|
||||||
bookmarkEl.dataset.level = level;
|
bookmarkEl.dataset.level = level;
|
||||||
|
|
||||||
@ -304,10 +304,10 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
bookmarkEl.appendChild(header);
|
bookmarkEl.appendChild(header);
|
||||||
|
|
||||||
// Create the content (collapsible part)
|
// Create the content (collapsible part)
|
||||||
const content = document.createElement('div');
|
const content = document.createElement("div");
|
||||||
content.className = 'bookmark-content';
|
content.className = "bookmark-content";
|
||||||
if (!bookmark.expanded) {
|
if (!bookmark.expanded) {
|
||||||
content.style.display = 'none';
|
content.style.display = "none";
|
||||||
}
|
}
|
||||||
|
|
||||||
// Main input row
|
// Main input row
|
||||||
@ -328,48 +328,48 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
// Create the header that's always visible
|
// Create the header that's always visible
|
||||||
function createBookmarkHeader(bookmark, level) {
|
function createBookmarkHeader(bookmark, level) {
|
||||||
const header = document.createElement('div');
|
const header = document.createElement("div");
|
||||||
header.className = 'bookmark-header';
|
header.className = "bookmark-header";
|
||||||
if (!bookmark.expanded) {
|
if (!bookmark.expanded) {
|
||||||
header.classList.add('collapsed');
|
header.classList.add("collapsed");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Left side of header with expand/collapse and info
|
// Left side of header with expand/collapse and info
|
||||||
const headerLeft = document.createElement('div');
|
const headerLeft = document.createElement("div");
|
||||||
headerLeft.className = 'd-flex align-items-center';
|
headerLeft.className = "d-flex align-items-center";
|
||||||
|
|
||||||
// Toggle expand/collapse icon with child count
|
// Toggle expand/collapse icon with child count
|
||||||
const toggleContainer = document.createElement('div');
|
const toggleContainer = document.createElement("div");
|
||||||
toggleContainer.className = 'd-flex align-items-center';
|
toggleContainer.className = "d-flex align-items-center";
|
||||||
toggleContainer.style.marginRight = '8px';
|
toggleContainer.style.marginRight = "8px";
|
||||||
|
|
||||||
// Only show toggle if has children
|
// Only show toggle if has children
|
||||||
if (bookmark.children && bookmark.children.length > 0) {
|
if (bookmark.children && bookmark.children.length > 0) {
|
||||||
// Create toggle icon
|
// Create toggle icon
|
||||||
const toggleIcon = document.createElement('span');
|
const toggleIcon = document.createElement("span");
|
||||||
toggleIcon.className = 'material-symbols-rounded toggle-icon me-1';
|
toggleIcon.className = "material-symbols-rounded toggle-icon me-1";
|
||||||
toggleIcon.textContent = 'expand_more';
|
toggleIcon.textContent = "expand_more";
|
||||||
toggleIcon.style.cursor = 'pointer';
|
toggleIcon.style.cursor = "pointer";
|
||||||
toggleContainer.appendChild(toggleIcon);
|
toggleContainer.appendChild(toggleIcon);
|
||||||
|
|
||||||
// Add child count indicator
|
// Add child count indicator
|
||||||
const childCount = document.createElement('span');
|
const childCount = document.createElement("span");
|
||||||
childCount.className = 'badge rounded-pill';
|
childCount.className = "badge rounded-pill";
|
||||||
// Use theme-appropriate badge color
|
// Use theme-appropriate badge color
|
||||||
const isDarkMode = document.documentElement.getAttribute('data-bs-theme') === 'dark';
|
const isDarkMode = document.documentElement.getAttribute("data-bs-theme") === "dark";
|
||||||
childCount.classList.add(isDarkMode ? 'bg-info' : 'bg-secondary');
|
childCount.classList.add(isDarkMode ? "bg-info" : "bg-secondary");
|
||||||
childCount.style.fontSize = '0.7rem';
|
childCount.style.fontSize = "0.7rem";
|
||||||
childCount.style.padding = '0.2em 0.5em';
|
childCount.style.padding = "0.2em 0.5em";
|
||||||
childCount.textContent = bookmark.children.length;
|
childCount.textContent = bookmark.children.length;
|
||||||
childCount.setAttribute('data-bs-toggle', 'tooltip');
|
childCount.setAttribute("data-bs-toggle", "tooltip");
|
||||||
childCount.setAttribute('data-bs-placement', 'top');
|
childCount.setAttribute("data-bs-placement", "top");
|
||||||
childCount.title = `${bookmark.children.length} child bookmark${bookmark.children.length > 1 ? 's' : ''}`;
|
childCount.title = `${bookmark.children.length} child bookmark${bookmark.children.length > 1 ? "s" : ""}`;
|
||||||
toggleContainer.appendChild(childCount);
|
toggleContainer.appendChild(childCount);
|
||||||
} else {
|
} else {
|
||||||
// Add spacer if no children
|
// Add spacer if no children
|
||||||
const spacer = document.createElement('span');
|
const spacer = document.createElement("span");
|
||||||
spacer.style.width = '24px';
|
spacer.style.width = "24px";
|
||||||
spacer.style.display = 'inline-block';
|
spacer.style.display = "inline-block";
|
||||||
toggleContainer.appendChild(spacer);
|
toggleContainer.appendChild(spacer);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -378,65 +378,68 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
// Level indicator for nested items
|
// Level indicator for nested items
|
||||||
if (level > 0) {
|
if (level > 0) {
|
||||||
// Add relationship indicator visual line
|
// Add relationship indicator visual line
|
||||||
const relationshipIndicator = document.createElement('div');
|
const relationshipIndicator = document.createElement("div");
|
||||||
relationshipIndicator.className = 'bookmark-relationship-indicator';
|
relationshipIndicator.className = "bookmark-relationship-indicator";
|
||||||
|
|
||||||
const line = document.createElement('div');
|
const line = document.createElement("div");
|
||||||
line.className = 'relationship-line';
|
line.className = "relationship-line";
|
||||||
relationshipIndicator.appendChild(line);
|
relationshipIndicator.appendChild(line);
|
||||||
|
|
||||||
const arrow = document.createElement('div');
|
const arrow = document.createElement("div");
|
||||||
arrow.className = 'relationship-arrow';
|
arrow.className = "relationship-arrow";
|
||||||
relationshipIndicator.appendChild(arrow);
|
relationshipIndicator.appendChild(arrow);
|
||||||
|
|
||||||
header.appendChild(relationshipIndicator);
|
header.appendChild(relationshipIndicator);
|
||||||
|
|
||||||
// Text indicator
|
// Text indicator
|
||||||
const levelIndicator = document.createElement('span');
|
const levelIndicator = document.createElement("span");
|
||||||
levelIndicator.className = 'bookmark-level-indicator';
|
levelIndicator.className = "bookmark-level-indicator";
|
||||||
levelIndicator.textContent = `Child`;
|
levelIndicator.textContent = `Child`;
|
||||||
headerLeft.appendChild(levelIndicator);
|
headerLeft.appendChild(levelIndicator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Title preview
|
// Title preview
|
||||||
const titlePreview = document.createElement('span');
|
const titlePreview = document.createElement("span");
|
||||||
titlePreview.className = 'bookmark-title-preview';
|
titlePreview.className = "bookmark-title-preview";
|
||||||
titlePreview.textContent = bookmark.title;
|
titlePreview.textContent = bookmark.title;
|
||||||
headerLeft.appendChild(titlePreview);
|
headerLeft.appendChild(titlePreview);
|
||||||
|
|
||||||
// Page number preview
|
// Page number preview
|
||||||
const pagePreview = document.createElement('span');
|
const pagePreview = document.createElement("span");
|
||||||
pagePreview.className = 'bookmark-page-preview';
|
pagePreview.className = "bookmark-page-preview";
|
||||||
pagePreview.textContent = `Page ${bookmark.pageNumber}`;
|
pagePreview.textContent = `Page ${bookmark.pageNumber}`;
|
||||||
headerLeft.appendChild(pagePreview);
|
headerLeft.appendChild(pagePreview);
|
||||||
|
|
||||||
// Right side of header with action buttons
|
// Right side of header with action buttons
|
||||||
const headerRight = document.createElement('div');
|
const headerRight = document.createElement("div");
|
||||||
headerRight.className = 'bookmark-actions-header';
|
headerRight.className = "bookmark-actions-header";
|
||||||
|
|
||||||
// Quick add buttons with clear visual distinction - using Stirling-PDF's tooltip system
|
// Quick add buttons with clear visual distinction - using Stirling-PDF's tooltip system
|
||||||
const quickAddChildButton = createButton('subdirectory_arrow_right', 'btn-add-child', 'Add child bookmark', function(e) {
|
const quickAddChildButton = createButton("subdirectory_arrow_right", "btn-add-child", "Add child bookmark", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
addBookmark(bookmark.id);
|
addBookmark(bookmark.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
const quickAddSiblingButton = createButton('add', 'btn-add-sibling', 'Add sibling bookmark', function(e) {
|
const quickAddSiblingButton = createButton("add", "btn-add-sibling", "Add sibling bookmark", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
// Find parent of current bookmark
|
// Find parent of current bookmark
|
||||||
const parentId = findParentBookmark(bookmarks, bookmark.id);
|
const parentId = findParentBookmark(bookmarks, bookmark.id);
|
||||||
addBookmark(parentId, '', bookmark.pageNumber); // Same level as current bookmark
|
addBookmark(parentId, "", bookmark.pageNumber); // Same level as current bookmark
|
||||||
});
|
});
|
||||||
|
|
||||||
// Quick remove button
|
// Quick remove button
|
||||||
const quickRemoveButton = createButton('delete', 'btn-outline-danger', 'Remove bookmark', function(e) {
|
const quickRemoveButton = createButton("delete", "btn-outline-danger", "Remove bookmark", function (e) {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
e.stopPropagation();
|
e.stopPropagation();
|
||||||
|
|
||||||
if (confirm('Are you sure you want to remove this bookmark' +
|
if (
|
||||||
(bookmark.children.length > 0 ? ' and all its children?' : '?'))) {
|
confirm(
|
||||||
|
"Are you sure you want to remove this bookmark" + (bookmark.children.length > 0 ? " and all its children?" : "?")
|
||||||
|
)
|
||||||
|
) {
|
||||||
removeBookmark(bookmark.id);
|
removeBookmark(bookmark.id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -450,9 +453,9 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
header.appendChild(headerRight);
|
header.appendChild(headerRight);
|
||||||
|
|
||||||
// Add click handler for expansion toggle
|
// Add click handler for expansion toggle
|
||||||
header.addEventListener('click', function(e) {
|
header.addEventListener("click", function (e) {
|
||||||
// Only toggle if not clicking on buttons
|
// Only toggle if not clicking on buttons
|
||||||
if (!e.target.closest('button')) {
|
if (!e.target.closest("button")) {
|
||||||
toggleBookmarkExpanded(bookmark.id);
|
toggleBookmarkExpanded(bookmark.id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -461,8 +464,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createInputRow(bookmark) {
|
function createInputRow(bookmark) {
|
||||||
const row = document.createElement('div');
|
const row = document.createElement("div");
|
||||||
row.className = 'row';
|
row.className = "row";
|
||||||
|
|
||||||
// Title input
|
// Title input
|
||||||
row.appendChild(createTitleInputElement(bookmark));
|
row.appendChild(createTitleInputElement(bookmark));
|
||||||
@ -474,26 +477,26 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createTitleInputElement(bookmark) {
|
function createTitleInputElement(bookmark) {
|
||||||
const titleCol = document.createElement('div');
|
const titleCol = document.createElement("div");
|
||||||
titleCol.className = 'col-md-8';
|
titleCol.className = "col-md-8";
|
||||||
|
|
||||||
const titleGroup = document.createElement('div');
|
const titleGroup = document.createElement("div");
|
||||||
titleGroup.className = 'mb-3';
|
titleGroup.className = "mb-3";
|
||||||
|
|
||||||
const titleLabel = document.createElement('label');
|
const titleLabel = document.createElement("label");
|
||||||
titleLabel.textContent = 'Title';
|
titleLabel.textContent = "Title";
|
||||||
titleLabel.className = 'form-label';
|
titleLabel.className = "form-label";
|
||||||
|
|
||||||
const titleInput = document.createElement('input');
|
const titleInput = document.createElement("input");
|
||||||
titleInput.type = 'text';
|
titleInput.type = "text";
|
||||||
titleInput.className = 'form-control bookmark-title';
|
titleInput.className = "form-control bookmark-title";
|
||||||
titleInput.value = bookmark.title;
|
titleInput.value = bookmark.title;
|
||||||
titleInput.addEventListener('input', function() {
|
titleInput.addEventListener("input", function () {
|
||||||
bookmark.title = this.value;
|
bookmark.title = this.value;
|
||||||
updateBookmarkData();
|
updateBookmarkData();
|
||||||
|
|
||||||
// Also update the preview in the header
|
// Also update the preview in the header
|
||||||
const header = titleInput.closest('.bookmark-item').querySelector('.bookmark-title-preview');
|
const header = titleInput.closest(".bookmark-item").querySelector(".bookmark-title-preview");
|
||||||
if (header) {
|
if (header) {
|
||||||
header.textContent = this.value;
|
header.textContent = this.value;
|
||||||
}
|
}
|
||||||
@ -507,27 +510,27 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createPageInputElement(bookmark) {
|
function createPageInputElement(bookmark) {
|
||||||
const pageCol = document.createElement('div');
|
const pageCol = document.createElement("div");
|
||||||
pageCol.className = 'col-md-4';
|
pageCol.className = "col-md-4";
|
||||||
|
|
||||||
const pageGroup = document.createElement('div');
|
const pageGroup = document.createElement("div");
|
||||||
pageGroup.className = 'mb-3';
|
pageGroup.className = "mb-3";
|
||||||
|
|
||||||
const pageLabel = document.createElement('label');
|
const pageLabel = document.createElement("label");
|
||||||
pageLabel.textContent = 'Page';
|
pageLabel.textContent = "Page";
|
||||||
pageLabel.className = 'form-label';
|
pageLabel.className = "form-label";
|
||||||
|
|
||||||
const pageInput = document.createElement('input');
|
const pageInput = document.createElement("input");
|
||||||
pageInput.type = 'number';
|
pageInput.type = "number";
|
||||||
pageInput.className = 'form-control bookmark-page';
|
pageInput.className = "form-control bookmark-page";
|
||||||
pageInput.value = bookmark.pageNumber;
|
pageInput.value = bookmark.pageNumber;
|
||||||
pageInput.min = 1;
|
pageInput.min = 1;
|
||||||
pageInput.addEventListener('input', function() {
|
pageInput.addEventListener("input", function () {
|
||||||
bookmark.pageNumber = parseInt(this.value) || 1;
|
bookmark.pageNumber = parseInt(this.value) || 1;
|
||||||
updateBookmarkData();
|
updateBookmarkData();
|
||||||
|
|
||||||
// Also update the preview in the header
|
// Also update the preview in the header
|
||||||
const header = pageInput.closest('.bookmark-item').querySelector('.bookmark-page-preview');
|
const header = pageInput.closest(".bookmark-item").querySelector(".bookmark-page-preview");
|
||||||
if (header) {
|
if (header) {
|
||||||
header.textContent = `Page ${bookmark.pageNumber}`;
|
header.textContent = `Page ${bookmark.pageNumber}`;
|
||||||
}
|
}
|
||||||
@ -541,25 +544,25 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createButton(icon, className, title, clickHandler) {
|
function createButton(icon, className, title, clickHandler) {
|
||||||
const button = document.createElement('button');
|
const button = document.createElement("button");
|
||||||
button.type = 'button';
|
button.type = "button";
|
||||||
button.className = `btn ${className} btn-bookmark-action`;
|
button.className = `btn ${className} btn-bookmark-action`;
|
||||||
button.innerHTML = `<span class="material-symbols-rounded">${icon}</span>`;
|
button.innerHTML = `<span class="material-symbols-rounded">${icon}</span>`;
|
||||||
|
|
||||||
// Use Bootstrap tooltips
|
// Use Bootstrap tooltips
|
||||||
button.setAttribute('data-bs-toggle', 'tooltip');
|
button.setAttribute("data-bs-toggle", "tooltip");
|
||||||
button.setAttribute('data-bs-placement', 'top');
|
button.setAttribute("data-bs-placement", "top");
|
||||||
button.title = title;
|
button.title = title;
|
||||||
|
|
||||||
button.addEventListener('click', clickHandler);
|
button.addEventListener("click", clickHandler);
|
||||||
return button;
|
return button;
|
||||||
}
|
}
|
||||||
|
|
||||||
function createChildrenContainer(bookmark, level) {
|
function createChildrenContainer(bookmark, level) {
|
||||||
const childrenContainer = document.createElement('div');
|
const childrenContainer = document.createElement("div");
|
||||||
childrenContainer.className = 'bookmark-children';
|
childrenContainer.className = "bookmark-children";
|
||||||
|
|
||||||
bookmark.children.forEach(child => {
|
bookmark.children.forEach((child) => {
|
||||||
childrenContainer.appendChild(createBookmarkElement(child, level + 1));
|
childrenContainer.appendChild(createBookmarkElement(child, level + 1));
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -568,24 +571,24 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
|
|
||||||
// Update the add bookmark button appearance with clear visual cue
|
// Update the add bookmark button appearance with clear visual cue
|
||||||
addBookmarkBtn.innerHTML = '<span class="material-symbols-rounded">add</span> Add Top-level Bookmark';
|
addBookmarkBtn.innerHTML = '<span class="material-symbols-rounded">add</span> Add Top-level Bookmark';
|
||||||
addBookmarkBtn.className = 'btn btn-primary btn-add-bookmark top-level';
|
addBookmarkBtn.className = "btn btn-primary btn-add-bookmark top-level";
|
||||||
|
|
||||||
// Use Bootstrap tooltips
|
// Use Bootstrap tooltips
|
||||||
addBookmarkBtn.setAttribute('data-bs-toggle', 'tooltip');
|
addBookmarkBtn.setAttribute("data-bs-toggle", "tooltip");
|
||||||
addBookmarkBtn.setAttribute('data-bs-placement', 'top');
|
addBookmarkBtn.setAttribute("data-bs-placement", "top");
|
||||||
addBookmarkBtn.title = 'Add a new top-level bookmark';
|
addBookmarkBtn.title = "Add a new top-level bookmark";
|
||||||
|
|
||||||
// Add icon to empty state button as well
|
// Add icon to empty state button as well
|
||||||
const updateEmptyStateButton = function() {
|
const updateEmptyStateButton = function () {
|
||||||
const emptyStateBtn = document.querySelector('.btn-add-first-bookmark');
|
const emptyStateBtn = document.querySelector(".btn-add-first-bookmark");
|
||||||
if (emptyStateBtn) {
|
if (emptyStateBtn) {
|
||||||
emptyStateBtn.innerHTML = '<span class="material-symbols-rounded">add</span> Add First Bookmark';
|
emptyStateBtn.innerHTML = '<span class="material-symbols-rounded">add</span> Add First Bookmark';
|
||||||
emptyStateBtn.setAttribute('data-bs-toggle', 'tooltip');
|
emptyStateBtn.setAttribute("data-bs-toggle", "tooltip");
|
||||||
emptyStateBtn.setAttribute('data-bs-placement', 'top');
|
emptyStateBtn.setAttribute("data-bs-placement", "top");
|
||||||
emptyStateBtn.title = 'Add first bookmark';
|
emptyStateBtn.title = "Add first bookmark";
|
||||||
|
|
||||||
// Initialize tooltips for the empty state button
|
// Initialize tooltips for the empty state button
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== "undefined") {
|
||||||
$('[data-bs-toggle="tooltip"]').tooltip();
|
$('[data-bs-toggle="tooltip"]').tooltip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -601,8 +604,8 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
function flashButtonSuccess(button) {
|
function flashButtonSuccess(button) {
|
||||||
const originalClass = button.className;
|
const originalClass = button.className;
|
||||||
|
|
||||||
button.classList.remove('btn-outline-primary');
|
button.classList.remove("btn-outline-primary");
|
||||||
button.classList.add('btn-success', 'success-flash');
|
button.classList.add("btn-success", "success-flash");
|
||||||
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
button.className = originalClass;
|
button.className = originalClass;
|
||||||
@ -610,7 +613,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function importBookmarkStringFromClipboard() {
|
async function importBookmarkStringFromClipboard() {
|
||||||
const button = document.getElementById('importBookmarksBtn');
|
const button = document.getElementById("importBookmarksBtn");
|
||||||
try {
|
try {
|
||||||
const newBookmarkDataString = await navigator.clipboard.readText();
|
const newBookmarkDataString = await navigator.clipboard.readText();
|
||||||
const newBookmarkData = JSON.parse(newBookmarkDataString);
|
const newBookmarkData = JSON.parse(newBookmarkDataString);
|
||||||
@ -629,7 +632,7 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function exportBookmarkStringToClipboard() {
|
async function exportBookmarkStringToClipboard() {
|
||||||
const button = document.getElementById('exportBookmarksBtn');
|
const button = document.getElementById("exportBookmarksBtn");
|
||||||
const bookmarkData = bookmarkDataInput.value;
|
const bookmarkData = bookmarkDataInput.value;
|
||||||
try {
|
try {
|
||||||
await navigator.clipboard.writeText(bookmarkData);
|
await navigator.clipboard.writeText(bookmarkData);
|
||||||
@ -640,25 +643,25 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add event listeners for import/export buttons
|
// Add event listeners for import/export buttons
|
||||||
const importBookmarksBtn = document.getElementById('importBookmarksBtn');
|
const importBookmarksBtn = document.getElementById("importBookmarksBtn");
|
||||||
const exportBookmarksBtn = document.getElementById('exportBookmarksBtn');
|
const exportBookmarksBtn = document.getElementById("exportBookmarksBtn");
|
||||||
importBookmarksBtn.addEventListener('click', importBookmarkStringFromClipboard);
|
importBookmarksBtn.addEventListener("click", importBookmarkStringFromClipboard);
|
||||||
exportBookmarksBtn.addEventListener('click', exportBookmarkStringToClipboard);
|
exportBookmarksBtn.addEventListener("click", exportBookmarkStringToClipboard);
|
||||||
|
|
||||||
// display import/export buttons if supported
|
// display import/export buttons if supported
|
||||||
if (navigator.clipboard && navigator.clipboard.writeText && navigator.clipboard.readText) {
|
if (navigator.clipboard && navigator.clipboard.writeText && navigator.clipboard.readText) {
|
||||||
importBookmarksBtn.classList.remove('d-none');
|
importBookmarksBtn.classList.remove("d-none");
|
||||||
exportBookmarksBtn.classList.remove('d-none');
|
exportBookmarksBtn.classList.remove("d-none");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Listen for theme changes to update badge colors
|
// Listen for theme changes to update badge colors
|
||||||
const observer = new MutationObserver(function(mutations) {
|
const observer = new MutationObserver(function (mutations) {
|
||||||
mutations.forEach(function(mutation) {
|
mutations.forEach(function (mutation) {
|
||||||
if (mutation.attributeName === 'data-bs-theme') {
|
if (mutation.attributeName === "data-bs-theme") {
|
||||||
const isDarkMode = document.documentElement.getAttribute('data-bs-theme') === 'dark';
|
const isDarkMode = document.documentElement.getAttribute("data-bs-theme") === "dark";
|
||||||
document.querySelectorAll('.badge').forEach(badge => {
|
document.querySelectorAll(".badge").forEach((badge) => {
|
||||||
badge.classList.remove('bg-secondary', 'bg-info');
|
badge.classList.remove("bg-secondary", "bg-info");
|
||||||
badge.classList.add(isDarkMode ? 'bg-info' : 'bg-secondary');
|
badge.classList.add(isDarkMode ? "bg-info" : "bg-secondary");
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -667,26 +670,26 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
observer.observe(document.documentElement, { attributes: true });
|
observer.observe(document.documentElement, { attributes: true });
|
||||||
|
|
||||||
// Add visual enhancement to clearly show the top-level/child relationship
|
// Add visual enhancement to clearly show the top-level/child relationship
|
||||||
document.addEventListener('mouseover', function(e) {
|
document.addEventListener("mouseover", function (e) {
|
||||||
// When hovering over add buttons, highlight their relationship targets
|
// When hovering over add buttons, highlight their relationship targets
|
||||||
const button = e.target.closest('.btn-add-child, .btn-add-sibling');
|
const button = e.target.closest(".btn-add-child, .btn-add-sibling");
|
||||||
if (button) {
|
if (button) {
|
||||||
if (button.classList.contains('btn-add-child')) {
|
if (button.classList.contains("btn-add-child")) {
|
||||||
// Highlight parent-child relationship
|
// Highlight parent-child relationship
|
||||||
const bookmarkItem = button.closest('.bookmark-item');
|
const bookmarkItem = button.closest(".bookmark-item");
|
||||||
if (bookmarkItem) {
|
if (bookmarkItem) {
|
||||||
bookmarkItem.style.boxShadow = '0 0 0 2px var(--btn-add-child-border, #198754)';
|
bookmarkItem.style.boxShadow = "0 0 0 2px var(--btn-add-child-border, #198754)";
|
||||||
}
|
}
|
||||||
} else if (button.classList.contains('btn-add-sibling')) {
|
} else if (button.classList.contains("btn-add-sibling")) {
|
||||||
// Highlight sibling relationship
|
// Highlight sibling relationship
|
||||||
const bookmarkItem = button.closest('.bookmark-item');
|
const bookmarkItem = button.closest(".bookmark-item");
|
||||||
if (bookmarkItem) {
|
if (bookmarkItem) {
|
||||||
// Find siblings
|
// Find siblings
|
||||||
const parent = bookmarkItem.parentElement;
|
const parent = bookmarkItem.parentElement;
|
||||||
const siblings = parent.querySelectorAll(':scope > .bookmark-item');
|
const siblings = parent.querySelectorAll(":scope > .bookmark-item");
|
||||||
siblings.forEach(sibling => {
|
siblings.forEach((sibling) => {
|
||||||
if (sibling !== bookmarkItem) {
|
if (sibling !== bookmarkItem) {
|
||||||
sibling.style.boxShadow = '0 0 0 2px var(--btn-add-sibling-border, #0d6efd)';
|
sibling.style.boxShadow = "0 0 0 2px var(--btn-add-sibling-border, #0d6efd)";
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -694,13 +697,13 @@ document.addEventListener('DOMContentLoaded', function() {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
document.addEventListener('mouseout', function(e) {
|
document.addEventListener("mouseout", function (e) {
|
||||||
// Remove highlights when not hovering
|
// Remove highlights when not hovering
|
||||||
const button = e.target.closest('.btn-add-child, .btn-add-sibling');
|
const button = e.target.closest(".btn-add-child, .btn-add-sibling");
|
||||||
if (button) {
|
if (button) {
|
||||||
// Remove all highlights
|
// Remove all highlights
|
||||||
document.querySelectorAll('.bookmark-item').forEach(item => {
|
document.querySelectorAll(".bookmark-item").forEach((item) => {
|
||||||
item.style.boxShadow = '';
|
item.style.boxShadow = "";
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1,93 +1,123 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html th:lang="${#locale.language}" th:dir="#{language.direction}" th:data-language="${#locale.toString()}"
|
<html th:lang="${#locale.language}"
|
||||||
|
th:dir="#{language.direction}"
|
||||||
|
th:data-language="${#locale.toString()}"
|
||||||
xmlns:th="https://www.thymeleaf.org">
|
xmlns:th="https://www.thymeleaf.org">
|
||||||
|
|
||||||
<head>
|
<head>
|
||||||
<th:block th:insert="~{fragments/common :: head(title=#{editTableOfContents.title}, header=#{editTableOfContents.header})}">
|
<th:block
|
||||||
</th:block>
|
th:insert="~{fragments/common :: head(title=#{editTableOfContents.title}, header=#{editTableOfContents.header})}">
|
||||||
<link rel="stylesheet" th:href="@{'/css/edit-table-of-contents.css'}">
|
</th:block>
|
||||||
</head>
|
<link rel="stylesheet"
|
||||||
|
th:href="@{'/css/edit-table-of-contents.css'}">
|
||||||
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="page-container">
|
<div id="page-container">
|
||||||
<div id="content-wrap">
|
<div id="content-wrap">
|
||||||
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
<th:block th:insert="~{fragments/navbar.html :: navbar}"></th:block>
|
||||||
<br><br>
|
<br><br>
|
||||||
<div class="container">
|
<div class="container">
|
||||||
<div class="row justify-content-center">
|
<div class="row justify-content-center">
|
||||||
<div class="col-md-8 bg-card">
|
<div class="col-md-8 bg-card">
|
||||||
<div class="tool-header">
|
<div class="tool-header">
|
||||||
<span class="material-symbols-rounded tool-header-icon edit">bookmark_add</span>
|
<span class="material-symbols-rounded tool-header-icon edit">bookmark_add</span>
|
||||||
<span class="tool-header-text" th:text="#{editTableOfContents.header}"></span>
|
<span class="tool-header-text"
|
||||||
</div>
|
th:text="#{editTableOfContents.header}"></span>
|
||||||
<form th:action="@{'/api/v1/general/edit-table-of-contents'}" method="post" enctype="multipart/form-data" id="editTocForm">
|
|
||||||
<div
|
|
||||||
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}">
|
|
||||||
</div>
|
</div>
|
||||||
|
<form th:action="@{'/api/v1/general/edit-table-of-contents'}"
|
||||||
<div class="mb-3 form-check">
|
method="post"
|
||||||
<input type="checkbox" class="form-check-input" id="replaceExisting" name="replaceExisting" checked>
|
enctype="multipart/form-data"
|
||||||
<label class="form-check-label" for="replaceExisting"
|
id="editTocForm">
|
||||||
th:text="#{editTableOfContents.replaceExisting}"></label>
|
<div
|
||||||
<input type="hidden" name="replaceExisting" value="false" />
|
th:replace="~{fragments/common :: fileSelector(name='fileInput', multipleInputsForSingleRequest=false, accept='application/pdf')}">
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="bookmark-editor">
|
|
||||||
<h5 th:text="#{editTableOfContents.editorTitle}"></h5>
|
|
||||||
<p th:text="#{editTableOfContents.editorDesc}"></p>
|
|
||||||
|
|
||||||
<div id="bookmarks-container">
|
|
||||||
<!-- Bookmarks will be added here dynamically -->
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="bookmark-actions">
|
<div class="mb-3 form-check">
|
||||||
<button type="button" id="addBookmarkBtn" class="btn btn-outline-primary" th:text="#{editTableOfContents.addBookmark}"></button>
|
<input type="checkbox"
|
||||||
<div class="d-flex flex-wrap justify-content-end gap-2">
|
class="form-check-input"
|
||||||
<button type="button"
|
id="replaceExisting"
|
||||||
id="importBookmarksBtn"
|
name="replaceExisting"
|
||||||
class="d-none btn btn-outline-primary"
|
checked>
|
||||||
th:text="#{editTableOfContents.importBookmarks}"
|
<label class="form-check-label"
|
||||||
th:data-bs-original-title="#{editTableOfContents.importBookmarksHint}"
|
for="replaceExisting"
|
||||||
data-bs-toggle="tooltip"
|
th:text="#{editTableOfContents.replaceExisting}"></label>
|
||||||
data-bs-placement="top">
|
<input type="hidden"
|
||||||
</button>
|
name="replaceExisting"
|
||||||
<button type="button"
|
value="false" />
|
||||||
id="exportBookmarksBtn"
|
</div>
|
||||||
class="d-none btn btn-outline-primary"
|
|
||||||
th:text="#{editTableOfContents.exportBookmarks}"
|
<div class="bookmark-editor">
|
||||||
th:data-bs-original-title="#{editTableOfContents.exportBookmarksHint}"
|
<h5 th:text="#{editTableOfContents.editorTitle}"></h5>
|
||||||
data-bs-toggle="tooltip"
|
<p th:text="#{editTableOfContents.editorDesc}"></p>
|
||||||
data-bs-placement="top">
|
|
||||||
</button>
|
<div id="bookmarks-container">
|
||||||
|
<!-- Bookmarks will be added here dynamically -->
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="bookmark-actions">
|
||||||
|
<button type="button"
|
||||||
|
id="addBookmarkBtn"
|
||||||
|
class="btn btn-outline-primary"
|
||||||
|
th:text="#{editTableOfContents.addBookmark}"></button>
|
||||||
|
<div class="d-flex flex-wrap justify-content-end gap-2">
|
||||||
|
<button type="button"
|
||||||
|
id="importBookmarksBtn"
|
||||||
|
class="d-none btn btn-outline-primary"
|
||||||
|
th:text="#{editTableOfContents.importBookmarks}"
|
||||||
|
th:data-bs-original-title="#{editTableOfContents.importBookmarksHint}"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
data-bs-placement="top">
|
||||||
|
</button>
|
||||||
|
<button type="button"
|
||||||
|
id="exportBookmarksBtn"
|
||||||
|
class="d-none btn btn-outline-primary"
|
||||||
|
th:text="#{editTableOfContents.exportBookmarks}"
|
||||||
|
th:data-bs-original-title="#{editTableOfContents.exportBookmarksHint}"
|
||||||
|
data-bs-toggle="tooltip"
|
||||||
|
data-bs-placement="top">
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- Hidden field to store JSON data -->
|
||||||
|
<input type="hidden"
|
||||||
|
id="bookmarkData"
|
||||||
|
name="bookmarkData"
|
||||||
|
value="[]">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Hidden field to store JSON data -->
|
|
||||||
<input type="hidden" id="bookmarkData" name="bookmarkData" value="[]">
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<a class="btn btn-outline-primary" data-bs-toggle="collapse" href="#info" role="button"
|
<a class="btn btn-outline-primary"
|
||||||
aria-expanded="false" aria-controls="info" th:text="#{info}"></a>
|
data-bs-toggle="collapse"
|
||||||
</p>
|
href="#info"
|
||||||
<div class="collapse" id="info">
|
role="button"
|
||||||
<p th:text="#{editTableOfContents.desc.1}"></p>
|
aria-expanded="false"
|
||||||
<p th:text="#{editTableOfContents.desc.2}"></p>
|
aria-controls="info"
|
||||||
<p th:text="#{editTableOfContents.desc.3}"></p>
|
th:text="#{info}"></a>
|
||||||
</div>
|
</p>
|
||||||
|
<div class="collapse"
|
||||||
|
id="info">
|
||||||
|
<p th:text="#{editTableOfContents.desc.1}"></p>
|
||||||
|
<p th:text="#{editTableOfContents.desc.2}"></p>
|
||||||
|
<p th:text="#{editTableOfContents.desc.3}"></p>
|
||||||
|
</div>
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<button type="submit" id="submitBtn" class="btn btn-primary" th:text="#{editTableOfContents.submit}"></button>
|
<button type="submit"
|
||||||
</form>
|
id="submitBtn"
|
||||||
|
class="btn btn-primary"
|
||||||
|
th:text="#{editTableOfContents.submit}"></button>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
||||||
</div>
|
</div>
|
||||||
<th:block th:insert="~{fragments/footer.html :: footer}"></th:block>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script th:src="@{'/js/pages/edit-table-of-contents.js'}"></script>
|
<script th:src="@{'/js/pages/edit-table-of-contents.js'}"></script>
|
||||||
<script>
|
<script>
|
||||||
document.addEventListener('DOMContentLoaded', function() {
|
document.addEventListener('DOMContentLoaded', function() {
|
||||||
// Initialize Bootstrap tooltips
|
// Initialize Bootstrap tooltips
|
||||||
if (typeof $ !== 'undefined') {
|
if (typeof $ !== 'undefined') {
|
||||||
@ -95,6 +125,6 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
Loading…
Reference in New Issue
Block a user