From a864c25de0116a87fbeaee8bdf411e9ad698201d Mon Sep 17 00:00:00 2001 From: NightScript <18664762+NightScript370@users.noreply.github.com> Date: Thu, 26 Dec 2024 17:32:02 -0500 Subject: [PATCH] Joey Zaghi request: Select individual Zemanim for the excel/ics export --- _includes/modals/export.html | 64 +++++++ assets/js/WebsiteCalendar.js | 6 +- assets/js/features/excelPrepare.js | 18 +- assets/js/features/export.js | 281 ++++++++++++++++++++++++++++ assets/js/features/icsPrepare.js | 2 +- assets/js/zmanimListUpdater.js | 286 ++--------------------------- pages/calendar.html | 15 +- 7 files changed, 379 insertions(+), 293 deletions(-) create mode 100644 _includes/modals/export.html create mode 100644 assets/js/features/export.js diff --git a/_includes/modals/export.html b/_includes/modals/export.html new file mode 100644 index 0000000..a17225b --- /dev/null +++ b/_includes/modals/export.html @@ -0,0 +1,64 @@ + \ No newline at end of file diff --git a/assets/js/WebsiteCalendar.js b/assets/js/WebsiteCalendar.js index 80646dd..ce66363 100644 --- a/assets/js/WebsiteCalendar.js +++ b/assets/js/WebsiteCalendar.js @@ -4,6 +4,9 @@ import * as KosherZmanim from "../libraries/kosherZmanim/kosher-zmanim.esm.js" import { he as n2heWords, he_rt as n2ruWords } from "../libraries/n2words.esm.js"; import { AmudehHoraahZmanim, OhrHachaimZmanim } from "./ROYZmanim.js"; +/** @typedef {{ hb: string, en: string, "en-et": string; "ru"?: string; }} langType */ +/** @typedef {{display: -2|-1|0|1, code: string[], luxonObj: KosherZmanim.Temporal.ZonedDateTime, title: langType, merge_title: langType; function: string}} zmanData */ + export default class WebsiteCalendar extends KosherZmanim.JewishCalendar { formatJewishFullDate() { @@ -111,8 +114,7 @@ class WebsiteCalendar extends KosherZmanim.JewishCalendar { * @param {{ hourCalculator: "degrees" | "seasonal"; tzeithIssurMelakha: { minutes: number; degree: number;}; tzeitTaanitHumra: boolean; }} funcSettings */ getZmanimInfo(independent, zmanCalc, zmanList, funcSettings) { - /** @typedef {{ hb: string, en: string, "en-et": string; "ru"?: string; }} langType */ - /** @type {Record} */ + /** @type {Record} */ const calculatedZmanim = {} for (const [zmanId, zmanInfo] of Object.entries(zmanList)) { diff --git a/assets/js/features/excelPrepare.js b/assets/js/features/excelPrepare.js index de8cab6..d3a6492 100644 --- a/assets/js/features/excelPrepare.js +++ b/assets/js/features/excelPrepare.js @@ -4,13 +4,15 @@ import { AmudehHoraahZmanim, OhrHachaimZmanim } from "../ROYZmanim.js"; import { Temporal, GeoLocation } from "../../libraries/kosherZmanim/kosher-zmanim.esm.js"; import WebsiteCalendar from "../WebsiteCalendar.js"; +/** @typedef {T[keyof T]} ValueOf */ + /** * @param {boolean} amudehHoraahZman * @param {[number, number, number, string | Temporal.CalendarProtocol]} plainDateParams * @param {[string, number, number, number, string]} geoLocationData * @param {boolean} useElevation * @param {boolean} isIsrael - * @param {{ [s: string]: { function: string|null; yomTovInclusive: string|null; luachInclusive: "degrees"|"seasonal"|null; condition: string|null; title: { "en-et": string; en: string; hb: string; }}; }} zmanList + * @param {Parameters[2]} zmanList * @param {boolean} monthView * @param {{ language: "en-et" | "en" | "he"; timeFormat: "h11" | "h12" | "h23" | "h24"; seconds: boolean; zmanInfoSettings: Parameters[3]; calcConfig: Parameters; netzTimes: number[] }} funcSettings */ @@ -38,22 +40,22 @@ export default function spreadSheetExport (amudehHoraahZman, plainDateParams, ge if (vNetz) seeSun = vNetz.find(zDT => Math.abs(regularNetz.until(zDT).total('minutes')) <= 6) - // @ts-ignore + /** @param {import("../WebsiteCalendar.js").zmanData} entry */ function formatTime(entry) { // @ts-ignore const time = (entry.function == 'getNetz' && seeSun ? seeSun : entry.luxonObj) return '=TIME(' + [time.hour, time.minute, time.second].join(', ') + ')' } - const dailyZmanim = Object.values(jCal.getZmanimInfo(true, calc, zmanList, funcSettings.zmanInfoSettings)) - .filter(entry => entry.display == 1) + const dailyZmanim = Object.entries(jCal.getZmanimInfo(true, calc, zmanList, funcSettings.zmanInfoSettings)) + .filter(entry => entry[1].display == 1) .map(entry => [ - entry.function || (entry.title["en"].startsWith("Candle Lighting") ? "getCandleLighting" : ""), - {t: "d", v: new Date(entry.luxonObj.epochMilliseconds), - f: formatTime(entry), z: + entry[0], + {t: "d", v: new Date(entry[1].luxonObj.epochMilliseconds), + f: formatTime(entry[1]), z: "h" + (["h23", "h24"].includes(funcSettings.timeFormat) ? "h" : "") // @ts-ignore - + ":mm" + (funcSettings.seconds || (entry.function == "getNetz" && seeSun) ? ":ss" : "") + + ":mm" + (funcSettings.seconds || (entry[1].function == "getNetz" && seeSun) ? ":ss" : "") + (["h11", "h12"].includes(funcSettings.timeFormat) ? " AM/PM" : "")} ]) diff --git a/assets/js/features/export.js b/assets/js/features/export.js new file mode 100644 index 0000000..97819f1 --- /dev/null +++ b/assets/js/features/export.js @@ -0,0 +1,281 @@ +// @ts-check + +import { AmudehHoraahZmanim } from '../ROYZmanim.js'; +import { settings } from "../settings/handler.js"; +import WebsiteCalendar from "../WebsiteCalendar.js"; + +export default class exportFriendly { + constructor() { + this.midDownload = false; + } + + /** @param {import('../zmanimListUpdater.js').default} zmanLister */ + async handleICS(zmanLister) { + if (this.midDownload) + return; + + this.midDownload = true; + + const exportZmanList = Object.fromEntries(Object.entries(zmanLister.zmanimList) + // @ts-ignore + .filter(([key, value]) => document.getElementById(`exportzmanid-${key}`).checked)) + + /** @type {[string, number, number, number, string]} */ + // @ts-ignore + const glArgs = Object.values(settings.location).map(numberFunc => numberFunc()) + + const { isoDay, isoMonth, isoYear, calendar: isoCalendar } = zmanLister.zmanFuncs.coreZC.getDate().getISOFields() + + let availableVS = []; + if (typeof localStorage !== "undefined" && localStorage.getItem('ctNetz') && isValidJSON(localStorage.getItem('ctNetz'))) { + const ctNetz = JSON.parse(localStorage.getItem('ctNetz')) + if (ctNetz.lat == zmanLister.geoLocation.getLatitude() + && ctNetz.lng == zmanLister.geoLocation.getLongitude()) + availableVS = ctNetz.times + } + + /** @type {Parameters} */ + const icsParams = [ + zmanLister.zmanFuncs instanceof AmudehHoraahZmanim, + undefined, + glArgs, + zmanLister.zmanFuncs.coreZC.isUseElevation(), + zmanLister.jCal.getInIsrael(), + exportZmanList, + true, + { + // @ts-ignore + language: settings.language() == "hb" ? "he" : settings.language(), + timeFormat: settings.timeFormat(), seconds: settings.seconds(), + zmanInfoSettings: zmanLister.zmanInfoSettings, + calcConfig: [settings.calendarToggle.rtKulah(), settings.customTimes.tzeithIssurMelakha()], + fasts: Object.fromEntries([...document.querySelector('[data-zfFind="FastDays"]').getElementsByTagName("h5")] + .map(ogHeading => { + /** @type {HTMLHeadingElement} */ + // @ts-ignore + const heading = ogHeading.cloneNode(true); + const [ he, et, en ] = [...heading.children] + .map(langElem => { + while (langElem.querySelector('[data-zfFind="erevTzom"]')) + langElem.querySelector('[data-zfFind="erevTzom"]').remove() + + return langElem.innerHTML.replace(/<.*?>/gm, ''); + }) + + return [heading.getAttribute("data-zfFind"), { he, "en-et": et, en }] + })), + tahanun: Object.fromEntries([...document.querySelector('[data-zfFind="Tachanun"]').children] + .map(/** @returns {[string, string|{"he": string; "en-et": string; "en": string}]} */ + tachObj => + [ + tachObj.getAttribute('data-zfFind'), + // @ts-ignore + tachObj.childElementCount == 0 + ? tachObj.innerHTML + : Object.fromEntries([...tachObj.children] + .map(langElem => [ + langElem.classList.values().find(cl => cl.startsWith('lang-')).replace('lang-', '').replace('hb', 'he'), + langElem.innerHTML + ])) + ])), + netzTimes: availableVS + } + ] + + /** @type {import('../../libraries/ics/ics.esm.js').ics.EventAttributes[]} */ + let receiveData = []; + let giveData = []; + + const postDataReceive = async () => { + const ics = (await import('../../libraries/ics/ics.esm.js')).ics; + + receiveData = receiveData.flat() + zmanLister.zmanFuncs.tekufaCalc.calculateTekufotShemuel(!(zmanLister.zmanFuncs instanceof AmudehHoraahZmanim)) + .forEach((tekufa, index) => { + const time = tekufa.toZonedDateTime("+02:00").withTimeZone(zmanLister.geoLocation.getTimeZone()) + const tekufaMonth = [ + WebsiteCalendar.TISHREI, + WebsiteCalendar.TEVES, + WebsiteCalendar.NISSAN, + WebsiteCalendar.TAMMUZ, + WebsiteCalendar.TISHREI, + WebsiteCalendar.TEVES, + ] + .map(month => (new WebsiteCalendar(zmanLister.jCal.getJewishYear(), month, 15)).formatJewishMonth()) + [index] + + receiveData.push({ + start: time.subtract({ minutes: 30 }).epochMilliseconds, + end: time.add({ minutes: 30 }).epochMilliseconds, + title: { + hb: "תקופת " + tekufaMonth.he, + en: tekufaMonth.en + " Season", + "en-et": "Tekufath " + tekufaMonth.en + }[settings.language()] + }) + }) + + const calName = (zmanLister.zmanFuncs instanceof AmudehHoraahZmanim ? "Amudeh Hora'ah" : "Ohr Hachaim") + + ` Calendar (${isoYear}) - ` + zmanLister.geoLocation.getLocationName(); + const labeledEvents = + Array.from(new Set(receiveData.map(field => JSON.stringify(field)))).map(field => JSON.parse(field)) + .map(obj => ({ + ...obj, + calName, + /** @type {"utc"} */ + startInputType: "utc", + /** @type {"utc"} */ + endInputType: "utc" + })); + + const icsRespond = ics.createEvents(labeledEvents) + if (icsRespond.error) + throw icsRespond.error; + + const element = document.createElement('a'); + element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(icsRespond.value)); + element.setAttribute('download', calName + ".ics"); + + element.style.display = 'none'; + document.body.appendChild(element); + + element.click(); + + document.body.removeChild(element); + this.midDownload = false; + } + + for (let i = 1; i <= zmanLister.jCal.getDate().monthsInYear; i++) { + const monthICSData = [...icsParams] + monthICSData[1] = [isoYear, i, isoDay, isoCalendar] + giveData.push(monthICSData) + } + + for (const monthICSData of giveData) { + if (window.Worker) { + console.log('activate thread') + const myWorker = new Worker("/assets/js/features/icsPrepare.js", { type: "module" }); + myWorker.postMessage(monthICSData) + myWorker.addEventListener("message", async (message) => { + console.log("received message from other thread"); + receiveData.push(message.data) + if (receiveData.length == giveData.length) + await postDataReceive(); + }) + } else { + const icsExport = (await import('./icsPrepare.js')).default; + const icsData = icsExport.apply(icsExport, monthICSData); + receiveData.push(icsData); + if (receiveData.length == giveData.length) + await postDataReceive(); + } + } + } + + /** @param {import('../zmanimListUpdater.js').default} zmanLister */ + async handleExcel(zmanLister) { + if (this.midDownload) + return; + + this.midDownload = true; + + const exportZmanList = Object.fromEntries(Object.entries(zmanLister.zmanimList) + // @ts-ignore + .filter(([key, value]) => document.getElementById(`exportzmanid-${key}`).checked)) + + /** @type {[string, number, number, number, string]} */ + // @ts-ignore + const glArgs = Object.values(settings.location).map(numberFunc => numberFunc()) + + const { isoDay, isoMonth, isoYear, calendar: isoCalendar } = zmanLister.zmanFuncs.coreZC.getDate().getISOFields() + + let availableVS = []; + if (typeof localStorage !== "undefined" && localStorage.getItem('ctNetz') && isValidJSON(localStorage.getItem('ctNetz'))) { + const ctNetz = JSON.parse(localStorage.getItem('ctNetz')) + if (ctNetz.lat == zmanLister.geoLocation.getLatitude() + && ctNetz.lng == zmanLister.geoLocation.getLongitude()) + availableVS = ctNetz.times + } + + /** @type {Parameters} */ + const excelParams = [ + zmanLister.zmanFuncs instanceof AmudehHoraahZmanim, + undefined, + glArgs, + zmanLister.zmanFuncs.coreZC.isUseElevation(), + zmanLister.jCal.getInIsrael(), + exportZmanList, + true, + { + // @ts-ignore + language: settings.language() == "hb" ? "he" : settings.language(), + zmanInfoSettings: zmanLister.zmanInfoSettings, + calcConfig: [settings.calendarToggle.rtKulah(), settings.customTimes.tzeithIssurMelakha()], + seconds: settings.seconds(), + timeFormat: settings.timeFormat(), + netzTimes: availableVS + } + ] + + /** @type {Parameters[1][]} */ + let workerData = []; + let giveData = []; + + const title = (zmanLister.zmanFuncs instanceof AmudehHoraahZmanim ? "Amudeh Hora'ah" : "Ohr Hachaim") + + ` Calendar (${isoYear}) - ` + zmanLister.geoLocation.getLocationName(); + + const postDataReceive = async () => { + const headerRow = Object.fromEntries( + [['DATE', {'hb': "יום", en: 'DATE', "en-et": "DATE"}[settings.language()]]] + .concat(Object.entries(exportZmanList).map(entry => [entry[0], entry[1].title[settings.language()]])) + ); + + const tableData = [...new Set(workerData.flat().map(field => JSON.stringify(field)))] + .map(field => JSON.parse(field)) + .sort((a, b) => new Date(Object.values(a)[1].v).getTime() - new Date(Object.values(b)[1].v).getTime()) + + const { utils, writeFile } = (await import('../../libraries/xlsx.mjs')); + const ws = utils.json_to_sheet([headerRow].concat(tableData), { skipHeader: true }); + const wb = utils.book_new(); + utils.book_append_sheet(wb, ws, "People"); + writeFile(wb, title + ".xlsx"); + this.midDownload = false; + } + + for (let i = 1; i <= zmanLister.jCal.getDate().monthsInYear; i++) { + const monthExcelData = [...excelParams] + monthExcelData[1] = [isoYear, i, isoDay, isoCalendar] + giveData.push(monthExcelData) + } + + for (const monthExcelData of giveData) { + if (window.Worker) { + const myWorker = new Worker("/assets/js/features/excelPrepare.js", { type: "module" }); + myWorker.postMessage(monthExcelData) + myWorker.addEventListener("message", async (message) => { + workerData.push(message.data); + if (workerData.length == giveData.length) + await postDataReceive(); + }) + } else { + const excelExport = (await import('./excelPrepare.js')).default; + const icsData = excelExport.apply(excelExport, monthExcelData); + workerData.push(icsData); + if (workerData.length == giveData.length) + await postDataReceive(); + } + } + } +} + +/** + * @param {string} str + */ +function isValidJSON(str) { + try { + JSON.parse(str); + return true; + } catch (e) { + return false; + } +} \ No newline at end of file diff --git a/assets/js/features/icsPrepare.js b/assets/js/features/icsPrepare.js index e3c225f..8c118b0 100644 --- a/assets/js/features/icsPrepare.js +++ b/assets/js/features/icsPrepare.js @@ -28,7 +28,7 @@ const monViewNight = (monthView, calc) => * @param {[string, number, number, number, string]} geoLocationData * @param {boolean} useElevation * @param {boolean} isIsrael - * @param {{ [s: string]: { function: string|null; yomTovInclusive: string|null; luachInclusive: "degrees"|"seasonal"|null; condition: string|null; title: { "en-et": string; en: string; hb: string; }}; }} zmanList + * @param {Parameters[2]} zmanList * @param {boolean} monthView * @param {{ language: "en-et" | "en" | "he"; timeFormat: "h11" | "h12" | "h23" | "h24"; seconds: boolean; zmanInfoSettings: Parameters[3]; calcConfig: Parameters; fasts: Record; tahanun: Record }} funcSettings */ diff --git a/assets/js/zmanimListUpdater.js b/assets/js/zmanimListUpdater.js index d5cc2a4..7baef64 100644 --- a/assets/js/zmanimListUpdater.js +++ b/assets/js/zmanimListUpdater.js @@ -9,15 +9,18 @@ import { ChaiTables } from "./features/chaiTables.js"; import * as leaflet from "../libraries/leaflet/leaflet.js" import { HebrewNumberFormatter } from "./WebsiteCalendar.js"; +import exportFriendly from "./features/export.js"; const harHabait = new KosherZmanim.GeoLocation('Jerusalem, Israel', 31.778, 35.2354, "Asia/Jerusalem"); const hiloulahIndex = new KosherZmanim.HiloulahYomiCalculator(); -class zmanimListUpdater { +export default class zmanimListUpdater { /** * @param {KosherZmanim.GeoLocation} geoLocation */ constructor(geoLocation) { + this.exportManager = new exportFriendly(); + this.jCal = new WebsiteLimudCalendar(); this.jCal.setUseModernHolidays(true); @@ -274,10 +277,10 @@ class zmanimListUpdater { if (!this.buttonsInit) { const downloadBtn = document.getElementById("downloadModalBtn"); - downloadBtn.addEventListener('click', async () => {await this.handleICS()}) + downloadBtn.addEventListener('click', async () => {await this.exportManager.handleICS(this)}) const spreadSheetBtn = document.getElementById("spreadSheetBtn"); - spreadSheetBtn.addEventListener('click', async () => {await this.handleExcel()}) + spreadSheetBtn.addEventListener('click', async () => {await this.exportManager.handleExcel(this)}) const clipboardBtn = document.getElementById('clipboardDownload'); if ('clipboard' in navigator) @@ -303,97 +306,6 @@ class zmanimListUpdater { } } - async handleExcel() { - if (this.midDownload) - return; - - this.midDownload = true; - - /** @type {[string, number, number, number, string]} */ - // @ts-ignore - const glArgs = Object.values(settings.location).map(numberFunc => numberFunc()) - - const { isoDay, isoMonth, isoYear, calendar: isoCalendar } = this.zmanFuncs.coreZC.getDate().getISOFields() - - let availableVS = []; - if (typeof localStorage !== "undefined" && localStorage.getItem('ctNetz') && isValidJSON(localStorage.getItem('ctNetz'))) { - const ctNetz = JSON.parse(localStorage.getItem('ctNetz')) - if (ctNetz.lat == geoLocation.getLatitude() - && ctNetz.lng == geoLocation.getLongitude()) - availableVS = ctNetz.times - } - - /** @type {Parameters} */ - const excelParams = [ - this.zmanFuncs instanceof AmudehHoraahZmanim, - undefined, - glArgs, - this.zmanFuncs.coreZC.isUseElevation(), - this.jCal.getInIsrael(), - this.zmanimList, - true, - { - // @ts-ignore - language: settings.language() == "hb" ? "he" : settings.language(), - zmanInfoSettings: this.zmanInfoSettings, - calcConfig: [settings.calendarToggle.rtKulah(), settings.customTimes.tzeithIssurMelakha()], - seconds: settings.seconds(), - timeFormat: settings.timeFormat(), - netzTimes: availableVS - } - ] - - /** @type {Parameters[1][]} */ - let workerData = []; - let giveData = []; - - const title = (this.zmanFuncs instanceof AmudehHoraahZmanim ? "Amudeh Hora'ah" : "Ohr Hachaim") - + ` Calendar (${isoYear}) - ` + this.geoLocation.getLocationName(); - - const postDataReceive = async () => { - const headerImport = (await import('../excelHeaderData.js')).default; - const headerRow = Object.fromEntries( - [['DATE', {'hb': "יום", en: 'DATE', "en-et": "DATE"}[settings.language()]]] - .concat(Object.entries(headerImport).map(entry => [entry[0], entry[1][settings.language()]])) - ); - - const tableData = [...new Set(workerData.flat().map(field => JSON.stringify(field)))] - .map(field => JSON.parse(field)) - .sort((a, b) => new Date(Object.values(a)[1].v).getTime() - new Date(Object.values(b)[1].v).getTime()) - - const { utils, writeFile } = (await import('../libraries/xlsx.mjs')); - const ws = utils.json_to_sheet([headerRow].concat(tableData), { skipHeader: true }); - const wb = utils.book_new(); - utils.book_append_sheet(wb, ws, "People"); - writeFile(wb, title + ".xlsx"); - this.midDownload = false; - } - - for (let i = 1; i <= this.jCal.getDate().monthsInYear; i++) { - const monthExcelData = [...excelParams] - monthExcelData[1] = [isoYear, i, isoDay, isoCalendar] - giveData.push(monthExcelData) - } - - for (const monthExcelData of giveData) { - if (window.Worker) { - const myWorker = new Worker("/assets/js/features/excelPrepare.js", { type: "module" }); - myWorker.postMessage(monthExcelData) - myWorker.addEventListener("message", async (message) => { - workerData.push(message.data); - if (workerData.length == giveData.length) - await postDataReceive(); - }) - } else { - const excelExport = (await import('./features/excelPrepare.js')).default; - const icsData = excelExport.apply(excelExport, monthExcelData); - workerData.push(icsData); - if (workerData.length == giveData.length) - await postDataReceive(); - } - } - } - async clipboardCopy() { const copyText = this.geoLocation.getLocationName() + "\n\n" + this.jCal.formatFancyDate(undefined, false) + ", " + this.jCal.getDate().year @@ -406,164 +318,6 @@ class zmanimListUpdater { await navigator.clipboard.writeText(copyText); } - async handleICS() { - if (this.midDownload) - return; - - this.midDownload = true; - - /** @type {[string, number, number, number, string]} */ - // @ts-ignore - const glArgs = Object.values(settings.location).map(numberFunc => numberFunc()) - - const { isoDay, isoMonth, isoYear, calendar: isoCalendar } = this.zmanFuncs.coreZC.getDate().getISOFields() - - let availableVS = []; - if (typeof localStorage !== "undefined" && localStorage.getItem('ctNetz') && isValidJSON(localStorage.getItem('ctNetz'))) { - const ctNetz = JSON.parse(localStorage.getItem('ctNetz')) - if (ctNetz.lat == geoLocation.getLatitude() - && ctNetz.lng == geoLocation.getLongitude()) - availableVS = ctNetz.times - } - - /** @type {Parameters} */ - const icsParams = [ - this.zmanFuncs instanceof AmudehHoraahZmanim, - undefined, - glArgs, - this.zmanFuncs.coreZC.isUseElevation(), - this.jCal.getInIsrael(), - this.zmanimList, - true, - { - // @ts-ignore - language: settings.language() == "hb" ? "he" : settings.language(), - timeFormat: settings.timeFormat(), seconds: settings.seconds(), - zmanInfoSettings: this.zmanInfoSettings, - calcConfig: [settings.calendarToggle.rtKulah(), settings.customTimes.tzeithIssurMelakha()], - fasts: Object.fromEntries([...document.querySelector('[data-zfFind="FastDays"]').getElementsByTagName("h5")] - .map(ogHeading => { - /** @type {HTMLHeadingElement} */ - // @ts-ignore - const heading = ogHeading.cloneNode(true); - const [ he, et, en ] = [...heading.children] - .map(langElem => { - while (langElem.querySelector('[data-zfFind="erevTzom"]')) - langElem.querySelector('[data-zfFind="erevTzom"]').remove() - - return langElem.innerHTML.replace(/<.*?>/gm, ''); - }) - - return [heading.getAttribute("data-zfFind"), { he, "en-et": et, en }] - })), - tahanun: Object.fromEntries([...document.querySelector('[data-zfFind="Tachanun"]').children] - .map(/** @returns {[string, string|{"he": string; "en-et": string; "en": string}]} */ - tachObj => - [ - tachObj.getAttribute('data-zfFind'), - // @ts-ignore - tachObj.childElementCount == 0 - ? tachObj.innerHTML - : Object.fromEntries([...tachObj.children] - .map(langElem => [ - langElem.classList.values().find(cl => cl.startsWith('lang-')).replace('lang-', '').replace('hb', 'he'), - langElem.innerHTML - ])) - ])), - netzTimes: availableVS - } - ] - - /** @type {import('../libraries/ics/ics.esm.js').ics.EventAttributes[]} */ - let receiveData = []; - let giveData = []; - - const postDataReceive = async () => { - const ics = (await import('../libraries/ics/ics.esm.js')).ics; - - receiveData = receiveData.flat() - this.zmanFuncs.tekufaCalc.calculateTekufotShemuel(this.zmanFuncs instanceof OhrHachaimZmanim) - .forEach((tekufa, index) => { - const time = tekufa.toZonedDateTime("+02:00").withTimeZone(geoLocation.getTimeZone()) - const tekufaMonth = [ - WebsiteLimudCalendar.TISHREI, - WebsiteLimudCalendar.TEVES, - WebsiteLimudCalendar.NISSAN, - WebsiteLimudCalendar.TAMMUZ, - WebsiteLimudCalendar.TISHREI, - WebsiteLimudCalendar.TEVES, - ] - .map(month => (new WebsiteLimudCalendar(this.jCal.getJewishYear(), month, 15)).formatJewishMonth()) - [index] - - receiveData.push({ - start: time.subtract({ minutes: 30 }).epochMilliseconds, - end: time.add({ minutes: 30 }).epochMilliseconds, - title: { - hb: "תקופת " + tekufaMonth.he, - en: tekufaMonth.en + " Season", - "en-et": "Tekufath " + tekufaMonth.en - }[settings.language()] - }) - }) - - const calName = (this.zmanFuncs instanceof AmudehHoraahZmanim ? "Amudeh Hora'ah" : "Ohr Hachaim") - + ` Calendar (${isoYear}) - ` + this.geoLocation.getLocationName(); - const labeledEvents = - Array.from(new Set(receiveData.map(field => JSON.stringify(field)))).map(field => JSON.parse(field)) - .map(obj => ({ - ...obj, - calName, - /** @type {"utc"} */ - startInputType: "utc", - /** @type {"utc"} */ - endInputType: "utc" - })); - - const icsRespond = ics.createEvents(labeledEvents) - if (icsRespond.error) - throw icsRespond.error; - - const element = document.createElement('a'); - element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(icsRespond.value)); - element.setAttribute('download', calName + ".ics"); - - element.style.display = 'none'; - document.body.appendChild(element); - - element.click(); - - document.body.removeChild(element); - this.midDownload = false; - } - - for (let i = 1; i <= this.jCal.getDate().monthsInYear; i++) { - const monthICSData = [...icsParams] - monthICSData[1] = [isoYear, i, isoDay, isoCalendar] - giveData.push(monthICSData) - } - - for (const monthICSData of giveData) { - if (window.Worker) { - console.log('activate thread') - const myWorker = new Worker("/assets/js/features/icsPrepare.js", { type: "module" }); - myWorker.postMessage(monthICSData) - myWorker.addEventListener("message", async (message) => { - console.log("received message from other thread"); - receiveData.push(message.data) - if (receiveData.length == giveData.length) - await postDataReceive(); - }) - } else { - const icsExport = (await import('./features/icsPrepare.js')).default; - const icsData = icsExport.apply(icsExport, monthICSData); - receiveData.push(icsData); - if (receiveData.length == giveData.length) - await postDataReceive(); - } - } - } - /** * @param {HTMLElement} [parashaBar] */ @@ -644,12 +398,14 @@ class zmanimListUpdater { }); } - const fastJCal = this.jCal.isTaanis() || this.jCal.isTaanisBechoros() ? this.jCal : this.jCal.tomorrow(); + const fastJCal = todayFast ? this.jCal : this.jCal.tomorrow(); const fastCalc = this.zmanFuncs.chainDate(fastJCal.getDate()); const nameElements = [...fastContainer.getElementsByTagName("h5")]; nameElements.forEach(element => element.style.display = "none"); - - const ourFast = nameElements.find(element => element.getAttribute("data-zfFind") == fastJCal.getYomTovIndex().toString()); + + const ourFast = nameElements.find(fastElm => + fastElm.getAttribute("data-zfFind") == (fastJCal.isTaanisBechoros() ? 0 : fastJCal.getYomTovIndex()).toString() + ); hideErev(ourFast); ourFast.style.removeProperty("display"); @@ -665,9 +421,8 @@ class zmanimListUpdater { const erevTzom = timeList.multiDay.firstElementChild; hideErev(erevTzom); - if (erevTzom.lastChild.nodeType == Node.TEXT_NODE) { + if (erevTzom.lastChild.nodeType == Node.TEXT_NODE) erevTzom.lastChild.remove(); - } const erevCalc = this.zmanFuncs.chainDate(fastJCal.getDate().subtract({ days: 1 })); const timeOnErev = @@ -689,9 +444,8 @@ class zmanimListUpdater { } else { timeList.multiDay.style.display = "none"; timeList.oneDay.style.removeProperty("display") - if (timeList.oneDay.lastChild.nodeType == Node.TEXT_NODE) { + if (timeList.oneDay.lastChild.nodeType == Node.TEXT_NODE) timeList.oneDay.lastChild.remove(); - } timeList.oneDay.appendChild(document.createTextNode( fastCalc.getAlotHashachar().toLocaleString(...this.dtF) + ' - ' + fastCalc.getTzaitLechumra().toLocaleString(...this.dtF) @@ -1310,16 +1064,4 @@ const zmanimListUpdater2 = new zmanimListUpdater(geoLocation) // @ts-ignore window.zmanimListUpdater2 = zmanimListUpdater2; // @ts-ignore -window.KosherZmanim = KosherZmanim; - -/** - * @param {string} str - */ -function isValidJSON(str) { - try { - JSON.parse(str); - return true; - } catch (e) { - return false; - } -} \ No newline at end of file +window.KosherZmanim = KosherZmanim; \ No newline at end of file diff --git a/pages/calendar.html b/pages/calendar.html index 73c03d4..01494ac 100644 --- a/pages/calendar.html +++ b/pages/calendar.html @@ -93,11 +93,8 @@
- -
@@ -539,6 +533,7 @@
{% include modals/location.html %} +{% include modals/export.html %} \ No newline at end of file