Merge pull request #4439 from expsa/eltayar

تحسينات نهائية للموديول - دعم كامل للعربية وإصلاحات أداء
This commit is contained in:
Mohamed Eltayar 2025-08-30 15:09:14 +03:00 committed by GitHub
commit 1c52a0b38a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 116 additions and 14 deletions

View File

@ -27,7 +27,8 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
filteredCount: 0,
originalDomain: null,
searchInProgress: false,
lastSearchPromise: null
lastSearchPromise: null,
lastSearchValue: '' // Track last search value
};
this._searchMutex = new concurrency.Mutex();
},
@ -59,6 +60,15 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
_handleCustomSearch: function(value) {
var self = this;
// Check if value actually changed
if (value === self._customSearchState.lastSearchValue) {
console.log('Search value unchanged, skipping');
return Promise.resolve();
}
// Update last search value
self._customSearchState.lastSearchValue = value;
// Cancel any pending search
if (self._customSearchState.timer) {
clearTimeout(self._customSearchState.timer);
@ -208,6 +218,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
this._customSearchState.value = '';
this._customSearchState.isFiltered = false;
this._customSearchState.filteredCount = 0;
this._customSearchState.lastSearchValue = '';
// Get original domain
var originalDomain = this._customSearchState.originalDomain || [];
@ -430,7 +441,11 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
*/
_updateCustomSearchUI: function(count) {
if (this.renderer && this.renderer.$) {
var message = _t('Found: ') + count + _t(' records');
var isArabic = this._isArabicLanguage();
var message = isArabic ?
'عدد السجلات: ' + count :
_t('Found: ') + count + _t(' records');
this.renderer.$('.oe_search_count')
.text(message)
.show();
@ -443,13 +458,24 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
*/
_showSearchError: function() {
if (this.renderer && this.renderer.$) {
var isArabic = this._isArabicLanguage();
var errorMsg = isArabic ? 'حدث خطأ في البحث' : _t('Search error occurred');
this.renderer.$('.oe_search_count')
.text(_t('Search error occurred'))
.text(errorMsg)
.addClass('text-danger')
.show();
}
},
/**
* Check if system language is Arabic
*/
_isArabicLanguage: function() {
var lang = session.user_context.lang || '';
return lang.startsWith('ar');
},
/**
* Normalize Arabic text - ENHANCED VERSION
*/
@ -498,6 +524,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
this._super.apply(this, arguments);
this._searchTimer = null;
this._customSearchReady = false;
this._lastInputValue = ''; // Track last input value
},
/**
@ -528,13 +555,24 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
// Restore search input value
if (state.value) {
this.$('.oe_search_input').val(state.value);
var $input = this.$('.oe_search_input');
$input.val(state.value);
// Set cursor position to end of text
var length = state.value.length;
if ($input[0] && $input[0].setSelectionRange) {
$input[0].setSelectionRange(length, length);
}
this.$('.oe_clear_search').show();
this._lastInputValue = state.value;
}
// Restore count display
if (state.isFiltered && state.filteredCount >= 0) {
var message = _t('Found: ') + state.filteredCount + _t(' records');
var isArabic = this._isArabicLanguage();
var message = isArabic ?
'عدد السجلات: ' + state.filteredCount :
_t('Found: ') + state.filteredCount + _t(' records');
this.$('.oe_search_count')
.text(message)
.removeClass('text-danger')
@ -543,6 +581,14 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
}
},
/**
* Check if system language is Arabic
*/
_isArabicLanguage: function() {
var lang = session.user_context.lang || '';
return lang.startsWith('ar');
},
/**
* Check if we should add search box
*/
@ -570,18 +616,32 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
isFiltered = controller._customSearchState.isFiltered || false;
}
var isArabic = this._isArabicLanguage();
var dir = isArabic ? 'rtl' : 'ltr';
// Translations
var placeholder = isArabic ? 'البحث في جميع الأعمدة المرئية...' : _t('Search in all visible columns...');
var clearText = isArabic ? 'مسح' : _t('Clear');
var countText = '';
if (isFiltered) {
countText = isArabic ?
'عدد السجلات: ' + savedCount :
_t('Found: ') + savedCount + _t(' records');
}
var html =
'<div class="oe_search_container" style="display: flex; align-items: center; margin: 8px; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); padding: 12px; border-radius: 6px; border: 1px solid #dee2e6; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">' +
'<div class="oe_search_container" dir="' + dir + '" style="display: flex; align-items: center; margin: 8px; background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%); padding: 12px; border-radius: 6px; border: 1px solid #dee2e6; box-shadow: 0 1px 3px rgba(0,0,0,0.1);">' +
'<input type="text" class="oe_search_input form-control" ' +
'placeholder="' + _t('Search in all visible columns...') + '" ' +
'placeholder="' + _.escape(placeholder) + '" ' +
'value="' + _.escape(savedValue) + '" ' +
'dir="' + dir + '" ' +
'style="flex: 1; border: 1px solid #ced4da; height: 36px; padding: 0 12px; border-radius: 4px; font-size: 14px;" ' +
'autocomplete="off">' +
'<button class="btn btn-secondary oe_clear_search ml-2" style="display: ' + (savedValue ? 'inline-block' : 'none') + '; min-width: 70px;">' +
'<i class="fa fa-times mr-1"></i>' + _t('Clear') +
'<i class="fa fa-times mr-1"></i>' + clearText +
'</button>' +
'<span class="oe_search_count badge badge-success ml-2" style="display: ' + (isFiltered ? 'inline-block' : 'none') + '; padding: 6px 10px; font-size: 0.9em;">' +
(isFiltered ? _t('Found: ') + savedCount + _t(' records') : '') +
countText +
'</span>' +
'<span class="oe_search_loading ml-2" style="display: none; color: #007bff;">' +
'<i class="fa fa-spinner fa-spin"></i>' +
@ -590,9 +650,19 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
this.$el.prepend($(html));
// Focus on search input if it has value
// Store initial value
this._lastInputValue = savedValue;
// Focus on search input if it has value and set cursor to end
if (savedValue) {
this.$('.oe_search_input').focus();
var $input = this.$('.oe_search_input');
$input.focus();
var length = savedValue.length;
if ($input[0] && $input[0].setSelectionRange) {
setTimeout(function() {
$input[0].setSelectionRange(length, length);
}, 0);
}
}
},
@ -600,7 +670,15 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
* Handle input events
*/
_onCustomSearchInput: function(e) {
var hasValue = !!$(e.currentTarget).val().trim();
var currentValue = $(e.currentTarget).val();
var hasValue = !!currentValue.trim();
// Only handle if value actually changed (not just cursor movement)
if (currentValue === this._lastInputValue) {
return;
}
this._lastInputValue = currentValue;
this.$('.oe_clear_search').toggle(hasValue);
if (!hasValue) {
@ -615,11 +693,33 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
var self = this;
var value = $(e.currentTarget).val().trim();
// Ignore special keys
if (e.which === 13 || e.which === 27) {
// List of keys to ignore (navigation, modifiers, etc.)
var ignoreKeys = [
13, // Enter (handled separately)
27, // Escape (handled separately)
16, 17, 18, // Shift, Ctrl, Alt
91, 93, // Command keys (Mac)
37, 38, 39, 40, // Arrow keys
33, 34, 35, 36, // Page Up/Down, Home, End
9, // Tab
20, // Caps Lock
144, // Num Lock
145, // Scroll Lock
112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123 // F1-F12
];
// Ignore if it's a navigation or modifier key
if (ignoreKeys.indexOf(e.which) !== -1) {
return;
}
// Check if the actual value changed
if (value === this._lastSearchValue) {
return;
}
this._lastSearchValue = value;
// Clear previous timer
if (this._searchTimer) {
clearTimeout(this._searchTimer);
@ -664,6 +764,8 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) {
this.$('.oe_search_input').val('').focus();
this.$('.oe_clear_search').hide();
this.$('.oe_search_count').hide();
this._lastInputValue = '';
this._lastSearchValue = '';
// Delegate to controller
if (this.getParent() && this.getParent()._clearCustomSearch) {