Merge PR #4411: تحديث موديول Web Hijri Datepicker v2.0

دمج تحديث موديول Web Hijri Datepicker v2.0

التحديثات الرئيسية:
- جعل التاريخ الهجري اختياري بدلاً من تلقائي
- إضافة widgets مخصصة: hijri_date و hijri_datetime
- عدم التأثير على الحقول الموجودة
- توثيق كامل وأمثلة استخدام
This commit is contained in:
Mohamed Eltayar 2025-08-29 03:01:48 +03:00 committed by GitHub
commit ab99a15852
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 244 additions and 62 deletions

View File

@ -0,0 +1,80 @@
# Web Hijri Datepicker Module
## الوصف / Description
موديول يضيف إمكانية عرض التاريخ الهجري بجانب التاريخ الميلادي في حقول التاريخ في نظام Odoo.
This module adds the ability to display Hijri calendar dates alongside Gregorian dates in Odoo date fields.
## المميزات / Features
- عرض التاريخ الهجري والميلادي معاً في نفس الحقل
- التحكم الكامل في أي حقل يظهر معه التاريخ الهجري
- دعم اللغة العربية والإنجليزية
- يعمل في جميع أنواع العروض (Form, List, etc.)
- لا يؤثر على الحقول الموجودة إلا عند تحديد ذلك صراحةً
## الاستخدام / Usage
### في ملفات XML:
```xml
<!-- حقل تاريخ عادي (بدون تاريخ هجري) -->
<field name="date_field"/>
<!-- حقل تاريخ مع التاريخ الهجري -->
<field name="date_field" widget="hijri_date"/>
<!-- حقل تاريخ ووقت مع التاريخ الهجري -->
<field name="datetime_field" widget="hijri_datetime"/>
```
### مثال كامل / Complete Example:
```xml
<record id="view_form_example" model="ir.ui.view">
<field name="name">example.form</field>
<field name="model">your.model</field>
<field name="arch" type="xml">
<form>
<group>
<!-- حقل عادي -->
<field name="normal_date"/>
<!-- حقل مع تاريخ هجري -->
<field name="hijri_date" widget="hijri_date"/>
<!-- حقل تاريخ ووقت مع تاريخ هجري -->
<field name="hijri_datetime" widget="hijri_datetime"/>
</group>
</form>
</field>
</record>
```
## التحديث من الإصدار السابق / Upgrading from Previous Version
إذا كنت تستخدم الإصدار السابق الذي يضيف التاريخ الهجري لجميع الحقول تلقائياً:
1. قم بتحديث الموديول
2. أضف `widget="hijri_date"` للحقول التي تريد إظهار التاريخ الهجري معها
3. الحقول التي لا تحتوي على هذا الـ widget ستعود للعرض العادي
## المتطلبات / Requirements
- Odoo 14.0+
- موديول web
## التثبيت / Installation
1. ضع الموديول في مجلد addons
2. قم بتحديث قائمة الموديولات
3. قم بتثبيت موديول "Web Hijri"
## الترخيص / License
LGPL-3
## المطور / Developer
Odex25 Team

View File

@ -3,13 +3,29 @@
{
'name': 'Web Hijri',
'category' : 'Odex25-base',
'version': '1.0',
'description': """Enable Web Hijri Datepicker in Odoo""",
'version': '2.0',
'description': """
Enable Web Hijri Datepicker in Odoo
====================================
This module allows you to use Hijri calendar alongside Gregorian calendar for date fields.
Features:
---------
* Custom widget for date fields to show both Gregorian and Hijri dates
* Use widget="hijri_date" for date fields
* Use widget="hijri_datetime" for datetime fields
* Normal date fields remain unchanged
Usage:
------
In your XML views, use:
<field name="date_field" widget="hijri_date"/>
<field name="datetime_field" widget="hijri_datetime"/>
""",
'depends': ['web'],
'data': ['views/web_hijri_template.xml'],
'qweb': ["static/src/xml/web_hijri_date.xml"],
'installable': True,
'auto_install': False,
'bootstrap': True,
'application': True,
'application': False,
}

View File

