Asem75 commited on
Commit
8063542
·
verified ·
1 Parent(s): 175e65b

Upload index.html

Browse files
Files changed (1) hide show
  1. 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
- a.push(makePeriod({
1795
- id:'sunrise_rising_forbidden',type:'forbidden',start:pt.sunrise,end:addM(pt.sunrise,15),
 
 
1796
  label:'طلوع الشمس حتى ارتفاعها',approximate:true,
1797
- notes:'نهاية هذه الطبقة تقريبية بصرياً بنحو 15 دقيقة بعد الشروق.'
1798
  }));
1799
 
1800
- // الاستواء قبيل الزوال: نطاق بصري تقريبي
1801
- a.push(makePeriod({
1802
- id:'zenith_forbidden',type:'forbidden',start:addM(pt.dhuhr,-5),end:pt.dhuhr,
1803
- label:'الاستواء قبيل الزوال',approximate:true,
1804
- notes:'النطاق بالدقائق تقريب واجهة؛ الأصل مرتبط بالاستواء الفلكي.'
1805
  }));
1806
 
1807
- // الضحى
1808
- a.push(makePeriod({
1809
- id:'duha_window',type:'recommended',start:addM(pt.sunrise,15),end:addM(pt.dhuhr,-5),
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
- <div class="hour-ruler">${hourCells}${bands}${falseDawnBand}${markers}${solarBoundaryHTML}${userMarkerHTML}
 
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>