added "manage bookmarks" menu + moved section/link controls. need to make link deletion + reordering next

This commit is contained in:
2025-07-09 21:55:27 -04:00
parent cb36a17254
commit 58b34bb07a
+206 -128
View File
@@ -115,7 +115,7 @@
.expandableMenuToggle { .expandableMenuToggle {
cursor: pointer; cursor: pointer;
padding: 18px; padding: 0px 18px;
width: 100%; width: 100%;
} }
.expandableMenuToggle.active, .expandableMenuToggle:hover { .expandableMenuToggle.active, .expandableMenuToggle:hover {
@@ -135,6 +135,10 @@
font-style: italic; font-style: italic;
} }
hr {
width: 75%;
}
#editToggle { #editToggle {
z-index: 999; z-index: 999;
position: fixed; position: fixed;
@@ -144,19 +148,6 @@
cursor: pointer; cursor: pointer;
} }
.hiddenButton {
display: inline;
visibility: visible;
font-style: italic;
}
.hiddenButton.hidden {
visibility: hidden;
display: none;
}
.hiddenButton:hover {
cursor: pointer;
}
#imageRemovalWarning { #imageRemovalWarning {
color: red; color: red;
size: 3rem; size: 3rem;
@@ -407,7 +398,7 @@
headerBold: false, headerBold: false,
headerItalic: false, headerItalic: false,
disableDivider: false, enableDivider: true,
dividerColor: "", dividerColor: "",
centerAlign: false, centerAlign: false,
shadowX: "0", shadowX: "0",
@@ -439,7 +430,7 @@
clockSize: "16", clockSize: "16",
clockBold: false, clockBold: false,
clockItalic: false, clockItalic: false,
disableDivider: false, enableDivider: false,
dividerColor: "", dividerColor: "",
centerAlign: false, centerAlign: false,
shadowX: "0", shadowX: "0",
@@ -498,7 +489,7 @@
* ensure there are no brackets in the name * ensure there are no brackets in the name
*/ */
this.name = name; this.name = name;
this.id = name.replace(" ", "-"); this.id = name.replace(" ", "-").toLowerCase();
// if initializing saved container content, // if initializing saved container content,
if (x !== undefined && y !== undefined) { if (x !== undefined && y !== undefined) {
@@ -523,13 +514,11 @@
this.initializeNewImageContainer(); this.initializeNewImageContainer();
} }
// apply bookmarks
this.loadBookmarks(); this.loadBookmarks();
// then create container options UI in settings menu
this.insertContainerSettingsListing();
this.applyContainerSettings();
// establish necessary event listeners this.createSettingsMenuListing();
this.applySettings();
this.addContainerEventListeners() this.addContainerEventListeners()
this.addSettingsMenuEventListeners(); this.addSettingsMenuEventListeners();
@@ -541,7 +530,7 @@
/** /**
* creates a basic container shell and lets * creates a basic container shell and lets
* loadBookmarks() and applyContainerSettings() do the rest * loadBookmarks() and applySettings() do the rest
*/ */
loadSavedContainer() { loadSavedContainer() {
document.body.insertAdjacentHTML( document.body.insertAdjacentHTML(
@@ -693,18 +682,98 @@
* rename settings form div ids (see "note to self") * rename settings form div ids (see "note to self")
*/ */
loadBookmarkListings() {
if (Object.keys(this.sections).length == 0) {
return;
}
insertContainerSettingsListing() { let sectionData = Object.values(this.sections);
let containerSettings = this.containerSettings;
let bookmarkListings = document.getElementById(this.id + "-bookmark-listings");
console.log(sectionData);
// [re]render the section listings
bookmarkListings.innerHTML = "";
for (let i = 0; i < sectionData.length; i++) {
console.log(i);
bookmarkListings.insertAdjacentHTML(
"beforeend",
`
${i == 0 ? "" : `<br />`}
<div id="${this.id}-section-listing-${i}">
<span onClick="deleteSection(this)">
[X]
</span>
<span class=${this.id + "-section-listing"}>
${sectionData[i].label}
</span>
${i > 1 ? `
<span onClick="reorderSection(this, 'up')">
[up]
</span>
` : ``}
${i > 0 ? `
<span onClick="reorderSection(this, 'down')">
[down]
</span>
` : ``}
</div>
`
);
}
// [re]render the link listings
for (let s = 0; s < sectionData.length; s++) {
for (let l = 0; l < sectionData[s].links.length; l++) {
console.log('s: ' + s);
let targetSection = document.getElementById(
this.id + "-section-listing-" + s
);
targetSection.insertAdjacentHTML(
"beforeend",
`
<div id="${this.id}-section-${s}-link-${l}-listing" >
<span onClick="deleteLink(this)">
[X]
</span>
<a
class="${this.id}-link"
href="${sectionData[s].links[l].url}"
>
${sectionData[s].links[l].label}
</a>
</div>
`
);
}
}
}
createSettingsMenuListing() {
document.getElementById("containers").insertAdjacentHTML( document.getElementById("containers").insertAdjacentHTML(
"beforeend", "beforeend",
` `
<div class="containerListing" id=${this.id + "-container-listing"}> <div class="containerListing" id=${this.id + "-container-listing"}>
<p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">- ${this.name}</p> <p class="expandableMenuToggle active" onclick="toggleExpandableMenu(this)">- ${this.name}</p>
<div class="expandableMenu" id=${this.id + "-settings-menu"} style="display: block;"> <div class="expandableMenu" id=${this.id + "-settings-menu"} style="display: block;">
<p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">+ ${this.id}: bookmarks</h1> <p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">+ ${this.name}: bookmarks</p>
<div class="expandableMenu" id=${this.id + "-bookmark-menu"} > <div class="expandableMenu" id=${this.id + "-bookmark-menu"} >
<p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">+ manage bookmarks / sections</p>
<div class="expandableMenu" id=${this.id + "-bookmark-listings"} >
${Object.keys(this.sections).length == 0 ? `<p>(no bookmarks)</p>` : ``}
</div>
<p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">+ add new bookmarks / sections</p>
<div class="expandableMenu" id=${this.id + "-add-bookmark-menu"} >
<label> enter url: </label> <label> enter url: </label>
<input id=${this.id + "-url-input"} type="text" name="url" /> <input id=${this.id + "-url-input"} type="text" name="url" />
@@ -719,9 +788,50 @@
<button id=${this.id + "-add-link-button"} onclick="addLink(this)">add link</button> <button id=${this.id + "-add-link-button"} onclick="addLink(this)">add link</button>
</div> </div>
</div>
<p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">+ ${this.id}: customize bookmarks</p>
<p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">+ ${this.name}: customize</p>
<div class="expandableMenu"> <div class="expandableMenu">
<p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">+ ${this.name}: header options</p>
<div class="expandableMenu">
<p class="menuHeader">date + time options</p>
<label for=${this.id + "-settings-date-toggle"}>show date?</label>
<input id=${this.id + "-settings-date-toggle"} type="checkbox" />
<br />
<label>show clock?</label>
<input id=${this.id + "-settings-clock-toggle"} type="checkbox" />
<br /><br />
<p class="menuHeader">divider options</p>
<label for=${this.id + "-settings-divider-toggle"}>show divider?</label>
<input id=${this.id + "-settings-divider-toggle"} type="checkbox" />
<br />
<label>set divider color: </label>
<input id=${this.id + "-settings-divider-color"} type="color" />
</div>
<p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">+ ${this.name}: text options</p>
<div class="expandableMenu">
<p class="menuHeader">header text options</p>
<label>set header text color: </label>
<input id=${this.id + "-settings-clock-color"} type="color" />
<br /><br />
<label>set header font size (px): </label>
<input id=${this.id + "-settings-clock-size"} />
<br />
<label for=${this.id + "-settings-clock-bold"}>bold header?</label>
<input id=${this.id + "-settings-clock-bold"} type="checkbox" />
<label for=${this.id + "-settings-clock-italic"}>italic header?</label>
<input id=${this.id + "-settings-clock-italic"} type="checkbox" />
<p class="menuHeader">section text options</p> <p class="menuHeader">section text options</p>
<label>set section size (px): </label> <label>set section size (px): </label>
<input id=${this.id + "-settings-section-size"} /> <input id=${this.id + "-settings-section-size"} />
@@ -741,39 +851,8 @@
<label>set link color: </label> <label>set link color: </label>
<input id=${this.id + "-settings-link-color"} type="color" /> <input id=${this.id + "-settings-link-color"} type="color" />
</div>
<p class="menuHeader">layer-wide options</p>
<p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">+ ${this.id}: customize layer</p>
<div class="expandableMenu">
<p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">+ ${this.id}: header settings</p>
<div class="expandableMenu">
<label>show date?</label>
<input id=${this.id + "-settings-date-toggle"} type="checkbox" />
<br />
<label>show clock?</label>
<input id=${this.id + "-settings-clock-toggle"} type="checkbox" />
<br /><br />
<label>set header text color: </label>
<input id=${this.id + "-settings-clock-color"} type="color" />
<br /><br />
<label>set header font size (px): </label>
<input id=${this.id + "-settings-clock-size"} />
<br />
<label for=${this.id + "-settings-clock-bold"}>bold header?</label>
<input id=${this.id + "-settings-clock-bold"} type="checkbox" />
<label for=${this.id + "-settings-clock-italic"}>italic header?</label>
<input id=${this.id + "-settings-clock-italic"} type="checkbox" />
</div>
<p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">+ ${this.id}: text settings</p>
<div class="expandableMenu">
<label>change font (see instructions for more info):</label> <label>change font (see instructions for more info):</label>
<input id=${this.id + "-settings-font-input"} /> <input id=${this.id + "-settings-font-input"} />
<button id=${this.id + "-settings-set-font-button"}>set font</button> <button id=${this.id + "-settings-set-font-button"}>set font</button>
@@ -790,10 +869,10 @@
<input id=${this.id + "-settings-center-align"} type="radio" name="align" /> <input id=${this.id + "-settings-center-align"} type="radio" name="align" />
</div> </div>
<p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">+ ${this.id}: color + shape settings</p> <p class="expandableMenuToggle" onclick="toggleExpandableMenu(this)">+ ${this.name}: color + shape options</p>
<div class="expandableMenu"> <div class="expandableMenu">
<p class="menuHeader">layer background options</p> <p class="menuHeader">background color</p>
<label>set background color: </label> <label>set background color: </label>
<input id=${this.id + "-settings-bg-color"} type="color" /> <input id=${this.id + "-settings-bg-color"} type="color" />
@@ -810,13 +889,6 @@
<label>set container roundedness (px): </label> <label>set container roundedness (px): </label>
<input id=${this.id + "-settings-border-radius"} placeholder="0 for square" /> <input id=${this.id + "-settings-border-radius"} placeholder="0 for square" />
<p class="menuHeader">change divider</p>
<label for=${this.id + "-settings-divider-toggle"}>disable divider: </label>
<input id=${this.id + "-settings-divider-toggle"} type="checkbox" />
<label>set divider color: </label>
<input id=${this.id + "-settings-divider-color"} type="color" />
<p class="menuHeader">change shadow / glow</p> <p class="menuHeader">change shadow / glow</p>
shadow settings:<br /> shadow settings:<br />
<label>x-offset (px): </label><br /> <label>x-offset (px): </label><br />
@@ -835,13 +907,14 @@
</div> </div>
` `
); );
this.loadBookmarkListings();
} }
/* /*
* applies saved cosmetic customizations to container * applies saved cosmetic customizations to container
*/ */
applyContainerSettings() { applySettings() {
/** set options relevant to both image and text containers */ /** set options relevant to both image and text containers */
/** POSITION */ /** POSITION */
document.getElementById(this.id).style.top = this.y; document.getElementById(this.id).style.top = this.y;
@@ -1016,7 +1089,7 @@
/** DIVIDER */ /** DIVIDER */
let divider = document.getElementById(this.id + "-divider"); let divider = document.getElementById(this.id + "-divider");
if (containerSettings.disableDivider) { if (!containerSettings.enableDivider) {
document.getElementById(this.id + "-divider").hidden = true; document.getElementById(this.id + "-divider").hidden = true;
// if there are links in this container, add room under the divider // if there are links in this container, add room under the divider
if (Object.keys(this.sections).length > 0) { if (Object.keys(this.sections).length > 0) {
@@ -1030,7 +1103,7 @@
} }
// fill-in settings ui // fill-in settings ui
document.getElementById(this.id + "-settings-divider-toggle").checked = document.getElementById(this.id + "-settings-divider-toggle").checked =
containerSettings.disableDivider; containerSettings.enableDivider;
document.getElementById(this.id + "-settings-divider-color").value = document.getElementById(this.id + "-settings-divider-color").value =
containerSettings.dividerColor; containerSettings.dividerColor;
} }
@@ -1135,7 +1208,7 @@
// container divider setting listeners // container divider setting listeners
document document
.getElementById(this.id + "-settings-divider-toggle") .getElementById(this.id + "-settings-divider-toggle")
.addEventListener("change", disableDivider, false); .addEventListener("change", toggleDivider, false);
document document
.getElementById(this.id + "-settings-divider-color") .getElementById(this.id + "-settings-divider-color")
.addEventListener("input", changeDividerColor, false); .addEventListener("input", changeDividerColor, false);
@@ -1158,48 +1231,45 @@
} }
/** /**
* [re]loads saved bookmark sections + links for container * [re]renders saved bookmark sections + links for container
*/ */
loadBookmarks() { loadBookmarks() {
let containerSettings = this.containerSettings;
let linkContainer = document.getElementById(this.id + "-sections");
linkContainer.innerHTML = "";
if (Object.keys(this.sections).length == 0) { if (Object.keys(this.sections).length == 0) {
return; return;
} }
let sectionData = Object.values(this.sections); let sectionData = Object.values(this.sections);
let containerSettings = this.containerSettings;
// render the sections let containerBookmarks = document.getElementById(this.id + "-sections");
containerBookmarks.innerHTML = "";
/* ensure uncategorized links (if any) stay at top
let noneSectionIndex;
for (let i = 0; i < sectionData.length; i++) { for (let i = 0; i < sectionData.length; i++) {
linkContainer.insertAdjacentHTML( if(sectionData[i].label == "") {
noneSectionIndex = i;
break;
}
}
if (noneSectionIndex != -1 && noneSectionIndex != 0) {
this.sections.splice(noneSectionIndex, 1);
this.sections.unshift("none");
}*/
for (let i = 0; i < sectionData.length; i++) {
containerBookmarks.insertAdjacentHTML(
"beforeend", "beforeend",
` `
${i == 0 ? "" : `<br />`} ${i == 0 ? "" : `<br />`}
<div id="${this.id}-section-${i}"> <div id="${this.id}-section-${i}">
<span
class="hiddenButton ${editing ? "" : "hidden"}"
onClick="deleteSection(this)"
>
[X]
</span>
<span class=${this.id + "-section"}> <span class=${this.id + "-section"}>
${sectionData[i].label} ${sectionData[i].label}
</span> </span>
<span
class="hiddenButton ${editing ? "" : "hidden"}"
onClick="reorderSection(this, 'up')"
>
[up]
</span>
<span
class="hiddenButton ${editing ? "" : "hidden"}"
onClick="reorderSection(this, 'down')"
>
[down]
</span>
</div> </div>
` `
); );
@@ -1216,12 +1286,6 @@
"beforeend", "beforeend",
` `
<div id="${this.id}-section-${s}-link-${l}" > <div id="${this.id}-section-${s}-link-${l}" >
<span
class="hiddenButton bookmark ${editing ? "" : "hidden"}"
onClick="deleteLink(this)"
>
[X]
</span>
<a <a
class="${this.id}-link" class="${this.id}-link"
@@ -1236,7 +1300,7 @@
} }
// ensure smooth ux when rerendering // ensure smooth ux when rerendering
if (containerSettings.disableDivider) { if (!containerSettings.enableDivider) {
document.getElementById(this.id + "-header").style.marginBottom = "18px"; document.getElementById(this.id + "-header").style.marginBottom = "18px";
} }
} }
@@ -1551,7 +1615,6 @@
function toggleEditingElements(show) { function toggleEditingElements(show) {
const editButton = document.getElementById("editToggle"); const editButton = document.getElementById("editToggle");
const settingsContainer = document.getElementById("settingsContainer"); const settingsContainer = document.getElementById("settingsContainer");
const hiddenButtons = document.getElementsByClassName("hiddenButton");
/** when editing-mode is enabled, */ /** when editing-mode is enabled, */
if (show) { if (show) {
@@ -1559,9 +1622,6 @@
// reveal settings container // reveal settings container
settingsContainer.classList.remove("hidden"); settingsContainer.classList.remove("hidden");
for (let i = 0; i < hiddenButtons.length; i++) {
hiddenButtons[i].classList.remove("hidden");
}
// change cursor on movable elements to indicate grabbable // change cursor on movable elements to indicate grabbable
let movableElements = document.getElementsByClassName("movable"); let movableElements = document.getElementsByClassName("movable");
@@ -1590,9 +1650,6 @@
// hide the settings container // hide the settings container
settingsContainer.classList.add("hidden"); settingsContainer.classList.add("hidden");
for (let i = 0; i < hiddenButtons.length; i++) {
hiddenButtons[i].classList.add("hidden");
}
} }
} }
@@ -1861,7 +1918,7 @@
let section = document.getElementById(containerId + "-section-input").value; let section = document.getElementById(containerId + "-section-input").value;
// sanitize input // sanitize input
if (!url.startsWith("http")) { if (url.length > 0 && !url.startsWith("http")) {
url = "https://" + url; // append HTTPS to link if needed url = "https://" + url; // append HTTPS to link if needed
} }
if (label == "" || url == "https://") { if (label == "" || url == "https://") {
@@ -1876,31 +1933,49 @@
sectionLabels.push(sectionData[i].label); sectionLabels.push(sectionData[i].label);
} }
let tempIndex = sectionLabels.indexOf(section); let sectionIndex = sectionLabels.indexOf(section);
// existing section // add link to existing section
if (tempIndex != -1) { if (sectionIndex != -1) {
let tempSectionLinks = Object.values(container.sections)[tempIndex].links; let tempSectionLinks = Object.values(container.sections)[sectionIndex].links;
tempSectionLinks.push({ tempSectionLinks.push({
label: label, label: label,
url: url url: url
}); });
} }
// creating new section // or create new section + add link
else { else {
let tempSectionLinks = []; let newSectionLinks = [];
tempSectionLinks.push({ newSectionLinks.push({
label: label, label: label,
url: url url: url
}); });
container.sections[sectionData.length] = {}
container.sections[sectionData.length].links = tempSectionLinks; // ensure that uncategorized links stay at top of container
if (section == "" && sectionData.length > 0) {
let reorderedSections = {};
reorderedSections[0] = {};
reorderedSections[0].links = newSectionLinks;
reorderedSections[0].label = section;
// move existing sections down
for (let i = 0; i < sectionData.length; i++) {
reorderedSections[i+1] = sectionData[i];
}
container.sections = reorderedSections;
}
else {
container.sections[sectionData.length] = {};
container.sections[sectionData.length].links = newSectionLinks;
container.sections[sectionData.length].label = section; container.sections[sectionData.length].label = section;
} }
}
// reset inputs + render // reset inputs + render
document.getElementById(containerId + "-url-input").value = ""; document.getElementById(containerId + "-url-input").value = "";
document.getElementById(containerId + "-label-input").value = ""; document.getElementById(containerId + "-label-input").value = "";
container.loadBookmarks(); container.loadBookmarks();
container.loadBookmarkListings();
} }
function reorderSection(buttonPressed, direction) { function reorderSection(buttonPressed, direction) {
@@ -1920,14 +1995,15 @@
} }
container.loadBookmarks(); container.loadBookmarks();
container.loadBookmarkListings();
} }
function deleteSection(buttonPressed) { function deleteSection(buttonPressed) {
let temp = buttonPressed.parentElement.id.split("-"); let temp = buttonPressed.parentElement.id.split("-");
let sectionId = parseInt(temp[temp.length - 1]); let sectionId = parseInt(temp[temp.length - 1]);
let container = containerDataMap.get(temp[0]); let container = containerDataMap.get(buttonPressed.parentElement.id.split("-section")[0]);
// go through sections, starting with one to delete // overwrite sections
let numSections = Object.keys(container.sections).length; let numSections = Object.keys(container.sections).length;
for (let i = sectionId; i < numSections; i++) { for (let i = sectionId; i < numSections; i++) {
container.sections[i] = container.sections[i+1]; container.sections[i] = container.sections[i+1];
@@ -1937,6 +2013,7 @@
// refresh screen // refresh screen
container.loadBookmarks(); container.loadBookmarks();
container.loadBookmarkListings();
} }
function deleteLink(buttonPressed) { function deleteLink(buttonPressed) {
@@ -2233,12 +2310,13 @@
divider.style.backgroundColor = container.containerSettings.dividerColor; divider.style.backgroundColor = container.containerSettings.dividerColor;
divider.style.borderColor = container.containerSettings.dividerColor; divider.style.borderColor = container.containerSettings.dividerColor;
} }
function disableDivider(checkboxChanged) { function toggleDivider(checkboxChanged) {
let containerId = checkboxChanged.target.id.split("-")[0]; let containerId = checkboxChanged.target.id.split("-")[0];
let container = containerDataMap.get(containerId); let container = containerDataMap.get(containerId);
container.containerSettings.disableDivider = checkboxChanged.target.checked; container.containerSettings.enableDivider = checkboxChanged.target.checked;
document.getElementById(containerId + "-divider").hidden = checkboxChanged.target.checked; document.getElementById(containerId + "-divider").style.display =
checkboxChanged.target.checked ? "block" : "none";
if (checkboxChanged.target.checked && Object.keys(container.sections).length > 0) { if (checkboxChanged.target.checked && Object.keys(container.sections).length > 0) {
document.getElementById(containerId + "-clock").style.marginBottom = "18px"; document.getElementById(containerId + "-clock").style.marginBottom = "18px";
@@ -2330,7 +2408,7 @@
localStorage.setItem("links", JSON.stringify(links)); localStorage.setItem("links", JSON.stringify(links));
localStorage.setItem("sections", JSON.stringify(sections)); localStorage.setItem("sections", JSON.stringify(sections));
if (containerSettings.disableDivider) { if (containerSettings.enableDivider) {
document.getElementById("clock").style.marginBottom = "0px"; document.getElementById("clock").style.marginBottom = "0px";
} }
@@ -2373,7 +2451,7 @@
document.getElementById("mainContainer").style.top = "10px"; document.getElementById("mainContainer").style.top = "10px";
document.getElementById("mainContainer").style.left = "10px"; document.getElementById("mainContainer").style.left = "10px";
applyContainerSettings(); applySettings();
loadSections(); loadSections();
} }