Spaces:
Running
Running
Upload index.html
Browse files- index.html +103 -17
index.html
CHANGED
|
@@ -1779,6 +1779,53 @@ function activeForProfile(p){
|
|
| 1779 |
const profile=getV2Settings().fiqhProfile||'general';
|
| 1780 |
return (p.profiles||[]).includes(profile)||(p.profiles||[]).includes('general');
|
| 1781 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1782 |
function buildTimePeriods(pt,thirds){
|
| 1783 |
const a=[];
|
| 1784 |
if(!pt)return a;
|
|
@@ -1790,25 +1837,24 @@ function buildTimePeriods(pt,thirds){
|
|
| 1790 |
a.push(makePeriod({id:'maghrib_prayer_window',type:'prayer',start:pt.maghrib,end:pt.isha,label:'وقت صلاة المغرب'}));
|
| 1791 |
if(thirds?.midpoint)a.push(makePeriod({id:'isha_prayer_window_general',type:'prayer',start:pt.isha,end:thirds.midpoint,label:'وقت العشاء (الحد العام المعروض)'}));
|
| 1792 |
|
| 1793 |
-
|
| 1794 |
-
|
| 1795 |
-
|
|
|
|
|
|
|
| 1796 |
label:'طلوع الشمس حتى ارتفاعها',approximate:true,
|
| 1797 |
-
notes:
|
| 1798 |
}));
|
| 1799 |
|
| 1800 |
-
|
| 1801 |
-
|
| 1802 |
-
|
| 1803 |
-
|
| 1804 |
-
notes:'النطاق بالدقائق تقريب واجهة؛ الأصل مرتبط بالاستواء الفلكي.'
|
| 1805 |
}));
|
| 1806 |
|
| 1807 |
-
// ال
|
| 1808 |
-
|
| 1809 |
-
|
| 1810 |
-
label:'وقت صلاة الضحى',approximate:true
|
| 1811 |
-
}));
|
| 1812 |
|
| 1813 |
// الثلث الأخير
|
| 1814 |
if(thirds?.lastThirdStart)a.push(makePeriod({
|
|
@@ -1817,7 +1863,7 @@ function buildTimePeriods(pt,thirds){
|
|
| 1817 |
}));
|
| 1818 |
|
| 1819 |
// نهي أثناء غروب قرص الشمس: من بدء ملامسة القرص للأفق حتى اكتمال الغروب/دخول المغرب
|
| 1820 |
-
const sunsetStart=estimateSunsetStart(pt);
|
| 1821 |
if(sunsetStart?.date && sunsetStart.date<pt.maghrib){
|
| 1822 |
a.push(makePeriod({
|
| 1823 |
id:'sunset_setting_forbidden',type:'forbidden',
|
|
@@ -2242,6 +2288,17 @@ function solarBoundaryMarkers(pt){
|
|
| 2242 |
id:'sunrise_boundary',kind:'solar_boundary',
|
| 2243 |
name:'شروق الشمس',date:pt.sunrise,css:'sunrise',icon:'☀'
|
| 2244 |
});
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2245 |
const sunsetStart=estimateSunsetStart(pt);
|
| 2246 |
if(sunsetStart)out.push(sunsetStart);
|
| 2247 |
const tw=estimateTwilightBoundaries(pt),fiqhIsha=selectedFiqhIshaBoundary(pt);
|
|
@@ -2291,6 +2348,33 @@ function prayerMarkers(){
|
|
| 2291 |
return Object.keys(n).map(k=>({key:k,name:n[k],date:cachedPrayerTimes[k]}));
|
| 2292 |
}
|
| 2293 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2294 |
buildSectionsHTML = function(pt, nightThirds){
|
| 2295 |
if(!pt)return;
|
| 2296 |
const grid=document.getElementById('sectionsGrid');
|
|
@@ -2359,9 +2443,11 @@ buildSectionsHTML = function(pt, nightThirds){
|
|
| 2359 |
<span class="false-dawn-window-label">نافذة الفجر الكاذب المحتملة</span></div>`;
|
| 2360 |
}
|
| 2361 |
|
|
|
|
| 2362 |
return `<div class="timeline-period" data-start-hour="${startHour}">
|
| 2363 |
-
<div class="period-title"><span>${title}</span><span>كل خانة = ساعة</span></div>
|
| 2364 |
-
|
|
|
|
| 2365 |
<div class="current-time-line" role="button" tabindex="0" onclick="event.stopPropagation();openCurrentHandDetails()" title="اضغط لمعرفة المحطة القادمة والمتبقي" style="display:none"><span class="current-time-head">--:--</span></div>
|
| 2366 |
<div class="celestial-marker" style="display:none"></div>
|
| 2367 |
</div>
|
|
|
|
| 1779 |
const profile=getV2Settings().fiqhProfile||'general';
|
| 1780 |
return (p.profiles||[]).includes(profile)||(p.profiles||[]).includes('general');
|
| 1781 |
}
|
| 1782 |
+
|
| 1783 |
+
function estimateSolarNoon(pt){
|
| 1784 |
+
if(!currentLocation)return pt?.dhuhr||null;
|
| 1785 |
+
const lat=Number(currentLocation.lat),lng=Number(currentLocation.lng);
|
| 1786 |
+
if(!Number.isFinite(lat)||!Number.isFinite(lng))return pt?.dhuhr||null;
|
| 1787 |
+
const guess=pt?.dhuhr instanceof Date?pt.dhuhr:new Date();
|
| 1788 |
+
let lo=guess.getTime()-75*60000,hi=guess.getTime()+75*60000;
|
| 1789 |
+
// maximize solar altitude; independent from user prayer-time adjustments
|
| 1790 |
+
for(let i=0;i<42;i++){
|
| 1791 |
+
const m1=lo+(hi-lo)/3,m2=hi-(hi-lo)/3;
|
| 1792 |
+
if(solarAltitudeAt(new Date(m1),lat,lng)<solarAltitudeAt(new Date(m2),lat,lng))lo=m1;else hi=m2;
|
| 1793 |
+
}
|
| 1794 |
+
return new Date((lo+hi)/2);
|
| 1795 |
+
}
|
| 1796 |
+
function findSolarCrossingWide(guess,altitude,direction,backMin=90,forwardMin=120){
|
| 1797 |
+
if(!currentLocation||!(guess instanceof Date)||isNaN(guess))return null;
|
| 1798 |
+
const lat=Number(currentLocation.lat),lng=Number(currentLocation.lng);
|
| 1799 |
+
if(!Number.isFinite(lat)||!Number.isFinite(lng))return null;
|
| 1800 |
+
const step=60000,start=guess.getTime()-backMin*60000,end=guess.getTime()+forwardMin*60000;
|
| 1801 |
+
let pt=start,pv=solarAltitudeAt(new Date(pt),lat,lng)-altitude;
|
| 1802 |
+
for(let t=start+step;t<=end;t+=step){
|
| 1803 |
+
const v=solarAltitudeAt(new Date(t),lat,lng)-altitude;
|
| 1804 |
+
const hit=direction==='ascending'?(pv<0&&v>=0):(pv>0&&v<=0);
|
| 1805 |
+
if(hit){
|
| 1806 |
+
let lo=pt,hi=t;
|
| 1807 |
+
for(let i=0;i<30;i++){
|
| 1808 |
+
const mid=(lo+hi)/2,mv=solarAltitudeAt(new Date(mid),lat,lng)-altitude;
|
| 1809 |
+
if(direction==='ascending'){if(mv<0)lo=mid;else hi=mid}
|
| 1810 |
+
else {if(mv>0)lo=mid;else hi=mid}
|
| 1811 |
+
}
|
| 1812 |
+
return new Date((lo+hi)/2);
|
| 1813 |
+
}
|
| 1814 |
+
pt=t;pv=v;
|
| 1815 |
+
}
|
| 1816 |
+
return null;
|
| 1817 |
+
}
|
| 1818 |
+
function solarFiqhBoundaries(pt){
|
| 1819 |
+
if(!pt)return{};
|
| 1820 |
+
const solarNoon=estimateSolarNoon(pt);
|
| 1821 |
+
// "ارتفاع الشمس" هنا حد حسابي للرسم مرتبط بارتفاع الشمس الحقيقي، وليس إضافة دقائق ثابتة.
|
| 1822 |
+
// 4.5° سياسة حسابية تقريبية لتمثيل ارتفاعها بعد الشروق؛ تبقى التفاصيل الفقهية في Registry.
|
| 1823 |
+
const risenAltitude=4.5;
|
| 1824 |
+
const sunriseRaised=findSolarCrossingWide(new Date(pt.sunrise.getTime()+20*60000),risenAltitude,'ascending',35,70);
|
| 1825 |
+
const sunsetStart=estimateSunsetStart(pt)?.date||null;
|
| 1826 |
+
return {solarNoon,sunriseRaised,duhaStart:sunriseRaised,duhaEnd:solarNoon,sunsetStart,risenAltitude};
|
| 1827 |
+
}
|
| 1828 |
+
|
| 1829 |
function buildTimePeriods(pt,thirds){
|
| 1830 |
const a=[];
|
| 1831 |
if(!pt)return a;
|
|
|
|
| 1837 |
a.push(makePeriod({id:'maghrib_prayer_window',type:'prayer',start:pt.maghrib,end:pt.isha,label:'وقت صلاة المغرب'}));
|
| 1838 |
if(thirds?.midpoint)a.push(makePeriod({id:'isha_prayer_window_general',type:'prayer',start:pt.isha,end:thirds.midpoint,label:'وقت العشاء (الحد العام المعروض)'}));
|
| 1839 |
|
| 1840 |
+
const solar=solarFiqhBoundaries(pt);
|
| 1841 |
+
|
| 1842 |
+
// أوقات مرتبطة بحركة الشمس نفسها، لا بإضافة عدد ثابت من الدقائق.
|
| 1843 |
+
if(solar.sunriseRaised)a.push(makePeriod({
|
| 1844 |
+
id:'sunrise_rising_forbidden',type:'forbidden',start:pt.sunrise,end:solar.sunriseRaised,
|
| 1845 |
label:'طلوع الشمس حتى ارتفاعها',approximate:true,
|
| 1846 |
+
notes:`النهاية محسوبة من ارتفاع الشمس الفعلي (${solar.risenAltitude}° كسياسة عرض حسابية)، وليست +15 دقيقة ثابتة.`
|
| 1847 |
}));
|
| 1848 |
|
| 1849 |
+
if(solar.duhaStart && solar.duhaEnd && solar.duhaEnd>solar.duhaStart)a.push(makePeriod({
|
| 1850 |
+
id:'duha_window',type:'recommended',start:solar.duhaStart,end:solar.duhaEnd,
|
| 1851 |
+
label:'وقت الضحى حتى الاستواء الشمسي',approximate:true,
|
| 1852 |
+
notes:'البداية والنهاية مشتقتان من موضع الشمس الفعلي؛ لا تستخدم نافذة دقائق ثابتة.'
|
|
|
|
| 1853 |
}));
|
| 1854 |
|
| 1855 |
+
// الاستواء/الزوال حد شمسي، وليس شريط خمس دقائق مصطنع.
|
| 1856 |
+
// يعرض كنقطة زمنية مستقلة على المسطرة عبر solarBoundaryMarkers.
|
| 1857 |
+
|
|
|
|
|
|
|
| 1858 |
|
| 1859 |
// الثلث الأخير
|
| 1860 |
if(thirds?.lastThirdStart)a.push(makePeriod({
|
|
|
|
| 1863 |
}));
|
| 1864 |
|
| 1865 |
// نهي أثناء غروب قرص الشمس: من بدء ملامسة القرص للأفق حتى اكتمال الغروب/دخول المغرب
|
| 1866 |
+
const sunsetStart=solar.sunsetStart?{date:solar.sunsetStart}:estimateSunsetStart(pt);
|
| 1867 |
if(sunsetStart?.date && sunsetStart.date<pt.maghrib){
|
| 1868 |
a.push(makePeriod({
|
| 1869 |
id:'sunset_setting_forbidden',type:'forbidden',
|
|
|
|
| 2288 |
id:'sunrise_boundary',kind:'solar_boundary',
|
| 2289 |
name:'شروق الشمس',date:pt.sunrise,css:'sunrise',icon:'☀'
|
| 2290 |
});
|
| 2291 |
+
const sf=solarFiqhBoundaries(pt);
|
| 2292 |
+
if(sf.sunriseRaised)out.push({
|
| 2293 |
+
id:'sun_raised_boundary',kind:'solar_boundary',
|
| 2294 |
+
name:'ارتفاع الشمس وبداية الضحى',date:sf.sunriseRaised,css:'fiqh-boundary',icon:'☀',
|
| 2295 |
+
note:'محسوب من ارتفاع الشمس الحقيقي، وليس من إضافة دقائق ثابتة إلى الشروق.'
|
| 2296 |
+
});
|
| 2297 |
+
if(sf.solarNoon)out.push({
|
| 2298 |
+
id:'solar_noon_boundary',kind:'solar_boundary',
|
| 2299 |
+
name:'الاستواء الشمسي / حد الزوال',date:sf.solarNoon,css:'fiqh-boundary',icon:'☀',
|
| 2300 |
+
note:'لحظة الاستواء محسوبة من أعلى ارتفاع للشمس في هذا اليوم والموقع؛ لا تُعرض كفترة خمس دقائق.'
|
| 2301 |
+
});
|
| 2302 |
const sunsetStart=estimateSunsetStart(pt);
|
| 2303 |
if(sunsetStart)out.push(sunsetStart);
|
| 2304 |
const tw=estimateTwilightBoundaries(pt),fiqhIsha=selectedFiqhIshaBoundary(pt);
|
|
|
|
| 2348 |
return Object.keys(n).map(k=>({key:k,name:n[k],date:cachedPrayerTimes[k]}));
|
| 2349 |
}
|
| 2350 |
|
| 2351 |
+
|
| 2352 |
+
function accessibleTimelineForPanel(startHour,periods,prayers,solarMarkers){
|
| 2353 |
+
const dayStart=new Date(cachedPrayerTimes.fajr);dayStart.setHours(0,0,0,0);
|
| 2354 |
+
const rows=[];
|
| 2355 |
+
const push=(date,label,action='')=>{
|
| 2356 |
+
if(!(date instanceof Date)||isNaN(date))return;
|
| 2357 |
+
const mins=localMinutesOfDay(date);
|
| 2358 |
+
if(mins<startHour*60||mins>=(startHour+6)*60)return;
|
| 2359 |
+
rows.push({date,label,action});
|
| 2360 |
+
};
|
| 2361 |
+
for(let i=0;i<6;i++){
|
| 2362 |
+
const d=new Date(dayStart);d.setHours(startHour+i,0,0,0);
|
| 2363 |
+
push(d,`الساعة ${String(startHour+i).padStart(2,'0')}:00`);
|
| 2364 |
+
}
|
| 2365 |
+
prayers.forEach(x=>push(x.date,`${x.name}، ${fmtTime(x.date)}`,`openTimelinePointDetails('${x.key}')`));
|
| 2366 |
+
solarMarkers.forEach(x=>push(x.date,`${x.name}، ${fmtTime(x.date)}`,`openSolarBoundaryDetails('${x.id}')`));
|
| 2367 |
+
userTimelineMarkers(new Date()).forEach(x=>push(x.date,`${x.name}، ${fmtTime(x.date)}`,`openTimelinePointDetails('${x.id}')`));
|
| 2368 |
+
periods.forEach((x,i)=>{
|
| 2369 |
+
push(x.start,`بداية ${x.label}، ${fmtTime(x.start)}`,`openPeriodDetailsByIndex(${i})`);
|
| 2370 |
+
push(x.end,`نهاية ${x.label}، ${fmtTime(x.end)}`,`openPeriodDetailsByIndex(${i})`);
|
| 2371 |
+
});
|
| 2372 |
+
rows.sort((a,b)=>a.date-b.date || a.label.localeCompare(b.label,'ar'));
|
| 2373 |
+
return `<ol class="sr-only" aria-label="المسطرة الزمنية من ${String(startHour).padStart(2,'0')}:00 إلى ${String(startHour+6).padStart(2,'0')}:00">${
|
| 2374 |
+
rows.map(r=>`<li>${r.action?`<button type="button" onclick="${r.action}" aria-label="${escapeHtml(r.label)}">${escapeHtml(r.label)}</button>`:`<span tabindex="0" aria-label="${escapeHtml(r.label)}">${escapeHtml(r.label)}</span>`}</li>`).join('')
|
| 2375 |
+
}</ol>`;
|
| 2376 |
+
}
|
| 2377 |
+
|
| 2378 |
buildSectionsHTML = function(pt, nightThirds){
|
| 2379 |
if(!pt)return;
|
| 2380 |
const grid=document.getElementById('sectionsGrid');
|
|
|
|
| 2443 |
<span class="false-dawn-window-label">نافذة الفجر الكاذب المحتملة</span></div>`;
|
| 2444 |
}
|
| 2445 |
|
| 2446 |
+
const accessibleTimeline=accessibleTimelineForPanel(startHour,periods,prayers,solarMarkers);
|
| 2447 |
return `<div class="timeline-period" data-start-hour="${startHour}">
|
| 2448 |
+
<div class="period-title" aria-hidden="true"><span>${title}</span><span>كل خانة = ساعة</span></div>
|
| 2449 |
+
${accessibleTimeline}
|
| 2450 |
+
<div class="hour-ruler" aria-hidden="true">${hourCells}${bands}${falseDawnBand}${markers}${solarBoundaryHTML}${userMarkerHTML}
|
| 2451 |
<div class="current-time-line" role="button" tabindex="0" onclick="event.stopPropagation();openCurrentHandDetails()" title="اضغط لمعرفة المحطة القادمة والمتبقي" style="display:none"><span class="current-time-head">--:--</span></div>
|
| 2452 |
<div class="celestial-marker" style="display:none"></div>
|
| 2453 |
</div>
|