diff --git a/odex25_base/fims_general_search_tree_view/static/src/js/list_search.js b/odex25_base/fims_general_search_tree_view/static/src/js/list_search.js index 985db20bf..4f83cdb60 100644 --- a/odex25_base/fims_general_search_tree_view/static/src/js/list_search.js +++ b/odex25_base/fims_general_search_tree_view/static/src/js/list_search.js @@ -3,17 +3,12 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { var ListRenderer = require('web.ListRenderer'); var ListController = require('web.ListController'); - var relational_fields = require('web.relational_fields'); var core = require('web.core'); var _t = core._t; var concurrency = require('web.concurrency'); var rpc = require('web.rpc'); var session = require('web.session'); - // Get relational field classes - var FieldOne2Many = relational_fields.FieldOne2Many; - var FieldMany2Many = relational_fields.FieldMany2Many; - ListController.include({ init: function () { this._super.apply(this, arguments); @@ -387,7 +382,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { if (state.isFiltered && state.filteredCount >= 0) { this.$('.oe_search_count') - .text(_t('عدد السجلات: ') + state.filteredCount) + .text(_t('Records: ') + state.filteredCount) .removeClass('text-danger') .show(); } @@ -415,7 +410,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { } var countText = isFiltered ? - _t('عدد السجلات: ') + savedCount : ''; + _t('Records: ') + savedCount : ''; var html = '
' + @@ -517,305 +512,8 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { } }); - // ============= NEW: Relational Fields Support ============= - - // Mixin for common relational field functionality - var RelationalFieldMixin = { - - _searchState: null, - _searchMutex: null, - - init: function() { - this._super.apply(this, arguments); - this._initRelationalSearch(); - }, - - _initRelationalSearch: function() { - this._searchState = { - timer: null, - value: '', - isFiltered: false, - filteredCount: 0, - originalRecords: null, - allRecords: null, - lastSearchValue: '' - }; - this._searchMutex = new concurrency.Mutex(); - }, - - _renderView: function() { - var self = this; - return this._super.apply(this, arguments).then(function(result) { - if (self._shouldAddRelationalSearchBox()) { - self._addRelationalSearchBox(); - self._storeOriginalRecords(); - } - return result; - }); - }, - - _shouldAddRelationalSearchBox: function() { - return this.renderer && - this.renderer.$el && - this.renderer.$el.find('.o_list_view').length > 0 && - !this.renderer.$el.find('.oe_relational_search_container').length && - this.value && - this.value.data && - this.value.data.length > 0; - }, - - _storeOriginalRecords: function() { - if (this.value && this.value.data && !this._searchState.originalRecords) { - this._searchState.originalRecords = JSON.parse(JSON.stringify(this.value.data)); - this._searchState.allRecords = JSON.parse(JSON.stringify(this.value.data)); - } - }, - - _addRelationalSearchBox: function() { - var self = this; - var savedValue = this._searchState.value || ''; - var savedCount = this._searchState.filteredCount || 0; - var isFiltered = this._searchState.isFiltered || false; - - var countText = isFiltered ? - _t('عدد السجلات: ') + savedCount : ''; - - var html = - '
' + - '' + - '' + - '' + - countText + - '' + - '' + - '
'; - - var $listContainer = this.renderer.$el.find('.o_list_view').first(); - $listContainer.prepend($(html)); - - // Bind events - this.renderer.$el.find('.oe_relational_search_input').on('keyup', function(e) { - self._onRelationalSearchKeyUp(e); - }); - - this.renderer.$el.find('.oe_relational_search_input').on('input', function(e) { - self._onRelationalSearchInput(e); - }); - - this.renderer.$el.find('.oe_relational_clear_search').on('click', function(e) { - self._onRelationalClearSearch(e); - }); - - this.renderer.$el.find('.oe_relational_search_input').on('keydown', function(e) { - self._onRelationalSearchKeyDown(e); - }); - }, - - _onRelationalSearchInput: function(e) { - var currentValue = $(e.currentTarget).val(); - var hasValue = !!currentValue.trim(); - - this.renderer.$el.find('.oe_relational_clear_search').toggle(hasValue); - - if (!hasValue) { - this.renderer.$el.find('.oe_relational_search_count').hide(); - } - }, - - _onRelationalSearchKeyUp: function(e) { - var self = this; - var value = $(e.currentTarget).val().trim(); - var ignoreKeys = [13, 27, 16, 17, 18, 91, 93, 37, 38, 39, 40, - 33, 34, 35, 36, 9, 20, 144, 145, - 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123]; - - if (ignoreKeys.indexOf(e.which) !== -1) return; - if (value === this._searchState.lastSearchValue) return; - - this._searchState.lastSearchValue = value; - - if (this._searchState.timer) { - clearTimeout(this._searchState.timer); - } - - this._searchState.timer = setTimeout(function() { - self._executeRelationalSearch(value); - }, 300); - }, - - _onRelationalSearchKeyDown: function(e) { - if (e.which === 13) { - e.preventDefault(); - if (this._searchState.timer) { - clearTimeout(this._searchState.timer); - } - var value = $(e.currentTarget).val().trim(); - this._executeRelationalSearch(value); - } else if (e.which === 27) { - e.preventDefault(); - this._onRelationalClearSearch(); - } - }, - - _onRelationalClearSearch: function() { - this.renderer.$el.find('.oe_relational_search_input').val('').focus(); - this.renderer.$el.find('.oe_relational_clear_search').hide(); - this.renderer.$el.find('.oe_relational_search_count').hide(); - this._searchState.lastSearchValue = ''; - this._clearRelationalSearch(); - }, - - _executeRelationalSearch: function(value) { - var self = this; - - return this._searchMutex.exec(function() { - if (!value || value.length === 0) { - return self._clearRelationalSearch(); - } - - return self._applyRelationalSearch(value); - }); - }, - - _applyRelationalSearch: function(value) { - var self = this; - - if (!this._searchState.allRecords || this._searchState.allRecords.length === 0) { - return Promise.resolve(); - } - - var normalizedSearch = this._normalizeText(value.toLowerCase()); - var searchValues = [value.toLowerCase(), normalizedSearch].filter(function(v, i, arr) { - return arr.indexOf(v) === i; // Remove duplicates - }); - - var filteredRecords = this._searchState.allRecords.filter(function(record) { - return self._recordMatchesSearch(record, searchValues); - }); - - this._searchState.filteredCount = filteredRecords.length; - this._searchState.isFiltered = true; - this._searchState.value = value; - - // Update the UI - this._updateRelationalSearchUI(filteredRecords.length); - - // Update the field's value with filtered data - var newValue = _.clone(this.value); - newValue.data = filteredRecords; - newValue.count = filteredRecords.length; - - // Re-render with filtered data - return this._setValue(newValue, {forceChange: true}).then(function() { - return Promise.resolve(); - }); - }, - - _recordMatchesSearch: function(record, searchValues) { - var self = this; - var recordData = record.data || {}; - - // Get searchable fields from the record - var searchableValues = []; - - // Add all text-like fields - Object.keys(recordData).forEach(function(fieldName) { - var value = recordData[fieldName]; - if (value !== null && value !== undefined) { - if (typeof value === 'string') { - searchableValues.push(value.toLowerCase()); - searchableValues.push(self._normalizeText(value.toLowerCase())); - } else if (typeof value === 'number') { - searchableValues.push(value.toString()); - } else if (Array.isArray(value) && value.length === 2) { - // Many2one field format [id, display_name] - if (typeof value[1] === 'string') { - searchableValues.push(value[1].toLowerCase()); - searchableValues.push(self._normalizeText(value[1].toLowerCase())); - } - } - } - }); - - // Check if any search value matches any record value - return searchValues.some(function(searchValue) { - return searchableValues.some(function(recordValue) { - return recordValue.indexOf(searchValue) !== -1; - }); - }); - }, - - _clearRelationalSearch: function() { - if (!this._searchState.originalRecords) { - return Promise.resolve(); - } - - this._searchState.value = ''; - this._searchState.isFiltered = false; - this._searchState.filteredCount = 0; - this._searchState.lastSearchValue = ''; - - // Restore original records - var newValue = _.clone(this.value); - newValue.data = JSON.parse(JSON.stringify(this._searchState.originalRecords)); - newValue.count = this._searchState.originalRecords.length; - - // Hide search UI elements - if (this.renderer && this.renderer.$el) { - this.renderer.$el.find('.oe_relational_search_count').hide(); - this.renderer.$el.find('.oe_relational_search_loading').hide(); - } - - // Re-render with original data - return this._setValue(newValue, {forceChange: true}); - }, - - _updateRelationalSearchUI: function(count) { - if (this.renderer && this.renderer.$el) { - this.renderer.$el.find('.oe_relational_search_count') - .text(_t('عدد السجلات: ') + count) - .removeClass('text-danger') - .show(); - this.renderer.$el.find('.oe_relational_clear_search').show(); - } - }, - - _normalizeText: function(text) { - if (!text) return ''; - return text - .replace(/[\u064B-\u065F]/g, '') // Remove Arabic diacritics - .replace(/[٠-٩]/g, function(d) { // Convert Arabic-Indic digits - return String.fromCharCode(d.charCodeAt(0) - 0x0660 + 0x0030); - }) - .replace(/[۰-۹]/g, function(d) { // Convert Extended Arabic-Indic digits - return String.fromCharCode(d.charCodeAt(0) - 0x06F0 + 0x0030); - }) - .replace(/[آأإا]/g, 'ا') // Normalize Alef variations - .replace(/ة/g, 'ه') // Normalize Taa Marbouta - .replace(/[يئى]/g, 'ي') // Normalize Yaa variations - .trim(); - } - }; - - // Apply the mixin to FieldOne2Many - FieldOne2Many.include(RelationalFieldMixin); - - // Apply the mixin to FieldMany2Many - FieldMany2Many.include(RelationalFieldMixin); - return { ListController: ListController, - ListRenderer: ListRenderer, - FieldOne2Many: FieldOne2Many, - FieldMany2Many: FieldMany2Many + ListRenderer: ListRenderer }; }); \ No newline at end of file