may this be Big
This commit is contained in:
1 parent
9100207c59
commit
12dc1c1550
7 files changed
+177
-83
No files matched your search
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"checkJs": true,
|
||||
"baseUrl": "./",
|
||||
"paths": {
|
||||
"@fullcalendar/*": ["node_modules/@fullcalendar/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src/**/*"]
|
||||
}
|
||||
+37
-4
@@ -11,7 +11,21 @@ import { getNextColor } from "./color_generator";
|
||||
|
||||
import { glued } from "./main";
|
||||
|
||||
let calendar = null;
|
||||
// /**
|
||||
// * @typedef {import("@fullcalendar/core").Calendar} Calendar
|
||||
// * @typedef {import("@fullcalendar/core").EventSourceInput} EventSourceInput
|
||||
// */
|
||||
|
||||
let /** @type {Calendar | null} */ calendar = null;
|
||||
|
||||
/**
|
||||
* Initializes and renders the FullCalendar instance.
|
||||
*
|
||||
* @param {HTMLElement} element - The DOM element to render the calendar into.
|
||||
* @param {string | URL} url - The URL for the initial event source.
|
||||
* @param {Function} onEventMouseEnter - Callback for mouse enter on events.
|
||||
* @param {Function} onEventMouseLeave - Callback for mouse leave on events.
|
||||
*/
|
||||
|
||||
export function initializeCalendar(
|
||||
element,
|
||||
@@ -49,25 +63,44 @@ export function initializeCalendar(
|
||||
timeGridDay: { buttonText: "Day" },
|
||||
listMonth: { buttonText: "List" },
|
||||
},
|
||||
events: init_ics_source(url),
|
||||
eventMouseEnter: onEventMouseEnter,
|
||||
eventMouseLeave: onEventMouseLeave,
|
||||
events: init_ics_source(url.toString()), // Convert URL to string
|
||||
eventMouseEnter:
|
||||
/** @type {(arg: import("@fullcalendar/core").EventHoveringArg) => void} */ (
|
||||
onEventMouseEnter
|
||||
),
|
||||
eventMouseLeave:
|
||||
/** @type {(arg: import("@fullcalendar/core").EventHoveringArg) => void} */ (
|
||||
onEventMouseLeave
|
||||
),
|
||||
loading: glued,
|
||||
});
|
||||
// console.log(calendar);
|
||||
calendar.render();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new event source to the calendar.
|
||||
* @param {string} url - The URL for the event source.
|
||||
*/
|
||||
export const addEventSource = (url) => {
|
||||
if (calendar) {
|
||||
calendar.addEventSource(init_ics_source(url));
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns the current calendar instance.
|
||||
* @returns {Calendar | null} The FullCalendar instance.
|
||||
*/
|
||||
export const getCalendarInstance = () => {
|
||||
return calendar;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initializes an event source object.
|
||||
* @param {string} url - The URL for the event source.
|
||||
* @returns {import("@fullcalendar/core").EventSourceInput} The event source object.
|
||||
*/
|
||||
const init_ics_source = (url) => {
|
||||
return {
|
||||
url: url,
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
/**
|
||||
* Updates the event source list in the DOM.
|
||||
* @param {HTMLElement | null} eventSourceList - The DOM element to display the event sources.
|
||||
* @returns {Function} A function that updates the event source list for a given calendar.
|
||||
*/
|
||||
export const updateEventSourceList2 = (eventSourceList) =>
|
||||
/**
|
||||
* Updates the event source list.
|
||||
* @param {import("@fullcalendar/core").Calendar} calendar - The FullCalendar instance.
|
||||
*/
|
||||
function updateEventSourceList(calendar) {
|
||||
if (!calendar) return;
|
||||
|
||||
// const eventSourceList = document.getElementById("event-source-list");
|
||||
if (!eventSourceList) return;
|
||||
|
||||
// Clear the current list
|
||||
eventSourceList.innerHTML = "";
|
||||
|
||||
// Fetch all event sources
|
||||
calendar.getEventSources().forEach((source) => {
|
||||
console.log(source);
|
||||
|
||||
const card = document.createElement("div");
|
||||
card.className = "event-source-card";
|
||||
card.style.display = "flex";
|
||||
card.style.justifyContent = "space-between";
|
||||
card.style.alignItems = "center";
|
||||
|
||||
// Fix type for borderColor
|
||||
const borderColor =
|
||||
source.internalEventSource.ui?.borderColor || "#007bff";
|
||||
card.style.borderLeft = `4px solid ${borderColor}`;
|
||||
|
||||
card.style.padding = "0.5em";
|
||||
card.style.marginBottom = "0.5em";
|
||||
|
||||
const info = document.createElement("div");
|
||||
const url = source.url || "(No URL)";
|
||||
const format = source.format || "(Unknown Format)";
|
||||
|
||||
const sourceInfo = document.createElement("div");
|
||||
sourceInfo.innerHTML = `<strong>Source:</strong> ${url}<br><strong>Format:</strong> ${format}`;
|
||||
|
||||
const loadingStatus = document.createElement("div");
|
||||
loadingStatus.className = "loading-status";
|
||||
loadingStatus.textContent = source.internalEventSource.isFetching
|
||||
? "Fetching in progress"
|
||||
: "Loaded";
|
||||
|
||||
info.appendChild(sourceInfo);
|
||||
info.appendChild(loadingStatus);
|
||||
|
||||
// Add Refetch Button
|
||||
const refetchButton = document.createElement("button");
|
||||
refetchButton.textContent = "Refetch";
|
||||
refetchButton.className = "btn btn-sm btn-primary";
|
||||
refetchButton.style.marginRight = "0.5em";
|
||||
refetchButton.addEventListener("click", () => {
|
||||
source.refetch();
|
||||
alert("Source refetched!");
|
||||
});
|
||||
|
||||
// Add Remove Button
|
||||
const removeButton = document.createElement("button");
|
||||
removeButton.textContent = "Remove";
|
||||
removeButton.className = "btn btn-sm btn-danger";
|
||||
removeButton.addEventListener("click", () => {
|
||||
source.remove();
|
||||
updateEventSourceList(calendar); // Refresh the list after removal
|
||||
});
|
||||
|
||||
// Create a button container
|
||||
const buttonContainer = document.createElement("div");
|
||||
buttonContainer.appendChild(refetchButton);
|
||||
buttonContainer.appendChild(removeButton);
|
||||
|
||||
// Append info and buttons to the card
|
||||
card.appendChild(info);
|
||||
card.appendChild(buttonContainer);
|
||||
|
||||
// Append the card to the event source list
|
||||
eventSourceList.appendChild(card);
|
||||
});
|
||||
};
|
||||
+20
-68
@@ -4,18 +4,36 @@ import {
|
||||
getCalendarInstance,
|
||||
} from "./calendar";
|
||||
import { newTippy, tippyDie } from "./tooltip";
|
||||
import { updateEventSourceList2 } from "./eventSourceManager";
|
||||
import { create_url } from "./utils";
|
||||
|
||||
import "bootstrap/dist/css/bootstrap.css";
|
||||
import "bootstrap-icons/font/bootstrap-icons.css";
|
||||
import "tippy.js/dist/tippy.css";
|
||||
|
||||
// Fix type for text_field
|
||||
/** @type {HTMLInputElement} */
|
||||
// @ts-ignore
|
||||
const text_field = document.getElementById("ics_file");
|
||||
|
||||
/** @type {HTMLButtonElement} */
|
||||
// @ts-ignore
|
||||
const confirm_button = document.getElementById("ics_run");
|
||||
|
||||
/** @type {HTMLButtonElement} */
|
||||
// @ts-ignore
|
||||
const add_button = document.getElementById("ics_add");
|
||||
|
||||
/** @type {HTMLElement} */
|
||||
const cal_ele = document.getElementById("calendar");
|
||||
|
||||
/** @type {HTMLElement} */
|
||||
const placeholder_message = document.getElementById("placeholder-message");
|
||||
|
||||
/** @type {HTMLElement} */
|
||||
const eventSourceList = document.getElementById("event-source-list");
|
||||
const updateEventSourceList = updateEventSourceList2(eventSourceList);
|
||||
|
||||
|
||||
function showPlaceholder() {
|
||||
placeholder_message.style.display = "block";
|
||||
@@ -27,74 +45,7 @@ function hidePlaceholder() {
|
||||
cal_ele.style.display = "block";
|
||||
}
|
||||
|
||||
function updateEventSourceList(calendar) {
|
||||
if (!calendar) return;
|
||||
|
||||
// Clear the current list
|
||||
eventSourceList.innerHTML = "";
|
||||
|
||||
// Fetch all event sources
|
||||
calendar.getEventSources().forEach((source) => {
|
||||
const card = document.createElement("div");
|
||||
card.className = "event-source-card";
|
||||
card.style.display = "flex";
|
||||
card.style.justifyContent = "space-between";
|
||||
card.style.alignItems = "center";
|
||||
card.style.borderLeft = `4px solid ${source.color || "#007bff"}`;
|
||||
card.style.padding = "0.5em";
|
||||
card.style.marginBottom = "0.5em";
|
||||
|
||||
// Create info container
|
||||
const info = document.createElement("div");
|
||||
const url = source.url || "(No URL)";
|
||||
const format = source.format || "(Unknown Format)";
|
||||
|
||||
const sourceInfo = document.createElement("div");
|
||||
sourceInfo.innerHTML = `<strong>Source:</strong> ${url}<br><strong>Format:</strong> ${format}`;
|
||||
|
||||
const loadingStatus = document.createElement("div");
|
||||
loadingStatus.className = "loading-status";
|
||||
loadingStatus.textContent = source.internalEventSource.isFetching
|
||||
? "Fetching in progress"
|
||||
: "Loaded";
|
||||
|
||||
info.appendChild(sourceInfo);
|
||||
info.appendChild(loadingStatus);
|
||||
|
||||
// Add Refetch Button
|
||||
const refetchButton = document.createElement("button");
|
||||
refetchButton.textContent = "Refetch";
|
||||
refetchButton.className = "btn btn-sm btn-primary";
|
||||
refetchButton.style.marginRight = "0.5em";
|
||||
refetchButton.addEventListener("click", () => {
|
||||
source.refetch();
|
||||
alert("Source refetched!");
|
||||
});
|
||||
|
||||
// Add Remove Button
|
||||
const removeButton = document.createElement("button");
|
||||
removeButton.textContent = "Remove";
|
||||
removeButton.className = "btn btn-sm btn-danger";
|
||||
removeButton.addEventListener("click", () => {
|
||||
source.remove();
|
||||
updateEventSourceList(calendar); // Refresh the list after removal
|
||||
});
|
||||
|
||||
// Create a button container
|
||||
const buttonContainer = document.createElement("div");
|
||||
buttonContainer.appendChild(refetchButton);
|
||||
buttonContainer.appendChild(removeButton);
|
||||
|
||||
// Append info and buttons to the card
|
||||
card.appendChild(info);
|
||||
card.appendChild(buttonContainer);
|
||||
|
||||
// Append the card to the event source list
|
||||
eventSourceList.appendChild(card);
|
||||
});
|
||||
}
|
||||
|
||||
export const glued = (e) => {
|
||||
export const glued = (_e) => {
|
||||
// console.log("loading:", e); // half of it will be true false and half of it will be events
|
||||
|
||||
setTimeout(() => updateEventSourceList(getCalendarInstance()));
|
||||
@@ -120,4 +71,5 @@ add_button.addEventListener("click", () => {
|
||||
return;
|
||||
}
|
||||
addEventSource(url);
|
||||
updateEventSourceList(getCalendarInstance());
|
||||
});
|
||||
@@ -31,5 +31,3 @@ export function tippyDie(info) {
|
||||
currentTippy.hideWithInteractivity(info.jsEvent);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+16
-3
@@ -1,11 +1,19 @@
|
||||
/** Escapes HTML special characters to prevent XSS */
|
||||
/**
|
||||
* Escapes HTML special characters to prevent XSS.
|
||||
* @param {string} text - The input text to escape.
|
||||
* @returns {string} The escaped HTML string.
|
||||
*/
|
||||
export function escapeHtml(text) {
|
||||
const div = document.createElement("div");
|
||||
div.innerText = text;
|
||||
return div.innerHTML;
|
||||
}
|
||||
|
||||
/** Converts URLs in text to clickable links, after escaping */
|
||||
/**
|
||||
* Converts URLs in text to clickable links, after escaping.
|
||||
* @param {string} text - The input text containing URLs.
|
||||
* @returns {string} The linkified HTML string.
|
||||
*/
|
||||
export function linkify(text) {
|
||||
let safe = escapeHtml(text);
|
||||
return safe.replace(
|
||||
@@ -15,7 +23,12 @@ export function linkify(text) {
|
||||
);
|
||||
}
|
||||
|
||||
/** Formats tooltip content: escapes, linkifies, and replaces newlines with \<br> */
|
||||
/**
|
||||
* Formats tooltip content: escapes, linkifies, and replaces newlines with <br>.
|
||||
* @param {string} title - The title of the tooltip.
|
||||
* @param {string} [description] - The optional description of the tooltip.
|
||||
* @returns {string} The formatted tooltip content.
|
||||
*/
|
||||
export function formatTooltip(title, description) {
|
||||
const safeTitle = escapeHtml(title);
|
||||
const safeDesc = description
|
||||
|
||||
+9
-6
@@ -1,10 +1,13 @@
|
||||
function create_url(url) {
|
||||
/**
|
||||
* Creates a valid URL from the given input.
|
||||
* @param {string} input - The input string to convert into a URL.
|
||||
* @returns {string | null} - The valid URL or null if invalid.
|
||||
*/
|
||||
export function create_url(input) {
|
||||
try {
|
||||
return new URL(url);
|
||||
} catch (e) {
|
||||
// console.info(e);
|
||||
const url = new URL(input);
|
||||
return url.href;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
export { create_url };
|
||||
Reference in new issue
Block a user