PageSourceSearch

https://compressoryar.ir/wp-content/litespeed/js/7089ad1dcc85bdb75a85255c41efb831.js?ver=fb831

js compressoryar.ir collected 2026-09-24 14:23:44 UTC 27,407 bytes, 389 lines download raw bytes

1/**
2 * Persian Calendar Component - Standalone Version
3 * @version 1.2.7
4 * @license MIT
5 */
6(function(){'use strict';const PERSIAN_CALENDAR_STYLES=`
7    /* Persian Calendar Popup Container */
8    .persian-date-popup {
9      background: #fff !important;
10      border: 1px solid #ccc !important;
11      box-shadow: 0 4px 20px rgba(0, 0, 0, 0.15) !important;
12      border-radius: 8px !important;
13      padding: 16px !important;
14      width: 290px !important;
15      box-sizing: border-box !important;
16      font-family: 'VazirMatn', 'Vazir', 'VazirmatnVF', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
17      -webkit-animation: fpFadeInDown 300ms cubic-bezier(0.23, 1, 0.32, 1);
18      animation: fpFadeInDown 300ms cubic-bezier(0.23, 1, 0.32, 1);
19    }
20    .persian-date-popup * {
21      box-sizing: border-box !important;
22      font-family: 'VazirMatn', 'Vazir', 'VazirmatnVF', -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif !important;
23    }
24    @-webkit-keyframes fpFadeInDown {
25      from { opacity: 0; -webkit-transform: translate3d(0, -20px, 0); transform: translate3d(0, -20px, 0); }
26      to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); }
27    }
28    @keyframes fpFadeInDown {
29      from { opacity: 0; -webkit-transform: translate3d(0, -20px, 0); transform: translate3d(0, -20px, 0); }
30      to { opacity: 1; -webkit-transform: translate3d(0, 0, 0); transform: translate3d(0, 0, 0); }
31    }
32
33    /* Calendar Wrapper Reset */
34    .persian-calendar-wrapper {
35      background: transparent !important;
36      border: none !important;
37      box-shadow: none !important;
38      padding: 0 !important;
39      direction: rtl;
40      text-align: right;
41      position: relative;
42      max-width: 100% !important;
43    }
44
45    /* Month and Year Header Navigation */
46    .persian-calendar-nav {
47      display: flex !important;
48      gap: 6px !important;
49      align-items: center !important;
50      justify-content: space-between !important;
51      margin-bottom: 12px !important;
52      padding: 0 !important;
53      height: 32px !important;
54    }
55
56    /* Header Clickable Labels (No border) */
57    .persian-calendar-header-labels {
58      display: flex !important;
59      gap: 6px !important;
60      align-items: center !important;
61    }
62    .persian-calendar-month-label,
63    .persian-calendar-year-label,
64    .persian-calendar-year-label-view,
65    .persian-calendar-years-range-label {
66      font-size: 14px !important;
67      font-weight: 600 !important;
68      color: #1e1e1e !important;
69      padding: 4px 8px !important;
70      border-radius: 4px !important;
71      user-select: none !important;
72      transition: background-color 0.15s ease, color 0.15s ease !important;
73    }
74    .persian-calendar-month-label[role="button"],
75    .persian-calendar-year-label[role="button"],
76    .persian-calendar-year-label-view[role="button"] {
77      cursor: pointer !important;
78    }
79    .persian-calendar-month-label[role="button"]:hover,
80    .persian-calendar-year-label[role="button"]:hover,
81    .persian-calendar-year-label-view[role="button"]:hover {
82      background-color: #f7f9fe !important;
83      color: #3858e9 !important;
84    }
85
86    /* Prev & Next Buttons */
87    .persian-calendar-prev,
88    .persian-calendar-next,
89    .persian-calendar-prev-year,
90    .persian-calendar-next-year,
91    .persian-calendar-prev-years,
92    .persian-calendar-next-years {
93      background: transparent !important;
94      border: none !important;
95      box-shadow: none !important;
96      padding: 0 !important;
97      margin: 0 !important;
98      cursor: pointer !important;
99      box-sizing: border-box !important;
100      text-shadow: none !important;
101      width: 32px !important;
102      height: 32px !important;
103      display: inline-flex !important;
104      align-items: center !important;
105      justify-content: center !important;
106      font-size: 20px !important;
107      color: #3858e9 !important;
108      border-radius: 2px !important;
109      transition: background-color 0.1s ease !important;
110    }
111    .persian-calendar-prev:hover,
112    .persian-calendar-next:hover,
113    .persian-calendar-prev-year:hover,
114    .persian-calendar-next-year:hover,
115    .persian-calendar-prev-years:hover,
116    .persian-calendar-next-years:hover {
117      background-color: #f7f9fe !important;
118      color: #183ad6 !important;
119    }
120    .persian-calendar-prev:focus,
121    .persian-calendar-prev:active,
122    .persian-calendar-next:focus,
123    .persian-calendar-next:active {
124      background-color: #eff2fe !important;
125      color: #183ad6 !important;
126      outline: none !important;
127    }
128
129    /* Grid & Weekdays */
130    .persian-calendar-grid { margin-top: 12px; }
131    .persian-calendar-weekdays {
132      display: grid;
133      grid-template-columns: repeat(7, 1fr);
134      gap: 4px;
135      margin-bottom: 8px;
136    }
137    .persian-calendar-weekday {
138      text-align: center;
139      font-size: 12px;
140      font-weight: 500;
141      color: #757575;
142      padding: 4px;
143    }
144    .persian-calendar-days {
145      display: grid;
146      grid-template-columns: repeat(7, 1fr);
147      gap: 4px;
148    }
149
150    /* Day Display */
151    .persian-calendar-day {
152      padding: 0 !important;
153      height: 28px !important;
154      width: 28px !important;
155      display: flex !important;
156      align-items: center !important;
157      justify-content: center !important;
158      box-sizing: border-box !important;
159      border-radius: 50% !important;
160      margin: 0 auto !important;
161      font-size: 14px !important;
162      cursor: pointer !important;
163      transition: none !important;
164      position: relative;
165    }
166    .persian-calendar-day:not(.empty):hover {
167      color: #3858e9 !important;
168    }
169    .persian-calendar-day.today {
170      background: #e0e0e0 !important;
171      font-weight: 500 !important;
172    }
173    .persian-calendar-day.selected {
174      background: #3858e9 !important;
175      color: white !important;
176      font-weight: 600 !important;
177    }
178    .persian-calendar-day.selected:hover {
179      color: white !important;
180    }
181    .persian-calendar-day.empty {
182      cursor: default;
183      pointer-events: none;
184    }
185
186    /* Months and Years Selection Grids */
187    .persian-calendar-months-grid,
188    .persian-calendar-years-grid {
189      display: grid !important;
190      grid-template-columns: repeat(3, 1fr) !important;
191      gap: 8px !important;
192      margin-top: 12px !important;
193    }
194    .persian-calendar-month-item,
195    .persian-calendar-year-item {
196      display: flex !important;
197      align-items: center !important;
198      justify-content: center !important;
199      height: 40px !important;
200      border-radius: 6px !important;
201      font-size: 13px !important;
202      cursor: pointer !important;
203      background: #fdfdfd !important;
204      border: none !important;
205      transition: all 0.15s ease !important;
206      user-select: none !important;
207      color: #1e1e1e !important;
208    }
209    .persian-calendar-month-item:hover,
210    .persian-calendar-year-item:hover {
211      background: #f7f9fe !important;
212      color: #3858e9 !important;
213    }
214    .persian-calendar-month-item.system-current,
215    .persian-calendar-year-item.system-current {
216      color: #1e1e1e !important;
217      font-weight: 600 !important;
218      background: #e0e0e0 !important;
219    }
220    .persian-calendar-month-item.active,
221    .persian-calendar-year-item.active {
222      background: #3858e9 !important;
223      color: white !important;
224      font-weight: 600 !important;
225      border: none !important;
226    }
227
228    /* Time Picker Styles (Inputs with Up/Down Arrows) */
229    .persian-calendar-time-picker {
230      display: flex !important;
231      align-items: center !important;
232      justify-content: center !important;
233      gap: 8px !important;
234      margin-top: 10px !important;
235      padding-top: 10px !important;
236      border-top: 1px solid #eee !important;
237      direction: rtl !important;
238    }
239    .persian-calendar-time-title {
240      font-size: 13px !important;
241      font-weight: 600 !important;
242      color: #333 !important;
243      margin-left: 2px !important;
244    }
245    .persian-calendar-time-box {
246      display: inline-flex !important;
247      align-items: center !important;
248      border: 1px solid #ccc !important;
249      border-radius: 6px !important;
250      background: #fff !important;
251      overflow: hidden !important;
252      height: 32px !important;
253      direction: ltr !important;
254    }
255    .persian-calendar-time-input {
256      width: 36px !important;
257      height: 100% !important;
258      border: none !important;
259      outline: none !important;
260      background: transparent !important;
261      text-align: center !important;
262      font-size: 14px !important;
263      font-weight: 600 !important;
264      color: #1e1e1e !important;
265      font-family: inherit !important;
266      padding: 0 !important;
267      margin: 0 !important;
268      -moz-appearance: textfield !important;
269    }
270    .persian-calendar-time-input::-webkit-outer-spin-button,
271    .persian-calendar-time-input::-webkit-inner-spin-button {
272      -webkit-appearance: none !important;
273      margin: 0 !important;
274    }
275    .persian-calendar-time-arrows {
276      display: flex !important;
277      flex-direction: column !important;
278      height: 100% !important;
279      width: 18px !important;
280      border-left: 1px solid #eee !important;
281      background: #f9f9f9 !important;
282    }
283    .persian-calendar-time-arrow {
284      flex: 1 !important;
285      border: none !important;
286      background: transparent !important;
287      cursor: pointer !important;
288      font-size: 8px !important;
289      color: #555 !important;
290      display: flex !important;
291      align-items: center !important;
292      justify-content: center !important;
293      padding: 0 !important;
294      margin: 0 !important;
295      line-height: 1 !important;
296      user-select: none !important;
297      transition: background-color 0.1s ease, color 0.1s ease !important;
298    }
299    .persian-calendar-time-arrow:hover {
300      background-color: #eef2ff !important;
301      color: #3858e9 !important;
302    }
303    .persian-calendar-time-arrow:active {
304      background-color: #e0e7ff !important;
305    }
306    .persian-calendar-time-separator {
307      font-weight: bold !important;
308      font-size: 16px !important;
309      color: #333 !important;
310    }
311
312    @media (max-width: 480px) {
313      .persian-calendar-wrapper { max-width: 100%; margin: 0 auto; }
314    }
315    @media (prefers-contrast: high) {
316      .persian-calendar-wrapper { border: 2px solid #000; }
317      .persian-calendar-day.selected { border: 2px solid #000; }
318    }
319    @media (prefers-reduced-motion: reduce) {
320      .persian-calendar-day, .persian-calendar-prev, .persian-calendar-next { transition: none; }
321    }
322  `;let stylesInjected=!1;function injectStyles(){if(stylesInjected)return;const styleElement=document.createElement('style');styleElement.id='persian-calendar-styles';styleElement.textContent=PERSIAN_CALENDAR_STYLES;document.head.appendChild(styleElement);stylesInjected=!0}
323const G_DAYS_IN_MONTH_NON_LEAP=[0,31,59,90,120,151,181,212,243,273,304,334];const JALALI_EPOCH_DIFFERENCE=355666;const JALALI_33_YEAR_CYCLE_DAYS=12053;const GREGORIAN_4_YEAR_CYCLE_DAYS=1461;const JALALI_YEAR_START_OFFSET=-1595;const GREGORIAN_EPOCH_DIFFERENCE=-355668;const JALALI_33_YEAR_CYCLE_LEAP_DAYS=8;const GREGORIAN_400_YEAR_CYCLE_DAYS=146097;const GREGORIAN_100_YEAR_CYCLE_DAYS=36524;const isValidGregorian=(gy,gm,gd)=>{if(!Number.isInteger(gy)||!Number.isInteger(gm)||!Number.isInteger(gd))return!1;return!(gy<1||gy>3000||gm<1||gm>12||gd<1||gd>31)};const isValidJalali=(jy,jm,jd)=>{if(!Number.isInteger(jy)||!Number.isInteger(jm)||!Number.isInteger(jd))return!1;return!(jy<1||jy>3000||jm<1||jm>12||jd<1||jd>31)};const gregorianToJalali=(gy,gm,gd)=>{if(!isValidGregorian(gy,gm,gd))return[0,0,0];const gy2=gm>2?(gy+1):gy;let days=JALALI_EPOCH_DIFFERENCE+(365*gy)+Math.floor((gy2+3)/4)-Math.floor((gy2+99)/100)+Math.floor((gy2+399)/400)+gd+G_DAYS_IN_MONTH_NON_LEAP[gm-1];let jy=JALALI_YEAR_START_OFFSET+33*Math.floor(days/JALALI_33_YEAR_CYCLE_DAYS);days%=JALALI_33_YEAR_CYCLE_DAYS;jy+=4*Math.floor(days/GREGORIAN_4_YEAR_CYCLE_DAYS);days%=GREGORIAN_4_YEAR_CYCLE_DAYS;if(days>365){jy+=Math.floor((days-1)/365);days=(days-1)%365}
324let jm,jd;if(days<186){jm=1+Math.floor(days/31);jd=1+(days%31)}else{jm=7+Math.floor((days-186)/30);jd=1+((days-186)%30)}
325return[jy,jm,jd]};const jalaliToGregorian=(jy,jm,jd)=>{if(!isValidJalali(jy,jm,jd))return[0,0,0];const jy_adj=jy+1595;let days=GREGORIAN_EPOCH_DIFFERENCE+(365*jy_adj)+(Math.floor(jy_adj/33)*JALALI_33_YEAR_CYCLE_LEAP_DAYS)+Math.floor(((jy_adj%33)+3)/4)+jd;if(jm<7)days+=(jm-1)*31;else days+=(jm-7)*30+186;let gy=400*Math.floor(days/GREGORIAN_400_YEAR_CYCLE_DAYS);days%=GREGORIAN_400_YEAR_CYCLE_DAYS;if(days>GREGORIAN_100_YEAR_CYCLE_DAYS){gy+=100*Math.floor(--days/GREGORIAN_100_YEAR_CYCLE_DAYS);days%=GREGORIAN_100_YEAR_CYCLE_DAYS;if(days>=365)days++}
326gy+=4*Math.floor(days/GREGORIAN_4_YEAR_CYCLE_DAYS);days%=GREGORIAN_4_YEAR_CYCLE_DAYS;if(days>365){gy+=Math.floor((days-1)/365);days=(days-1)%365}
327let gd=days+1;const isLeap=((gy%4===0)&&(gy%100!==0))||(gy%400===0);const G_DAYS_IN_MONTH=[0,31,isLeap?29:28,31,30,31,30,31,31,30,31,30,31];let gm;for(gm=1;gm<=12;gm++){if(gd<=G_DAYS_IN_MONTH[gm])break;gd-=G_DAYS_IN_MONTH[gm]}
328return[gy,gm,gd]};const safeParseInt=(value,defaultValue=0,min=null,max=null)=>{const parsed=parseInt(value,10);if(isNaN(parsed))return defaultValue;if(min!==null&&parsed<min)return min;if(max!==null&&parsed>max)return max;return parsed};const isValidJalaliDate=(year,month,day)=>year>=1&&year<=3000&&month>=1&&month<=12&&day>=1&&day<=31;const PERSIAN_MONTHS=['فروردین','اردیبهشت','خرداد','تیر','مرداد','شهریور','مهر','آبان','آذر','دی','بهمن','اسفند'];const PERSIAN_WEEKDAYS=['ش','ی','د','س','چ','پ','ج'];const PERSIAN_DIGITS=['۰','۱','۲','۳','۴','۵','۶','۷','۸','۹'];const toPersianDigits=(str)=>String(str).replace(/[0-9]/g,(d)=>PERSIAN_DIGITS[d]);const toAsciiDigits=(str)=>String(str).replace(/[۰-۹]/g,(d)=>PERSIAN_DIGITS.indexOf(d).toString());const getDaysInJalaliMonth=(jy,jm)=>{if(jm<=6)return 31;if(jm<=11)return 30;const leapYears=[1,5,9,13,17,22,26,30];return leapYears.includes(jy%33)?30:29};const IRAN_OFFSET_MINUTES=210;const getIranLocalDate=()=>{const now=new Date();const browserOffsetMinutes=-now.getTimezoneOffset();const diffMinutes=IRAN_OFFSET_MINUTES-browserOffsetMinutes;return new Date(now.getTime()+diffMinutes*60*1000)};class PersianCalendar{constructor(container,options={}){if(!container||!(container instanceof Element))throw new Error('PersianCalendar: Invalid container element');injectStyles();this.container=container;this.options={selectedDate:(options.selectedDate instanceof Date)?options.selectedDate:new Date(),enableTime:!!options.enableTime,selectedHour:typeof options.selectedHour==='number'?options.selectedHour:null,selectedMinute:typeof options.selectedMinute==='number'?options.selectedMinute:null,onDateSelect:(typeof options.onDateSelect==='function')?o
328ptions.onDateSelect:()=>{},onClose:(typeof options.onClose==='function')?options.onClose:()=>{},title:options.title||'انتخاب تاریخ',...options};let initialDate=this.options.selectedDate;const browserOffsetMinutes=-initialDate.getTimezoneOffset();const diffMinutes=IRAN_OFFSET_MINUTES-browserOffsetMinutes;initialDate=new Date(initialDate.getTime()+diffMinutes*60*1000);const[jy,jm,jd]=gregorianToJalali(initialDate.getFullYear(),initialDate.getMonth()+1,initialDate.getDate());this.currentYear=jy;this.currentMonth=jm;this.selectedDate={year:jy,month:jm,day:jd};this.selectedHour=this.options.selectedHour!==null?this.options.selectedHour:initialDate.getHours();this.selectedMinute=this.options.selectedMinute!==null?this.options.selectedMinute:initialDate.getMinutes();this.viewMode='days';this._boundClickHandler=null;this.render();this.attachEventListeners()}
329render(){this.container.textContent='';const wrapper=document.createElement('div');wrapper.className='persian-calendar-wrapper';this.container.appendChild(wrapper);this.updateCalendarView()}
330createDaysFragment(){const daysInMonth=getDaysInJalaliMonth(this.currentYear,this.currentMonth);const[gy,gm,gd]=jalaliToGregorian(this.currentYear,this.currentMonth,1);const jsDay=new Date(Date.UTC(gy,gm-1,gd)).getUTCDay();const startDay=(jsDay+1)%7;const today=getIranLocalDate();const[todayJy,todayJm,todayJd]=gregorianToJalali(today.getFullYear(),today.getMonth()+1,today.getDate());const isTodayMonth=(this.currentMonth===todayJm&&this.currentYear===todayJy);const isSelectedMonth=(this.currentMonth===this.selectedDate.month&&this.currentYear===this.selectedDate.year);const fragment=document.createDocumentFragment();for(let i=0;i<startDay;i++){const emptyDay=document.createElement('div');emptyDay.className='persian-calendar-day empty';emptyDay.setAttribute('aria-hidden','true');fragment.appendChild(emptyDay)}
331for(let day=1;day<=daysInMonth;day++){const dayElement=document.createElement('div');dayElement.className='persian-calendar-day';dayElement.setAttribute('data-day',day.toString());dayElement.setAttribute('role','gridcell');dayElement.setAttribute('tabindex','0');dayElement.textContent=toPersianDigits(day);if(isTodayMonth&&day===todayJd){dayElement.classList.add('today');dayElement.setAttribute('aria-current','date')}
332if(isSelectedMonth&&day===this.selectedDate.day){dayElement.classList.add('selected');dayElement.setAttribute('aria-selected','true')}
333fragment.appendChild(dayElement)}
334return fragment}
335attachEventListeners(){this._boundClickHandler=(e)=>{const target=e.target;if(target.matches('.persian-calendar-day:not(.empty)')){const day=safeParseInt(target.dataset.day,1,1,31);if(isValidJalaliDate(this.currentYear,this.currentMonth,day))this.selectDate(this.currentYear,this.currentMonth,day);}else if(target.matches('.persian-calendar-prev')){this.previousMonth()}else if(target.matches('.persian-calendar-next')){this.nextMonth()}else if(target.closest('.persian-calendar-month-label')){this.viewMode='months';this.updateCalendarView()}else if(target.closest('.persian-calendar-year-label')||target.closest('.persian-calendar-year-label-view')){this.viewMode='years';this.updateCalendarView()}else if(target.matches('.persian-calendar-prev-year')){this.currentYear--;this.updateCalendarView()}else if(target.matches('.persian-calendar-next-year')){this.currentYear++;this.updateCalendarView()}else if(target.closest('.persian-calendar-month-item')){const item=target.closest('.persian-calendar-month-item');this.currentMonth=parseInt(item.dataset.month,10);this.viewMode='days';this.updateCalendarView()}else if(target.matches('.persian-calendar-prev-years')){this.currentYear-=12;this.updateCalendarView()}else if(target.matches('.persian-calendar-next-years')){this.currentYear+=12;this.updateCalendarView()}else if(target.closest('.persian-calendar-year-item')){const item=target.closest('.persian-calendar-year-item');this.currentYear=parseInt(item.dataset.year,10);this.viewMode='days';this.updateCalendarView()}};this.container.addEventListener('click',this._boundClickHandler)}
336selectDate(year,month,day){this.selectedDate={year,month,day};this.updateCalendarView();this.notifyDateChange()}
337previousMonth(){this.currentMonth--;if(this.currentMonth<1){this.currentMonth=12;this.currentYear--}
338this.updateCalendarView()}
339nextMonth(){this.currentMonth++;
339if(this.currentMonth>12){this.currentMonth=1;this.currentYear++}
340this.updateCalendarView()}
341updateCalendarView(){const wrapper=this.container.querySelector('.persian-calendar-wrapper');if(!wrapper)return;wrapper.textContent='';const datePicker=document.createElement('div');datePicker.className='persian-calendar-date-picker';const nav=document.createElement('div');nav.className='persian-calendar-nav';const body=document.createElement('div');body.className='persian-calendar-body';if(this.viewMode==='days'){nav.innerHTML=`
342          <button class="persian-calendar-prev" type="button" aria-label="ماه قبل">‹</button>
343          <div class="persian-calendar-header-labels">
344            <span class="persian-calendar-month-label" role="button" tabindex="0">${PERSIAN_MONTHS[this.currentMonth - 1]}</span>
345            <span class="persian-calendar-year-label" role="button" tabindex="0">${toPersianDigits(this.currentYear)}</span>
346          </div>
347          <button class="persian-calendar-next" type="button" aria-label="ماه بعد">›</button>
348        `;body.innerHTML=`
349          <div class="persian-calendar-grid">
350            <div class="persian-calendar-weekdays">${PERSIAN_WEEKDAYS.map(day => `<div class="persian-calendar-weekday">${day}</div>`).join('')}</div>
351            <div class="persian-calendar-days" role="grid" aria-label="تقویم"></div>
352          </div>
353        `;datePicker.appendChild(nav);datePicker.appendChild(body);const daysContainer=body.querySelector('.persian-calendar-days');daysContainer.appendChild(this.createDaysFragment());if(this.options.enableTime){const timePicker=document.createElement('div');timePicker.className='persian-calendar-time-picker';const hStr=String(this.selectedHour).padStart(2,'0');const mStr=String(this.selectedMinute).padStart(2,'0');timePicker.innerHTML=`
354            <span class="persian-calendar-time-title">زمان:</span>
355            <div class="persian-calendar-time-box">
356              <input type="number" class="persian-calendar-time-input persian-calendar-minute-input" min="0" max="59" value="${mStr}" dir="ltr">
357              <div class="persian-calendar-time-arrows">
358                <button type="button" class="persian-calendar-time-arrow arrow-up-minute" tabindex="-1">▲</button>
359                <button type="button" class="persian-calendar-time-arrow arrow-down-minute" tabindex="-1">▼</button>
360              </div>
361            </div>
362            <span class="persian-calendar-time-separator">:</span>
363            <div class="persian-calendar-time-box">
364              <input type="number" class="persian-calendar-time-input persian-calendar-hour-input" min="0" max="23" value="${hStr}" dir="ltr">
365              <div class="persian-calendar-time-arrows">
366                <button type="button" class="persian-calendar-time-arrow arrow-up-hour" tabindex="-1">▲</button>
367                <button type="button" class="persian-calendar-time-arrow arrow-down-hour" tabindex="-1">▼</button>
368              </div>
369            </div>
370          `;datePicker.appendChild(timePicker);const hourInput=timePicker.querySelector('.persian-calendar-hour-input');const minInput=timePicker.querySelector('.persian-calendar-minute-input');const upHour=timePicker.querySelector('.arrow-up-hour');const downHour=timePicker.querySelector('.arrow-down-hour');const upMin=timePicker.querySelector('.arrow-up-minute');const downMin=timePicker.querySelector('.arrow-down-minute');const updateHour=(val)=>{let h=parseInt(val,10);if(isNaN(h))h=0;if(h>23)h=0;if(h<0)h=23;this.selectedHour=h;hourInput.value=String(h).padStart(2,'0');this.notifyDateChange()};const updateMin=(val)=>{let m=parseInt(val,10);if(isNaN(m))m=0;if(m>59)m=0;if(m<0)m=59;this.selectedMinute=m;minInput.value=String(m).padStart(2,'0');this.notifyDateChange()};hourInput.addEventListener('change',(e)=>updateHour(e.target.value));hourInput.addEventListener('input',(e)=>{if(e.target.value.length>=2)updateHour(e.target.value);});minInput.addEventListener('change',(e)=>updateMin(e.target.value));minInput.addEventListener('input',(e)=>{if(e.target.value.length>=2)updateMin(e.target.value);});upHour.addEventListener('click',(e)=>{e.preventDefault();e.stopPropagation();updateHour(this.selectedHour+1)});downHour.addEventListener('click',(e)=>{e.preventDefault();e.stopPropagation();updateHour(this.selectedHour-1)});upMin.addEventListener('click',(e)=>{e.preventDefault();e.stopPropagation();updateMin(this.selectedMinute+1)});downMin.addEventListener('click',(e)=>{e.preventDefault();e.stopPropagation();updateMin(this.selectedMinute-1)})}}else if(this.viewMode==='months'){nav.innerHTML=`
371          <button class="persian-calendar-prev-year" type="button" aria-label="سال قبل">‹</button>
372          <span class="persian-calendar-year-label-view" role="button" tabindex="0">${toPersianDigits(this.currentYear)}</span>
373          <button class="persian-calendar-next-year" type="button" aria-label="سال بعد">›</button>
374        `;const today=getIranLocalDate();const[todayJy,todayJm,todayJd]=gregorianToJalali(today.getFullYear(),today.getMonth()+1,today.getDate());const monthsGrid=document.createElement('div');monthsGrid.className='persian-calendar-months-grid';PERSIAN_MONTHS.forEach((m,idx)=>{const monthVal=idx+1;const monthBtn=document.createElement('div');monthBtn.className='persian-calendar-month-item';monthBtn.setAttribute('role','button');monthBtn.setAttribute('tabindex','0');monthBtn.setAttribute('data-month',monthVal);monthBtn.textContent=m;if(this.currentMonth===monthVal){monthBtn.classList.add('active')}
375if(monthVal===todayJm){monthBtn.classList.add('system-current')}
376monthsGrid.appendChild(monthBtn)});body.appendChild(monthsGrid);datePicker.appendChild(nav);datePicker.appendChild(body)}else if(this.viewMode==='years'){const startYear=this.currentYear-(this.currentYear%12);const endYear=startYear+11;nav.innerHTML=`
377          <button class="persian-calendar-prev-years" type="button" aria-label="۱۲ سال قبل">‹</button>
378          <span class="persian-calendar-years-range-label">${toPersianDigits(startYear)} - ${toPersianDigits(endYear)}</span>
379          <button class="persian-calendar-next-years" type="button" aria-label="۱۲ سال بعد">›</button>
380        `;const today=getIranLocalDate();const[todayJy,todayJm,todayJd]=gregorianToJalali(today.getFullYear(),today.getMonth()+1,today.getDate());const yearsGrid=document.createElement('div');yearsGrid.className='persian-calendar-years-grid';for(let y=startYear;y<=endYear;y++){const yearBtn=document.createElement('div');yearBtn.className='persian-calendar-year-item';yearBtn.setAttribute('role','button');yearBtn.setAttribute('tabindex','0');yearBtn.setAttribute('data-year',y);yearBtn.textContent=toPersianDigits(y);if(this.currentYear===y){yearBtn.classList.add('active')}
381if(y===todayJy){yearBtn.classList.add('system-current')}
382yearsGrid.appendChild(yearBtn)}
383body.appendChild(yearsGrid);datePicker.appendChild(nav);datePicker.appendChild(body)}
384wrapper.appendChild(datePicker)}
385notifyDateChange(){const[gy,gm,gd]=jalaliToGregorian(this.selectedDate.year,this.selectedDate.month,this.selectedDate.day);const hour=this.selectedHour||0;const minute=this.selectedMinute||0;const dateObj=new Date(gy,gm-1,gd,hour,minute,0);this.options.onDateSelect({jalali:{...this.selectedDate,hour,minute},gregorian:{year:gy,month:gm,day:gd,hour,minute},date:dateObj})}
386getSelectedDate(){const[gy,gm,gd]=jalaliToGregorian(this.selectedDate.year,this.selectedDate.month,this.selectedDate.day);const hour=this.selectedHour||0;const minute=this.selectedMinute||0;return new Date(gy,gm-1,gd,hour,minute,0)}
387destroy(){if(this._boundClickHandler)this.container.removeEventListener('click',this._boundClickHandler);this.container.textContent='';this.dom=null;this._boundClickHandler=null}}
388window.PersianElementorDateConverter={gregorianToJalali,jalaliToGregorian,isValidGregorian,isValidJalali,toPersianDigits,toAsciiDigits,getDaysInJalaliMonth,PERSIAN_MONTHS,PERSIAN_WEEKDAYS};window.PersianElementorCalendar=PersianCalendar})()
389;

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.