Fix: Hijri Datepicker Complete Solution

Merge PR #4400: Fix Hijri Datepicker Complete Solution

- Fixed __libInput undefined error
- Fixed library paths (2.0.2 instead of 2.2.0)
- Fixed navigation buttons
- Added comprehensive error handling
This commit is contained in:
Mohamed Eltayar 2025-08-29 01:50:53 +03:00 committed by GitHub
commit a6d12f7a93
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 217 additions and 110 deletions

View File

@ -2,31 +2,21 @@
{
'name': 'Web Hijri Datepicker Enhanced',
'version': '2.2.0',
'version': '2.2.1',
'category': 'Web/Tools',
'summary': 'Modern Hijri Calendar Integration with Enhanced UI/UX',
'summary': 'Modern Hijri Calendar Integration with Enhanced UI/UX - Fixed',
'description': """
Enhanced Web Hijri Datepicker v2.2.0
=====================================
Enhanced Web Hijri Datepicker v2.2.1 - All Issues Fixed
=========================================================
🌟 **Major Update with Modern Design and Performance Improvements**
🌟 **Major Fixes & Improvements**
**New Features:**
Updated jQuery Calendars library to v2.2.0
Modern, responsive UI design matching Odoo's aesthetics
Enhanced Arabic/RTL language support
Improved performance and memory optimization
Better error handling and validation
Smooth animations and transitions
Mobile-friendly responsive design
**Key Improvements:**
40% faster loading times
25% reduced memory usage
60% better responsiveness
Enhanced integration with Odoo forms
Improved accessibility features
Better cross-browser compatibility
**Fixed Issues:**
Fixed __libInput undefined error
Fixed library paths (2.0.2 instead of 2.2.0)
Fixed navigation buttons not working
Improved error handling and stability
Enhanced CSS for better button interactions
**Features:**
Automatic conversion between Gregorian and Hijri dates
@ -35,19 +25,21 @@ Enhanced Web Hijri Datepicker v2.2.0
Full Arabic language support with proper RTL
Clear placeholders and intuitive user experience
Seamless integration with all Odoo date fields
Working navigation buttons for months/years
Stable and production-ready
**Technical Specs:**
Compatible with Odoo 14.0+
Supports multiple Islamic calendar variants
Responsive design for all screen sizes
Modern CSS3 with smooth animations
Enhanced JavaScript with error handling
Enhanced JavaScript with comprehensive error handling
Optimized for production environments
This module automatically adds Hijri date picker functionality below every standard date field in Odoo, providing users with an intuitive way to work with Islamic calendar dates.
""",
'author': 'Your Company',
'website': 'https://www.yourcompany.com',
'author': 'Expert Solutions',
'website': 'https://www.exp-sa.com',
'license': 'LGPL-3',
'depends': ['web'],
'data': [
@ -55,20 +47,27 @@ This module automatically adds Hijri date picker functionality below every stand
],
'assets': {
'web.assets_backend': [
# ✅ CSS files
'web_hijri_datepicker/static/src/scss/hijri_modern.css',
'web_hijri_datepicker/static/src/scss/web_hijri_date.scss',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.2.0/jquery.plugin.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.2.0/jquery.calendars.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.2.0/jquery.calendars.all.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.2.0/jquery.calendars.plus.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.2.0/jquery.calendars.picker.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.2.0/jquery.calendars.islamic.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.2.0/jquery.calendars.islamic-ar.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.2.0/jquery.calendars.islamic-fa.js',
# ✅ FIXED: Using correct path 2.0.2 instead of 2.2.0
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.0.2/jquery.plugin.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.0.2/jquery.calendars.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.0.2/jquery.calendars.all.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.0.2/jquery.calendars.plus.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.0.2/jquery.calendars.picker.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.0.2/jquery.calendars.islamic.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.0.2/jquery.calendars.islamic-ar.js',
'web_hijri_datepicker/static/lib/jquery.calendars.package-2.0.2/jquery.calendars.islamic-fa.js',
# Time entry files
'web_hijri_datepicker/static/lib/jquery.timeentry.package-2.0.1/jquery.timeentry.css',
'web_hijri_datepicker/static/lib/jquery.timeentry.package-2.0.1/jquery.plugin.js',
'web_hijri_datepicker/static/lib/jquery.timeentry.package-2.0.1/jquery.timeentry.js',
'web_hijri_datepicker/static/lib/jquery.timeentry.package-2.0.1/jquery.timeentry-ar.js',
# ✅ Our custom JavaScript
'web_hijri_datepicker/static/src/js/web_hijri_date.js',
],
},
@ -90,11 +89,11 @@ This module automatically adds Hijri date picker functionality below every stand
'python': [],
'bin': [],
},
'maintainers': ['Your Name'],
'support': 'support@yourcompany.com',
'maintainers': ['Expert Solutions Team'],
'support': 'support@exp-sa.com',
'price': 0,
'currency': 'USD',
'live_test_url': 'https://demo.yourcompany.com',
'live_test_url': 'https://demo.exp-sa.com',
'demo': [],
'test': [],
}
}

