ngx-hijri-datepicker
Version:
A Hijri datepicker component for Angular applications
533 lines (479 loc) • 21 kB
text/typescript
import {
Component,
HostListener,
ElementRef,
Input,
Output,
EventEmitter,
forwardRef,
OnInit,
} from '@angular/core';
import { NG_VALUE_ACCESSOR, ControlValueAccessor } from '@angular/forms';
import moment from 'moment-hijri';
export class NgxHijriDatepickerComponent {
// Input properties to allow customization by the user
// المدخلات لتخصيص المكون من قبل المستخدم
value: string | null = null; // The initial value / القيمة الأولية
valueChange: EventEmitter<string> = new EventEmitter<string>(); // Emits value when it changes / إرسال القيمة عند التغيير
placeholder: string = 'اختر تاريخ هجري'; // Placeholder text / النص الافتراضي للحقل
width: string = '250px'; // Width of the input field / عرض الحقل
height: string = '40px'; // Height of the input field / ارتفاع الحقل
InputColor: string | null = null; // Input text color / لون النص في الحقل
InputBackgroundColor: string | null= null; // Input background color / لون خلفية الحقل
IconColor: string | null= null; // Icon color / لون الأيقونة
IconBackgroundColor: string| null = null; // Icon background color / لون خلفية الأيقونة
DayColor: string| null= null; // Day color in calendar / لون الأيام في التقويم
BorderColor: string | null= null; // Border color for input and popup / لون الحدود
DatepickerPopupHeaderColor: string | null= null; // Header color in the popup / لون الرأس في نافذة التقويم
displayFormat: string = 'iYYYY/iM/iD'; // تنسيق التاريخ الافتراضي
storageFormat: string | null = null; // التنسيق المستخدم للتخزين (افتراضيًا يكون null)
locale: 'en' | 'ar-SA' = 'ar-SA'; // خيار لاختيار اللغة (افتراضي: عربي)
storageLocale: 'en' | 'ar-SA' = 'en'; // لغة التخزين
selectedDate: moment.Moment | null = null; // Currently selected date / التاريخ المختار
showDatePicker = false; // To control visibility of the datepicker popup / التحكم في إظهار التقويم
showYearPopup: boolean = false; // إضافة الخاصية هنا
currentViewDate: moment.Moment = moment().locale(this.locale);; // Currently displayed month in the popup / الشهر الحالي المعروض
todayBtn:string = 'اليوم'
onChange = (value: string) => {}; // Placeholder for Reactive Forms' change event / واجهة للتعامل مع التغييرات في Reactive Forms
onTouched = () => {}; // Placeholder for Reactive Forms' touch event / واجهة للتعامل مع لمسة الحقل في Reactive Forms
// أسماء الأيام (اختصار)
// Short names for days of the week
// Getter لتحديد أسماء الأيام بناءً على اللغة
get dayNamesMin(): string[] {
return this.locale === 'ar-SA'
? ['ح', 'ن', 'ث', 'ر', 'خ', 'ج', 'س'] // عربي
: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa']; // إنجليزي
}
constructor(private elementRef: ElementRef) {}
// **Initial setup on component load**
// **إعداد مبدئي عند تحميل المكون**
ngOnInit() {
moment.locale(this.locale); // ضبط locale بناءً على اللغة المختارة
if (this.value) {
this.selectedDate = moment(this.value, this.displayFormat).locale(this.locale);; // Parse the initial value / تحويل القيمة الأولية لتاريخ
this.currentViewDate = this.selectedDate.clone(); // Set the view date to the selected date / عرض الشهر الخاص بالتاريخ المختار
}
if(this.locale == 'en')
this.todayBtn = 'Today'
}
// إذا لم يتم تمرير `storageFormat` من المستخدم، نستخدم `displayFormat` كقيمة افتراضية
get resolvedStorageFormat(): string {
return this.storageFormat || this.displayFormat;
}
// **Property: Display the current month's name in Hijri format**
// **خاصية: عرض اسم الشهر الحالي بالتنسيق الهجري**
get currentMonthName(): string {
return this.currentViewDate.locale(this.locale).format('iMMMM iYYYY'); // Format the current month / صيغة اسم الشهر الحالي
}
// **Property: Calculate and return days of the current month**
// **خاصية: حساب وإرجاع أيام الشهر الحالي**
get daysInCurrentMonth(): any[] {
const startOfMonth = this.currentViewDate.clone().startOf('iMonth'); // Start of the month / بداية الشهر
const endOfMonth = this.currentViewDate.clone().endOf('iMonth'); // End of the month / نهاية الشهر
const days = [];
const startDayOfWeek = startOfMonth.day(); // The first day of the month in the week / اليوم الأول من الشهر
// Add empty slots for previous month's days
// إضافة فراغات للأيام التي تسبق الشهر الحالي
for (let i = 0; i < startDayOfWeek; i++) {
days.push(null);
}
// Add actual days of the current month
// إضافة الأيام الفعلية للشهر الحالي
const totalDays = endOfMonth.iDate();
for (let d = 1; d <= totalDays; d++) {
days.push(startOfMonth.clone().iDate(d).locale(this.locale));
}
return days;
}
// **Method: Navigate to the previous month**
// **طريقة: الانتقال إلى الشهر السابق**
prevMonth() {
this.currentViewDate = this.currentViewDate.clone().subtract(1, 'iMonth').locale(this.locale);;
}
// **Method: Navigate to the next month**
// **طريقة: الانتقال إلى الشهر التالي**
nextMonth() {
this.currentViewDate = this.currentViewDate.clone().add(1, 'iMonth').locale(this.locale);;
}
// **Method: Select a specific date**
// **طريقة: اختيار تاريخ معين**
selectDate(day: moment.Moment | null) {
if (day) {
this.selectedDate = day.locale(this.locale);
const storedValue = this.selectedDate.locale(this.storageLocale).format(this.resolvedStorageFormat); // القيمة لتخزينها في قاعدة البيانات
const displayValue = this.selectedDate.locale(this.locale).format(this.displayFormat); // القيمة لعرضها
this.onChange(storedValue); // إرسال القيمة المخزنة إلى النموذج
this.valueChange.emit(storedValue); // إرسال القيمة المخزنة
this.showDatePicker = false; // إغلاق نافذة التقويم
}
}
// **Method: Toggle visibility of the datepicker**
// **طريقة: فتح/إغلاق التقويم**
toggleDatePicker() {
this.currentViewDate = this.selectedDate
? this.selectedDate.clone().locale(this.locale)
: moment().locale(this.locale); // Set to current date if no date is selected / عرض الشهر الحالي إذا لم يتم اختيار تاريخ
this.showDatePicker = !this.showDatePicker; // Toggle visibility / تبديل الحالة
}
// **Method: Close the popup when clicking outside**
// **طريقة: إغلاق التقويم عند النقر خارج المكون**
onDocumentClick(targetElement: HTMLElement) {
const clickedInside = this.elementRef.nativeElement.contains(targetElement); // Check if click is inside / التحقق إذا كان النقر داخل المكون
if (!clickedInside) {
this.showDatePicker = false; // Close the popup / إغلاق نافذة التقويم
}
}
// **Property: Display the selected date in the input field**
// **خاصية: عرض التاريخ المختار في الحقل**
get displayedDate(): string {
return this.selectedDate ? this.selectedDate.locale(this.locale).format(this.displayFormat) : ''; // Display formatted date or empty string / عرض التاريخ أو تركه فارغاً
}
// **Method: Select today's date**
// **طريقة: اختيار تاريخ اليوم**
selectToday() {
this.selectedDate = moment().locale(this.locale); // Set the date to today / تعيين التاريخ إلى اليوم
const storedValue = this.selectedDate.locale(this.storageLocale).format(this.resolvedStorageFormat);
const displayValue = this.selectedDate.locale(this.storageLocale).format(this.displayFormat);
this.onChange(storedValue); // Emit the value for Reactive Forms / إرسال القيمة إلى Reactive Forms
this.valueChange.emit(storedValue); // Emit the value for standalone usage / إرسال القيمة عند الاستخدام الفردي
this.showDatePicker = false; // Close the popup / إغلاق نافذة التقويم
}
// **ControlValueAccessor: Write a new value**
// **واجهة: تعيين قيمة جديدة**
writeValue(value: string): void {
if (value) {
this.selectedDate = moment(value, this.resolvedStorageFormat).locale(this.locale); // تحويل القيمة إلى لحظة بناءً على التنسيق
this.currentViewDate = this.selectedDate.clone(); // Set the current view date / تعيين عرض الشهر
} else {
this.selectedDate = null; // Clear the selected date / مسح التاريخ المختار
}
}
// **ControlValueAccessor: Register a change callback**
// **واجهة: تسجيل دالة تغيير القيمة**
registerOnChange(fn: any): void {
this.onChange = fn; // Store the callback function / تخزين دالة التغيير
}
// **ControlValueAccessor: Register a touched callback**
// **واجهة: تسجيل دالة اللمس**
registerOnTouched(fn: any): void {
this.onTouched = fn; // Store the callback function / تخزين دالة اللمس
}
toggleYearPopup() {
this.showYearPopup = !this.showYearPopup;
}
selectYear(year: number) {
this.currentViewDate = moment(this.currentViewDate).iYear(year); // تحديث باستخدام moment مباشرة
this.selectedDate = this.currentViewDate.clone(); // تحديث التاريخ المختار أيضًا
this.showYearPopup = false;
this.onChange(this.selectedDate.format('iYYYY/iM/iD')); // إرسال التغيير إلى الـ formControl
}
get hijriYears(): number[] {
const currentYear = moment().iYear();
const startYear = currentYear - 50;
const endYear = currentYear + 50;
const years = [];
for (let i = startYear; i <= endYear; i++) {
years.push(i);
}
return years;
}
}