@ -26,6 +26,7 @@ odoo.define('web_hijri_datepicker.ListRenderer', function (require) {
monetary: 'o_list_number',
text: 'o_list_text',
};
String.prototype.fromDigits = function () {
var id = ['۰', '۱', '۲', '۳', '٤', '۵', '٦', '۷', '۸', '۹'];
return this.replace(/[0-9]/g, function (w) {
@ -68,6 +69,7 @@ odoo.define('web_hijri_datepicker.ListRenderer', function (require) {
return _.str.sprintf("%s %s", month, date);
}
},
_renderBodyCell: function (record, node, colIndex, options) {
var tdClassName = 'o_data_cell';
if (node.tag === 'button') {
@ -112,34 +114,39 @@ odoo.define('web_hijri_datepicker.ListRenderer', function (require) {
this._handleAttributes($td, node);
var name = node.attrs.name;
var field = this.state.fields[name];
if (field!== undefined){
var value = record.data[name];
var formatter = field_utils.format[field.type];
var formatOptions = {
escape: true,
data: record.data,
isPassword: 'password' in node.attrs,
};
var formattedValue = formatter(value, field, formatOptions);
if (_.contains(['date', 'datetime'], field.type)) {
if (formattedValue) {
var formattedHijriValue = this._parseDate(value)
formattedValue = this._formateDate(formattedValue, formattedHijriValue);
if (field !== undefined) {
var value = record.data[name];
var formatter = field_utils.format[field.type];
var formatOptions = {
escape: true,
data: record.data,
isPassword: 'password' in node.attrs,
};
var formattedValue = formatter(value, field, formatOptions);
// فقط إضافة التاريخ الهجري إذا كان الـ widget هو hijri_date أو hijri_datetime
if (_.contains(['date', 'datetime'], field.type) &&
(node.attrs.widget === 'hijri_date' || node.attrs.widget === 'hijri_datetime')) {
if (formattedValue) {
var formattedHijriValue = this._parseDate(value);
formattedValue = this._formateDate(formattedValue, formattedHijriValue);
}
}
}
var title = '';
if (field.type !== 'boolean') {
title = formatter(value, field, _.extend(formatOptions, {escape: false}));
}
}
else{
var title = '';
if (field.type !== 'boolean') {
title = formatter(value, field, _.extend(formatOptions, {escape: false}));
}
} else {
return $td.append(this._renderButton(record, node));
}
return $td.html(formattedValue).attr('title', title);
},
_parseDate: function (v) {
return v.clone().locale('en').format('YYYY-MM-DD');
},
_formateDate: function (formattedValue, formattedHijriValue) {
var self = this;
if (formattedHijriValue) {
@ -148,6 +155,7 @@ odoo.define('web_hijri_datepicker.ListRenderer', function (require) {
});
}
},
_onWindowClicked: function (event) {
if ($(event.target).hasClass('calendars-highlight')) {
return;

View File

@ -5,6 +5,8 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
var field_utils = require('web.field_utils');
var time = require('web.time');
var FieldDate = require('web.basic_fields').FieldDate;
var FieldDateTime = require('web.basic_fields').FieldDateTime;
var registry = require('web.field_registry');
var _t = core._t;
var hijriMonths = {
@ -29,7 +31,10 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
});
}
datepicker.DateWidget.include({
// إنشاء HijriDateWidget مخصص للتواريخ الهجرية
var HijriDateWidget = datepicker.DateWidget.extend({
template: 'web_hijri.datepicker',
start: function () {
var self = this;
this.$input = this.$('input.o_datepicker_input');
@ -73,7 +78,6 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
this.__libInput--;
// تطبيق placeholder للتاريخ الميلادي بعد تهيئة datetimepicker
// نستخدم setTimeout لضمان تطبيقه بعد أي تغييرات من datetimepicker
setTimeout(function() {
self.$input.attr('placeholder', gregorianPlaceholder);
}, 0);
@ -119,6 +123,7 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
return _.str.sprintf("%s %s", month, date);
}
},
_convertDateToHijri: function (date) {
if (!date || date.length === 0) {
return false;
@ -133,11 +138,12 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
var date_value = moment(time.str_to_date(formatted_date)).add(1, 'days');
this.setValue(this._parseClient(date_value));
this.trigger("datetime_changed");
},
_parseDate: function (v) {
return v.clone().locale('en').format('YYYY-MM-DD');
},
setValue: function (value) {
this._super.apply(this, arguments);
var parsed_date = value ? this._parseDate(value) : null;
@ -152,6 +158,7 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
this.$input_hijri.attr('placeholder', this.hijriPlaceholder);
}
},
destroy: function () {
if (this.$el) {
this.__libInput++;
@ -159,45 +166,101 @@ odoo.define('web_hijri_datepicker.datepicker', function (require) {
this.__libInput--;
}
},
_onInputClicked: function (e) {
if (e && e.target && ! $(e.target).hasClass('o_hijri')){
return this._super();
}
},
_formatClients: function (v) {
return field_utils.format[this.type_of_date](v, null, {timezone: true});
},
});
FieldDate.include({
// إنشاء FieldHijriDate للتواريخ مع التقويم الهجري
var FieldHijriDate = FieldDate.extend({
_makeDatePicker: function () {
return new HijriDateWidget(this, this.datepickerOptions);
},
_renderReadonly: function () {
var self = this;
this._super.apply(this, arguments);
if (this.value) {
window.dv = this.value;
this.datewidget = this._makeDatePicker();
var $div = $('<div/>');
var value = this.value ? this.datewidget._formatClients(this.value) : '';
var parsed_date = this.value ? this.datewidget._parseDate(this.value) : '';
var hijri_value = parsed_date ? this.datewidget._convertGregorianToHijri(parsed_date) : '';
// إضافة labels توضيحية في وضع القراءة فقط
var userLang = (odoo.session_info && odoo.session_info.user_context && odoo.session_info.user_context.lang) || 'en_US';
var gregorianLabel = userLang.startsWith('ar') ? 'التاريخ الميلادي: ' : 'Gregorian Date: ';
var hijriLabel = userLang.startsWith('ar') ? 'التاريخ الهجري: ' : 'Hijri Date: ';
$('<div>', {
class: this.$el.attr('class'),
text: gregorianLabel + value,
}).appendTo($div);
$('<div>', {
class: this.$el.attr('class'),
text: hijriLabel + hijri_value,
}).appendTo($div);
this.datewidget.appendTo('<div>').then(function () {
self._replaceElement($div);
});
if (!this.value) {
this._super.apply(this, arguments);
return;
}
this.datewidget = this._makeDatePicker();
var $div = $('<div/>');
var value = this.value ? this.datewidget._formatClients(this.value) : '';
var parsed_date = this.value ? this.datewidget._parseDate(this.value) : '';
var hijri_value = parsed_date ? this.datewidget._convertGregorianToHijri(parsed_date) : '';
// إضافة labels توضيحية في وضع القراءة فقط
var userLang = (odoo.session_info && odoo.session_info.user_context && odoo.session_info.user_context.lang) || 'en_US';
var gregorianLabel = userLang.startsWith('ar') ? 'التاريخ الميلادي: ' : 'Gregorian Date: ';
var hijriLabel = userLang.startsWith('ar') ? 'التاريخ الهجري: ' : 'Hijri Date: ';
$('<div>', {
class: this.$el.attr('class'),
text: gregorianLabel + value,
}).appendTo($div);
$('<div>', {
class: this.$el.attr('class'),
text: hijriLabel + hijri_value,
}).appendTo($div);
this.datewidget.appendTo('<div>').then(function () {
self._replaceElement($div);
});
},
})
});
// إنشاء FieldHijriDateTime للتواريخ والأوقات مع التقويم الهجري
var FieldHijriDateTime = FieldDateTime.extend({
_makeDatePicker: function () {
return new HijriDateWidget(this, this.datepickerOptions);
},
_renderReadonly: function () {
var self = this;
if (!this.value) {
this._super.apply(this, arguments);
return;
}
this.datewidget = this._makeDatePicker();
var $div = $('<div/>');
var value = this.value ? this.datewidget._formatClients(this.value) : '';
var parsed_date = this.value ? this.datewidget._parseDate(this.value) : '';
var hijri_value = parsed_date ? this.datewidget._convertGregorianToHijri(parsed_date) : '';
// إضافة labels توضيحية في وضع القراءة فقط
var userLang = (odoo.session_info && odoo.session_info.user_context && odoo.session_info.user_context.lang) || 'en_US';
var gregorianLabel = userLang.startsWith('ar') ? 'التاريخ الميلادي: ' : 'Gregorian Date: ';
var hijriLabel = userLang.startsWith('ar') ? 'التاريخ الهجري: ' : 'Hijri Date: ';
$('<div>', {
class: this.$el.attr('class'),
text: gregorianLabel + value,
}).appendTo($div);
$('<div>', {
class: this.$el.attr('class'),
text: hijriLabel + hijri_value,
}).appendTo($div);
this.datewidget.appendTo('<div>').then(function () {
self._replaceElement($div);
});
},
});
// تسجيل الحقول الجديدة في registry
registry.add('hijri_date', FieldHijriDate);
registry.add('hijri_datetime', FieldHijriDateTime);
return {
HijriDateWidget: HijriDateWidget,
FieldHijriDate: FieldHijriDate,
FieldHijriDateTime: FieldHijriDateTime,
};
});

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<templates id="template" xml:space="preserve">
<!-- Template الأصلي للتوافق الخلفي (لن يُستخدم افتراضياً) -->
<t t-name="web.datepicker" t-extend="web.datepicker">
<t t-jquery=".o_datepicker" t-operation="replace">
<div class="o_datepicker" aria-atomic="true" t-att-id="datepickerID" data-target-input="nearest">
@ -7,16 +8,29 @@
class="o_datepicker_input o_input datetimepicker-input"
t-att-name="widget.name"
t-att-placeholder="placeholder"
t-attf-data-target="##{datepickerID}"
t-attf-data-target="#{datepickerID}"
autocomplete="off"/>
<span class="o_datepicker_button"/>
<span class="o_datepicker_button"/>
<input type="text"
class="o_hijri o_input mt4"
t-att-name="widget.name"
t-att-placeholder="placeholder"/>
<span class="o_datepicker_button o_hijri_datepicker_button"/>
</div>
</t>
</t>
</templates>
<!-- Template الجديد للتواريخ الهجرية -->
<t t-name="web_hijri.datepicker">
<div class="o_datepicker o_hijri_datepicker" aria-atomic="true" t-att-id="datepickerID" data-target-input="nearest">
<input type="text"
class="o_datepicker_input o_input datetimepicker-input"
t-att-name="widget.name"
t-att-placeholder="placeholder"
t-attf-data-target="#{datepickerID}"
autocomplete="off"/>
<span class="o_datepicker_button"/>
<span class="o_datepicker_button"/>
<input type="text"
class="o_hijri o_input mt4"
t-att-name="widget.name"
t-att-placeholder="placeholder"/>
<span class="o_datepicker_button o_hijri_datepicker_button"/>
</div>
</t>
</templates>

View File

@ -15,6 +15,7 @@
<script type="text/javascript" src="/web_hijri_datepicker/static/lib/jquery.calendars.package-2.0.2/jquery.calendars.islamic-ar.js"/>
<script type="text/javascript" src="/web_hijri_datepicker/static/lib/jquery.calendars.package-2.0.2/jquery.calendars.islamic-fa.js"/>
<script type="text/javascript" src="/web_hijri_datepicker/static/src/js/web_hijri_date.js"/>
<script type="text/javascript" src="/web_hijri_datepicker/static/src/js/list_renderer.js"/>
<script type="text/javascript" src="/web_hijri_datepicker/static/lib/jquery.timeentry.package-2.0.1/jquery.plugin.js"/>
<script type="text/javascript" src="/web_hijri_datepicker/static/lib/jquery.timeentry.package-2.0.1/jquery.timeentry.js"/>
<script type="text/javascript" src="/web_hijri_datepicker/static/lib/jquery.timeentry.package-2.0.1/jquery.timeentry-ar.js"/>