View File

@ -34,68 +34,142 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
datepicker.DateWidget.include({
start: function () {
var self = this;
// ✅ FIX: Initialize __libInput if it doesn't exist
if (typeof this.__libInput === 'undefined') {
this.__libInput = 0;
}
this.$input = this.$('input.o_datepicker_input');
this.$input_hijri = this.$('input.o_hijri');
// ✅ إضافة بسيطة للـ placeholder للحقل الميلادي
// ✅ Add placeholder for Gregorian field
if (this.$input && this.$input.length && !this.$input.attr('placeholder')) {
this.$input.attr('placeholder', 'التاريخ الميلادي');
}
// Enhanced click handler with better UX
this.$input_hijri.click(function (e) {
e.preventDefault();
e.stopPropagation();
self.$input_hijri.calendarsPicker('show');
});
// ✅ Initialize Hijri calendar with safety checks
if (this.$input_hijri && this.$input_hijri.length) {
this._initHijriCalendar();
}
// Modern configuration with enhanced features
this.$input_hijri.calendarsPicker({
calendar: $.calendars.instance('islamic', this.options.locale || 'ar'),
dateFormat: 'M d, yyyy',
showAnim: 'slideDown', // Modern animation
showSpeed: 'fast',
showOnFocus: false,
closeOnDateSelect: true, // Better UX - close after selection
yearRange: 'c-100:c+50', // Extended year range
changeMonth: true,
changeYear: true,
showOtherMonths: true,
selectOtherMonths: true,
localNumbers: true, // Enable Arabic numerals
renderer: this._getModernRenderer(),
onSelect: this._convertDateToHijri.bind(this),
onShow: function() {
// Add modern CSS class for styling
$('.calendars-popup').addClass('hijri-modern-popup');
// ✅ FIX: Safe datetimepicker initialization
if (this.$el && this.$el.datetimepicker) {
this.__libInput++;
try {
this.$el.datetimepicker(this.options);
} catch (e) {
console.warn('Error initializing datetimepicker:', e);
} finally {
this.__libInput--;
}
});
}
this.__libInput++;
this.$el.datetimepicker(this.options);
this.__libInput--;
this._setReadonly(false);
// ✅ تأكد مرة أخيرة من الـ placeholder بعد تحميل datetimepicker
// ✅ Final check for placeholder and Hijri calendar
setTimeout(function() {
if (self.$input && self.$input.length && !self.$input.attr('placeholder')) {
self.$input.attr('placeholder', 'التاريخ الميلادي');
}
}, 50);
// Try to initialize Hijri calendar again if not done
if (typeof $ !== 'undefined' && $.calendars && self.$input_hijri &&
self.$input_hijri.length && !self.$input_hijri.hasClass('hasCalendarsPicker')) {
self._initHijriCalendar();
}
}, 200);
},
// ✅ Separate method for Hijri calendar initialization
_initHijriCalendar: function() {
var self = this;
// Check if jQuery Calendars library is available
if (typeof $ === 'undefined' || !$.calendars || !$.calendars.instance) {
console.warn('jQuery Calendars library not loaded yet. Will retry...');
return;
}
try {
// Enhanced click handler with better event handling
this.$input_hijri.off('click.hijri').on('click.hijri', function (e) {
e.preventDefault();
e.stopPropagation();
if (self.$input_hijri.hasClass('hasCalendarsPicker')) {
self.$input_hijri.calendarsPicker('show');
}
});
// ✅ Initialize calendar with fixed configuration
this.$input_hijri.calendarsPicker({
calendar: $.calendars.instance('islamic', this.options.locale || 'ar'),
dateFormat: 'M d, yyyy',
showAnim: 'slideDown',
showSpeed: 'fast',
showOnFocus: false,
closeOnDateSelect: true,
yearRange: 'c-100:c+50',
changeMonth: true,
changeYear: true,
showOtherMonths: true,
selectOtherMonths: true,
localNumbers: true,
renderer: this._getModernRenderer(),
onSelect: this._convertDateToHijri.bind(this),
onShow: function() {
// Add modern CSS class
$('.calendars-popup').addClass('hijri-modern-popup');
// ✅ FIX: Navigation buttons with proper symbols
setTimeout(function() {
// Fix previous button
$('.calendars-prev').each(function() {
$(this).html('').attr('title', 'الشهر السابق');
$(this).css({
'cursor': 'pointer',
'user-select': 'none',
'pointer-events': 'auto'
});
});
// Fix next button
$('.calendars-next').each(function() {
$(this).html('').attr('title', 'الشهر التالي');
$(this).css({
'cursor': 'pointer',
'user-select': 'none',
'pointer-events': 'auto'
});
});
}, 50);
}
});
console.log('Hijri calendar initialized successfully');
} catch (error) {
console.error('Error initializing Hijri calendar:', error);
}
},
/**
* Get modern renderer configuration for better styling
* Get modern renderer configuration with fixed navigation buttons
*/
_getModernRenderer: function() {
// Check if library is available
if (!$ || !$.calendarsPicker || !$.calendarsPicker.defaultRenderer) {
return {};
}
return $.extend({}, $.calendarsPicker.defaultRenderer, {
picker: '<div class="calendars">{months}</div>',
monthRow: '<div class="calendars-month-row">{months}</div>',
month: '<div class="calendars-month">' +
'<div class="calendars-month-header">' +
'<button type="button" class="calendars-nav calendars-prev" title="{prevText}">{prevText}</button>' +
'<button type="button" class="calendars-nav calendars-prev" title="الشهر السابق"></button>' +
'<div class="calendars-month-year">{monthHeader}</div>' +
'<button type="button" class="calendars-nav calendars-next" title="{nextText}">{nextText}</button>' +
'<button type="button" class="calendars-nav calendars-next" title="الشهر التالي"></button>' +
'</div>' +
'<table><thead>{weekHeader}</thead><tbody>{weeks}</tbody></table>' +
'</div>',
@ -121,41 +195,53 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
},
_convertGregorianToHijri: function (date) {
// Check if library is available
if (!$ || !$.calendars || !$.calendars.instance) {
return null;
}
var year, month, day, jd, formatted_date;
var calendar = $.calendars.instance('islamic');
var calendar;
if (date && !_.isUndefined(date)) {
date = moment(date).locale('en');
month = parseInt(date.format('M'));
day = parseInt(date.format('D'));
year = parseInt(date.format('YYYY'));
jd = $.calendars.instance('gregorian').toJD(year, month, day);
formatted_date = calendar.fromJD(jd);
var hijriMonth = calendar.formatDate('MM', formatted_date);
var hijriDate = calendar.formatDate('d, yyyy', formatted_date);
// Enhanced Arabic localization
if (this.options.locale === 'ar' || !this.options.locale) {
hijriDate = hijriDate.fromDigits();
// Find Arabic month name
var arabicMonth = _.find(hijriMonths, function (value, key) {
return key === hijriMonth;
});
hijriMonth = arabicMonth || hijriMonth;
try {
calendar = $.calendars.instance('islamic');
date = moment(date).locale('en');
month = parseInt(date.format('M'));
day = parseInt(date.format('D'));
year = parseInt(date.format('YYYY'));
jd = $.calendars.instance('gregorian').toJD(year, month, day);
formatted_date = calendar.fromJD(jd);
var hijriMonth = calendar.formatDate('MM', formatted_date);
var hijriDate = calendar.formatDate('d, yyyy', formatted_date);
// Enhanced Arabic localization
if (this.options.locale === 'ar' || !this.options.locale) {
hijriDate = hijriDate.fromDigits();
// Find Arabic month name
var arabicMonth = _.find(hijriMonths, function (value, key) {
return key === hijriMonth;
});
hijriMonth = arabicMonth || hijriMonth;
}
return _.str.sprintf("%s %s", hijriMonth, hijriDate);
} catch (error) {
console.error('Error converting Gregorian to Hijri:', error);
return null;
}
return _.str.sprintf("%s %s", hijriMonth, hijriDate);
}
return null;
},
_convertDateToHijri: function (date) {
if (!date || date.length === 0) {
if (!date || date.length === 0 || !$ || !$.calendars) {
return false;
}
// Prevent event bubbling for better UX
// Prevent event bubbling
$(document).off('click.calendars').on('click.calendars', '.calendars a', function (e) {
e.preventDefault();
e.stopImmediatePropagation();
@ -176,11 +262,13 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
this.setValue(this._parseClient(dateValue));
this.trigger("datetime_changed");
// Hide the popup after selection for better UX
this.$input_hijri.calendarsPicker('hide');
// Hide the popup after selection
if (this.$input_hijri && this.$input_hijri.hasClass('hasCalendarsPicker')) {
this.$input_hijri.calendarsPicker('hide');
}
} catch (error) {
console.warn('Hijri date conversion error:', error);
console.error('Hijri date conversion error:', error);
}
},
@ -194,10 +282,12 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
var hijri_value = parsed_date ? this._convertGregorianToHijri(parsed_date) : null;
// Enhanced placeholder handling
if (hijri_value) {
this.$input_hijri.val(hijri_value).removeClass('o_input_placeholder');
} else {
this.$input_hijri.val('').addClass('o_input_placeholder');
if (this.$input_hijri && this.$input_hijri.length) {
if (hijri_value) {
this.$input_hijri.val(hijri_value).removeClass('o_input_placeholder');
} else {
this.$input_hijri.val('').addClass('o_input_placeholder');
}
}
},
@ -205,14 +295,32 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
// Clean up event handlers
$(document).off('click.calendars');
if (this.$input_hijri && this.$input_hijri.hasClass('hasCalendarsPicker')) {
this.$input_hijri.calendarsPicker('destroy');
if (this.$input_hijri) {
this.$input_hijri.off('click.hijri');
if (this.$input_hijri.hasClass('hasCalendarsPicker')) {
try {
this.$input_hijri.calendarsPicker('destroy');
} catch (error) {
console.warn('Error destroying calendars picker:', error);
}
}
}
if (this.$el) {
if (this.$el && this.$el.datetimepicker) {
// ✅ FIX: Initialize __libInput if not exists
if (typeof this.__libInput === 'undefined') {
this.__libInput = 0;
}
this.__libInput++;
this.$el.datetimepicker('destroy');
this.__libInput--;
try {
this.$el.datetimepicker('destroy');
} catch (e) {
console.warn('Error destroying datetimepicker:', e);
} finally {
this.__libInput--;
}
}
},
@ -267,9 +375,9 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
});
// Enhanced integration with Odoo's form validation
if ($.validator) {
if ($ && $.validator) {
$.validator.addMethod('hijriDate', function(value, element) {
if (!value) return true;
if (!value || !$ || !$.calendars) return true;
try {
var calendar = $.calendars.instance('islamic');
@ -282,7 +390,7 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
}
// Global configuration for better performance
if ($.calendarsPicker) {
if ($ && $.calendarsPicker) {
$.calendarsPicker.setDefaults({
showSpeed: 'fast',
showAnim: 'slideDown',