htmx.defineExtension('disable-submit', { onEvent: function (name, evt, data) { /* let elt = evt.detail.elt; let result = elt.querySelectorAll('.hx-disable'); if (name === 'htmx:beforeRequest') { result.forEach(element => element.disabled = true); if (elt.classList.contains('hx-disable')) { elt.disabled = true;} } else if(name == 'htmx:afterRequest') { result.forEach(element => element.disabled = false); if (elt.classList.contains('hx-disable')) elt.disabled = false; } */ } }) htmx.defineExtension('rename-params', { onEvent: function(name , evt) { if (name === "htmx:configRequest") { var normal = evt.detail.elt.getAttribute("hx-rename-params"); if (normal) { normal = JSON.parse(normal); for (const [key, value] of Object.entries(normal)) { console.log(evt.detail.parameters) evt.detail.parameters[value] = evt.detail.parameters[key]; delete evt.detail.parameters[key]; } } var exclusive = evt.detail.elt.getAttribute("hx-rename-params-ex"); if (exclusive) { exclusive = JSON.parse(exclusive); var params = {}; for (const [key, value] of Object.entries(exclusive)) { var v = evt.detail.parameters[key] if (v) { params[value] = v; } } evt.detail.parameters = params; } } } }); htmx.defineExtension('reactive-trigger', { onEvent: function(name , evt) { if (name === "htmx:beforeProcessNode") { var element = evt.detail.elt; var reactiveTrigger = element.getAttribute("hx-reactive-trigger"); if (reactiveTrigger) { reactiveTrigger = JSON.parse(reactiveTrigger); var reactiveSource = element.getAttribute("hx-reactive-source"); reactiveSource = reactiveSource ? document.querySelector(reactiveSource) : element.closest("form"); // var triggerString = Object.keys(reactiveTrigger).map(k => "change from:#" + reactiveSource.getAttribute("id") + " [name=\"" + k + "\"]").join(", "); var triggerString = reactiveTrigger.map(k => "change from:" + "[name=\"" + k + "\"]").join(", "); element.setAttribute("hx-trigger", triggerString); } } else if (name=="htmx:configRequest") { var element = evt.detail.elt; var reactiveTrigger = element.getAttribute("hx-reactive-trigger"); if (reactiveTrigger) { reactiveTrigger = JSON.parse(reactiveTrigger); var reactiveSource = element.getAttribute("hx-reactive-source"); reactiveSource = reactiveSource ? document.querySelector(reactiveSource) : element.closest("form"); for (key of reactiveTrigger) { console.log( reactiveSource.querySelector(`[name="${key}"]`).value) evt.detail.parameters[key] = reactiveSource.querySelector(`[name="${key}"]`).value || ""; } } } } }); function deepEqual(obj1, obj2) { if (obj1 === obj2) { return true; // Check for equality } if (typeof obj1 !== 'object' || typeof obj2 !== 'object' || obj1 === null || obj2 === null) { return false; // Check if both are objects } const keys1 = Object.keys(obj1); const keys2 = Object.keys(obj2); if (keys1.length !== keys2.length) { return false; // Check if they have the same number of properties } for (const key of keys1) { if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) { return false; // Recursively compare properties } } return true; // Objects are deeply equal } htmx.defineExtension('trigger-filter', { onEvent: function(name , evt) { if (name=="htmx:beforeRequest") { var element = evt.detail.elt; if (!deepEqual(element.lastParams, evt.detail.requestConfig.parameters)) { element.lastParams = evt.detail.requestConfig.parameters; } else { console.log("unchanged") evt.preventDefault(); } } } }); initDatepicker = function(elem) { const modalParent = elem.closest('#modal-content'); if (modalParent) { console.log('datepicker in modal') return new Datepicker(elem, {format: "mm/dd/yyyy", autohide: true, container: "#modal-content .modal-card"}); } else { console.log('datepicker normal') return new Datepicker(elem, {format: "mm/dd/yyyy", autohide: true}); } } function formatDateMMDDYYYY(date) { const month = String(date.getMonth() + 1).padStart(2, '0'); // Get month (1-12), pad with leading zero if necessary const day = String(date.getDate()).padStart(2, '0'); // Get day (1-31), pad with leading zero if necessary const year = date.getFullYear(); // Get full year return `${month}/${day}/${year}`; } function parseMMDDYYYY(dateString) { const parts = dateString.split('/'); if (parts.length !== 3) { throw new Error('Invalid date format. Expected mm/dd/yyyy'); } const month = parseInt(parts[0], 10) - 1; // Months are zero-based in JavaScript const day = parseInt(parts[1], 10); const year = parseInt(parts[2], 10); return new Date(year, month, day); } const getFourWeekPeriods = endDate => { if (!endDate) { endDate= formatDateMMDDYYYY(new Date()) } let periods = [endDate]; for (let i = 0; i < 13; i++) { const currentDate = new Date(parseMMDDYYYY(endDate).getTime()); currentDate.setDate(currentDate.getDate() - 28 * (i + 1)); periods.push(formatDateMMDDYYYY(new Date(currentDate))); } return periods; }; function getFourWeekPeriodsPeriods(endDate) { // Determine today's date based on data or current local date const today = endDate ? parseMMDDYYYY(endDate) : new Date(); // Calculate the total period const totalStart = dateFns.addDays(dateFns.subWeeks(today, 13 * 4), 1); // Construct the array of periods return [ { start: dateFns.format(totalStart, 'MM/dd/yyyy'), end: dateFns.format(today, 'MM/dd/yyyy'), title: "Total" }, ...Array.from({ length: 13 }, (_, i) => ({ start: dateFns.format(dateFns.addDays(dateFns.subWeeks(today, (i + 1) * 4), 1), 'MM/dd/yyyy'), end: dateFns.format(dateFns.subWeeks(today, i * 4), 'MM/dd/yyyy') })) ]; } const getTwelveCalendarMonthsPeriods = (endDate) => { console.log(endDate) // If no date is provided, default to today's date const today = endDate ? parseMMDDYYYY(endDate) : new Date(); // Set the last day of the provided month as the end date const inputEndDate = new Date(today.getFullYear(), today.getMonth() + 1, 0); // Calculate the start of the total year range (12 months back from the end of input month) const totalStartDate = new Date(inputEndDate.getFullYear(), inputEndDate.getMonth() - 11, 1); // Build the array of months // Build the array of months const months = [ { start: formatDateMMDDYYYY(totalStartDate), end: formatDateMMDDYYYY(inputEndDate), title: "Total" }, ...Array.from({ length: 12 }, (_, i) => { const monthEnd = new Date(inputEndDate.getFullYear(), inputEndDate.getMonth() - (11 - i) + 1, 0); // Last day of the month const monthStart = new Date(monthEnd.getFullYear(), monthEnd.getMonth(), 1); // First day of the month return { start: formatDateMMDDYYYY(monthStart), end: formatDateMMDDYYYY(monthEnd), title: monthEnd.toLocaleString('default', { month: 'long', year: 'numeric' }) }; }) ]; console.log(months) return months; }; const withLastYear = (date) => { if (!date) { date= new Date() } else { date = parseMMDDYYYY(date) } const originalYear = date.getFullYear(); const priorYear = originalYear - 1; // Create new Date objects for both years const originalDate = new Date(originalYear, date.getMonth(), date.getDate()); const priorYearDate = new Date(priorYear, date.getMonth(), date.getDate()); return [formatDateMMDDYYYY(originalDate), formatDateMMDDYYYY(priorYearDate)]; } const lastYearPeriod = (date) => { if (!date) { date= new Date() } else { date = parseMMDDYYYY(date) } const originalYear = date.getFullYear(); const priorYear = originalYear - 1; // Create new Date objects for both years const originalDate = new Date(originalYear, date.getMonth(), date.getDate()); const priorYearDate = dateFns.addDays(new Date(priorYear, date.getMonth(), date.getDate()), 1); return {end: formatDateMMDDYYYY(originalDate), start: formatDateMMDDYYYY(priorYearDate)}; } const calendarYearPeriod = (date) => { if (!date) { date= new Date() } else { date = parseMMDDYYYY(date) } const originalYear = date.getFullYear(); const priorYear = originalYear - 1; // Create new Date objects for both years const start = new Date(originalYear, 0, 1); const end = new Date(originalYear, 11, 31); return {end: formatDateMMDDYYYY(end), start: formatDateMMDDYYYY(start)}; } const getLastMonthPeriods = (date) => { if (!date) { date = new Date(); } else { date = parseMMDDYYYY(date); } // Get the first day of the current month const firstDayOfCurrentMonth = new Date(date.getFullYear(), date.getMonth(), 1); // Get the last day of the previous month const lastDayOfPreviousMonth = dateFns.subDays(firstDayOfCurrentMonth, 1); // Get the first day of the previous month const firstDayOfPreviousMonth = new Date(lastDayOfPreviousMonth.getFullYear(), lastDayOfPreviousMonth.getMonth(), 1); // Get the same period for the previous year const firstDayOfPreviousYearMonth = new Date(firstDayOfPreviousMonth.getFullYear() - 1, firstDayOfPreviousMonth.getMonth(), 1); const lastDayOfPreviousYearMonth = dateFns.lastDayOfMonth(firstDayOfPreviousYearMonth); // Create period objects const currentPeriod = { start: formatDateMMDDYYYY(firstDayOfPreviousMonth), end: formatDateMMDDYYYY(lastDayOfPreviousMonth) }; const previousYearPeriod = { start: formatDateMMDDYYYY(firstDayOfPreviousYearMonth), end: formatDateMMDDYYYY(lastDayOfPreviousYearMonth) }; return [currentPeriod, previousYearPeriod]; }; const getMonthToDatePeriods = () => { date = new Date(); // Get the first day of the current month const firstDayOfCurrentMonth = new Date(date.getFullYear(), date.getMonth(), 1); // Get the same period for the previous year const firstDayOfPreviousYearMonth = new Date(firstDayOfCurrentMonth.getFullYear() - 1, firstDayOfCurrentMonth.getMonth(), 1); // Create period objects const currentPeriod = { start: formatDateMMDDYYYY(firstDayOfCurrentMonth), end: formatDateMMDDYYYY(date) }; const previousYearPeriod = { start: formatDateMMDDYYYY(firstDayOfPreviousYearMonth), end: formatDateMMDDYYYY(new Date(firstDayOfPreviousYearMonth.getFullYear(), firstDayOfPreviousYearMonth.getMonth(), date.getDate())) }; return [currentPeriod, previousYearPeriod]; }; const getYearToDatePeriods = () => { date = new Date(); // Get the first day of the current month const firstDayOfCurrentMonth = new Date(date.getFullYear(), 0, 1); // Get the same period for the previous year const firstDayOfPreviousYearMonth = new Date(firstDayOfCurrentMonth.getFullYear() - 1, 0, 1); // Create period objects const currentPeriod = { start: formatDateMMDDYYYY(firstDayOfCurrentMonth), end: formatDateMMDDYYYY(date) }; const previousYearPeriod = { start: formatDateMMDDYYYY(firstDayOfPreviousYearMonth), end: formatDateMMDDYYYY(new Date(firstDayOfPreviousYearMonth.getFullYear(), firstDayOfPreviousYearMonth.getMonth(), date.getDate())) }; return [currentPeriod, previousYearPeriod]; } initMultiDatepicker = function(elem, startingValue) { const modalParent = elem.closest('#modal-content'); if (modalParent) { return new Datepicker(elem, {format: "mm/dd/yyyy", autohide: false, container: "#modal-content .modal-card", maxNumberOfDates: 12, dateDelimiter: ", "}); } else { return new Datepicker(elem, {format: "mm/dd/yyyy", autohide: false, maxNumberOfDates: 12, dateDelimiter: ", "}); } } initCalendar = function(elem, startingValue) { const modalParent = elem.closest('#modal-content'); if (modalParent) { return new Datepicker(elem, {format: "mm/dd/yyyy", autohide: false, container: "#modal-content .modal-card"}); } else { return new Datepicker(elem, {format: "mm/dd/yyyy", autohide: false, }); } } destroyDatepicker = function(dp) { try { dp.destroy() } catch { } } countRows = function(id) { var table = document.querySelector(id); var rows = table.querySelectorAll("tbody tr"); return rows.length; } htmx.onLoad(function(content) { var sortables = content.querySelectorAll(".sortable"); for (var i = 0; i < sortables.length; i++) { var sortable = sortables[i]; var sortableInstance = new Sortable(sortable, { animation: 150, ghostClass: 'bg-blue-100', // Make the `.htmx-indicator` unsortable filter: ".htmx-indicator", onMove: function (evt) { return evt.related.className.indexOf('htmx-indicator') === -1; }, // Disable sorting on the `end` event onEnd: function (evt) { this.option("disabled", true); } }); // Re-enable sorting on the `htmx:afterSwap` event sortable.addEventListener("htmx:afterSwap", function() { sortableInstance.option("disabled", false); }); } }) async function copyToClipboard(text) { try { // Write the text to the clipboard await navigator.clipboard.writeText(text); console.log('Text copied to clipboard:', text); } catch (err) { console.error('Failed to copy text to clipboard:', err); } }