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 ff073dade..85a246f67 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 @@ -30,8 +30,9 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { _renderView: function () { var self = this; - // IMPORTANT: Don't reset search state, just preserve it - var hasActiveSearch = this._search && this._search.value; + // Store search state before render + var searchValue = this._search ? this._search.value : ''; + var hasActiveSearch = searchValue && searchValue.length > 0; return this._super.apply(this, arguments).then(function () { // Add search box if needed @@ -43,15 +44,16 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { self._addSearchBox(); } - // Always restore search state after render + // Always restore search UI self._restoreSearchUI(); - // If we have an active search, apply the filter - if (hasActiveSearch && self._search.filteredIds) { - // Apply filter after DOM is ready + // If we had an active search, re-apply it after a short delay + if (hasActiveSearch) { setTimeout(function() { - self._reapplySearchFilter(); - }, 0); + if (self._search && self._search.value) { + self._performSearch(self._search.value); + } + }, 100); } } }); @@ -115,21 +117,6 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { } }, - /** - * Reapply search filter after re-render - */ - _reapplySearchFilter: function() { - if (!this._search || !this._search.filteredIds) return; - - // If we have all filtered records, update the view - if (this._search.allFilteredRecords) { - this._updateViewWithFilteredData(this._search.allFilteredRecords, false); - } else { - // Just apply DOM filter - this._applyDOMFilter(this._search.filteredIds); - } - }, - /** * Handle search input event (immediate tracking) */ @@ -263,213 +250,292 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { return; } - // Update the view with filtered results - this._updateViewWithFilteredData(records, true); + // Update the view with filtered results - CRITICAL FIX + this._updateViewWithFilteredData(records); }, /** - * Update view with filtered data - THE KEY METHOD + * Update view with filtered data - COMPLETELY REWRITTEN */ - _updateViewWithFilteredData: function(records, updateState) { + _updateViewWithFilteredData: function(records) { var self = this; - var limit = this.state.limit || 80; - var pageRecords = records.slice(0, limit); - // Method 1: Try DOM filtering first (fastest, preserves input) - var domFilterSuccess = this._tryDOMFiltering(this._search.filteredIds, limit); + // Method 1: Try to filter existing DOM rows first + var domFilterWorked = this._filterExistingRows(); - if (domFilterSuccess) { - // DOM filtering worked, just update pager + if (domFilterWorked) { + // Update pager with correct count this._updatePager(records.length); return; } - // Method 2: Need to update data and re-render - // This happens when DOM doesn't have the records we need - if (updateState && this.state && this.state.data) { - // Update state with filtered data - this.state.data.records = pageRecords; - this.state.count = records.length; - this.state.res_ids = this._search.filteredIds; - - // Clear and re-render - this._clearTableBody(); - this._renderFilteredRows(); - } + // Method 2: Update the actual data and re-render + this._updateStateAndRerender(records); }, /** - * Try DOM filtering first (fastest method) + * Filter existing rows in DOM - ENHANCED METHOD */ - _tryDOMFiltering: function(filteredIds, limit) { - var $rows = this.$('.o_data_row'); - if ($rows.length === 0) { - return false; // No rows to filter + _filterExistingRows: function() { + if (!this._search.filteredIds || this._search.filteredIds.length === 0) { + return false; } var self = this; + var $allRows = this.$('.o_data_row'); + var limit = this.state.limit || 80; var visibleCount = 0; - var foundMatch = false; + var foundAnyMatch = false; - $rows.each(function() { + console.log('Filtering rows. Total rows:', $allRows.length, 'Filtered IDs:', this._search.filteredIds); + + // First pass: hide all rows + $allRows.hide(); + + // Second pass: show matching rows up to limit + $allRows.each(function(index) { var $row = $(this); var rowId = self._getRowId($row); - if (rowId && filteredIds.includes(rowId)) { + console.log('Row', index, 'ID:', rowId, 'Should show:', self._search.filteredIds.includes(rowId)); + + if (rowId && self._search.filteredIds.includes(rowId)) { if (visibleCount < limit) { $row.show(); visibleCount++; - foundMatch = true; - } else { - $row.hide(); + foundAnyMatch = true; + console.log('Showing row', index, 'with ID', rowId); } - } else { - $row.hide(); } }); - return foundMatch; - }, - - /** - * Clear table body - */ - _clearTableBody: function() { - this.$('tbody .o_data_row').remove(); - this.$('.oe_no_results').remove(); - }, - - /** - * Render filtered rows - */ - _renderFilteredRows: function() { - var self = this; + console.log('DOM filtering result - Found matches:', foundAnyMatch, 'Visible count:', visibleCount); - try { - // Try Odoo's internal render methods - if (typeof this._renderRows === 'function') { - var $rows = this._renderRows(); - if ($rows && $rows.length) { - this.$('tbody').append($rows); - this._updatePager(this._search.filteredIds.length); - return; - } - } - - if (typeof this._renderBody === 'function') { - var result = this._renderBody(); - if (result && typeof result.then === 'function') { - result.then(function() { - self._updatePager(self._search.filteredIds.length); - }); - } else { - this._updatePager(this._search.filteredIds.length); - } - return; - } - } catch (err) { - console.warn('Render failed, using fallback:', err); + // If no matches found in DOM, we need to re-render + return foundAnyMatch; + }, + + /** + * Update state and re-render - ENHANCED METHOD + */ + _updateStateAndRerender: function(records) { + var self = this; + var limit = this.state.limit || 80; + var pageRecords = records.slice(0, limit); + + console.log('Re-rendering with filtered data. Total records:', records.length, 'Page records:', pageRecords.length); + + // Update state + if (this.state && this.state.data) { + this.state.data.records = pageRecords; + this.state.count = records.length; + this.state.res_ids = this._search.filteredIds; } - // Fallback: Create rows manually - this._createRowsManually(); + // Clear existing rows + this.$('tbody .o_data_row').remove(); + this.$('.oe_no_results').remove(); + + // Try different rendering approaches + this._tryMultipleRenderMethods(pageRecords); + + // Update pager + this._updatePager(records.length); }, /** - * Create rows manually as last resort + * Try multiple rendering methods - NEW ENHANCED METHOD */ - _createRowsManually: function() { + _tryMultipleRenderMethods: function(records) { var self = this; - var records = this.state.data.records; + var renderSuccess = false; - if (!records || records.length === 0) return; + // Method 1: Try Odoo's _renderRows if available + if (!renderSuccess && typeof this._renderRows === 'function') { + try { + var $rows = this._renderRows(); + if ($rows && $rows.length > 0) { + this.$('tbody').append($rows); + renderSuccess = true; + console.log('Render method 1 succeeded'); + } + } catch (err) { + console.warn('Render method 1 failed:', err); + } + } - records.forEach(function(record) { + // Method 2: Try _renderBody if available + if (!renderSuccess && typeof this._renderBody === 'function') { + try { + var result = this._renderBody(); + if (result) { + if (typeof result.then === 'function') { + result.then(function() { + console.log('Render method 2 succeeded (async)'); + }); + } else { + console.log('Render method 2 succeeded (sync)'); + } + renderSuccess = true; + } + } catch (err) { + console.warn('Render method 2 failed:', err); + } + } + + // Method 3: Manual row creation (fallback) + if (!renderSuccess) { + console.log('Using manual row creation fallback'); + this._createRowsManually(records); + renderSuccess = true; + } + + return renderSuccess; + }, + + /** + * Create rows manually - ENHANCED FALLBACK + */ + _createRowsManually: function(records) { + var self = this; + + if (!records || records.length === 0) { + console.log('No records to create rows for'); + return; + } + + console.log('Creating', records.length, 'rows manually'); + + records.forEach(function(record, index) { var $row = $(''); - $row.data('id', record.id); - $row.attr('data-id', record.id); - // Add cells for each visible column - if (self.columns) { + // Set multiple ID attributes for better compatibility + $row.attr('data-id', record.id); + $row.attr('data-res-id', record.id); + $row.data('id', record.id); + $row.data('res-id', record.id); + + // Store record data + $row.data('record', record); + + console.log('Creating row for record ID:', record.id); + + // Add cells based on visible columns + if (self.columns && self.columns.length > 0) { self.columns.forEach(function(col) { if (!col.invisible && col.attrs && col.attrs.name) { - var value = record[col.attrs.name] || ''; - - // Handle many2one fields - if (typeof value === 'object' && value) { - if (Array.isArray(value) && value.length >= 2) { - value = value[1]; - } else if (value.display_name) { - value = value.display_name; - } else { - value = ''; - } - } - - var $cell = $(''); - $cell.text(value); - $cell.attr('data-field', col.attrs.name); + var $cell = self._createCellForField(record, col); $row.append($cell); } }); + } else { + // Fallback: create basic cells + var cellValue = record.display_name || record.name || record.id; + var $cell = $('').text(cellValue); + $row.append($cell); } self.$('tbody').append($row); }); - this._updatePager(this._search.filteredIds.length); + console.log('Manual row creation completed'); }, /** - * Apply DOM filter (used after re-render) + * Create cell for specific field - NEW HELPER METHOD */ - _applyDOMFilter: function(filteredIds) { - var self = this; - var $rows = this.$('.o_data_row'); - var limit = this.state.limit || 80; - var visibleCount = 0; + _createCellForField: function(record, col) { + var fieldName = col.attrs.name; + var value = record[fieldName]; + var displayValue = ''; - $rows.each(function() { - var $row = $(this); - var rowId = self._getRowId($row); - - if (rowId && filteredIds.includes(rowId) && visibleCount < limit) { - $row.show(); - visibleCount++; + // Handle different field types + if (value !== null && value !== undefined) { + if (typeof value === 'object' && value) { + // Many2one field + if (Array.isArray(value) && value.length >= 2) { + displayValue = value[1]; + } else if (value.display_name) { + displayValue = value.display_name; + } else { + displayValue = String(value); + } } else { - $row.hide(); + displayValue = String(value); } - }); + } + + var $cell = $(''); + $cell.text(displayValue); + $cell.attr('data-field', fieldName); + + // Add field-specific classes if needed + if (col.attrs.class) { + $cell.addClass(col.attrs.class); + } + + return $cell; }, /** - * Get row ID from DOM element + * Get row ID from DOM element - ENHANCED METHOD */ _getRowId: function($row) { // Method 1: data-id attribute var id = $row.attr('data-id'); - if (id) return parseInt(id); + if (id && !isNaN(parseInt(id))) { + return parseInt(id); + } - // Method 2: jQuery data - id = $row.data('id'); - if (id) return parseInt(id); - - // Method 3: data-res-id attribute + // Method 2: data-res-id attribute id = $row.attr('data-res-id'); - if (id) return parseInt(id); + if (id && !isNaN(parseInt(id))) { + return parseInt(id); + } + + // Method 3: jQuery data id + id = $row.data('id'); + if (id && !isNaN(parseInt(id))) { + return parseInt(id); + } // Method 4: jQuery data res-id id = $row.data('res-id'); - if (id) return parseInt(id); - - // Method 5: Check for record object - var record = $row.data('record'); - if (record) { - if (record.res_id) return record.res_id; - if (record.id) return record.id; - if (record.data && record.data.id) return record.data.id; + if (id && !isNaN(parseInt(id))) { + return parseInt(id); } + // Method 5: Check for record object in data + var record = $row.data('record'); + if (record) { + if (record.res_id && !isNaN(parseInt(record.res_id))) { + return parseInt(record.res_id); + } + if (record.id && !isNaN(parseInt(record.id))) { + return parseInt(record.id); + } + if (record.data && record.data.id && !isNaN(parseInt(record.data.id))) { + return parseInt(record.data.id); + } + } + + // Method 6: Look for hidden inputs with record ID + var $hiddenInput = $row.find('input[name="id"]'); + if ($hiddenInput.length) { + id = $hiddenInput.val(); + if (id && !isNaN(parseInt(id))) { + return parseInt(id); + } + } + + // Method 7: Check if row has any reference to record ID in classes + var classes = $row.attr('class') || ''; + var match = classes.match(/o_data_row_(\d+)/); + if (match) { + return parseInt(match[1]); + } + + console.warn('Could not determine row ID for row:', $row[0]); return null; }, @@ -487,7 +553,7 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { }, /** - * Client-side search fallback + * Client-side search fallback - ENHANCED */ _clientSideSearch: function(value) { var self = this; @@ -497,17 +563,25 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { var limit = this.state.limit || 80; var matchedIds = []; + console.log('Using client-side search fallback'); + this.$('.o_data_row').each(function() { var $row = $(this); var text = $row.text().toLowerCase(); var normalizedText = self._normalizeArabic(text); var match = text.includes(searchLower) || normalizedText.includes(normalized); - if (match && visible < limit) { - $row.show(); - visible++; - var rowId = self._getRowId($row); - if (rowId) matchedIds.push(rowId); + if (match) { + if (visible < limit) { + $row.show(); + visible++; + var rowId = self._getRowId($row); + if (rowId) { + matchedIds.push(rowId); + } + } else { + $row.hide(); + } } else { $row.hide(); } @@ -528,12 +602,16 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { } this._updatePager(visible); + + console.log('Client-side search completed. Visible:', visible, 'IDs:', matchedIds); }, /** - * Clear search + * Clear search - ENHANCED */ _clearSearch: function() { + console.log('Clearing search'); + // Clear UI this.$('.oe_search_input').val(''); this.$('.oe_clear_search').hide(); @@ -574,18 +652,23 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { this._search.originalData = null; this._search.originalDomain = null; } else { - // Just show rows with limit + // Just show all rows with limit var $rows = this.$('.o_data_row'); - var limit = this.state.limit || 80; + var limit = this.state ? (this.state.limit || 80) : 80; + $rows.show(); // Show all first $rows.each(function(index) { - $(this).toggle(index < limit); + if (index >= limit) { + $(this).hide(); + } }); if (this.state) { this._updatePager(this.state.count || $rows.length); } } + + console.log('Search cleared'); }, /** @@ -602,6 +685,8 @@ odoo.define('fims_general_search_tree_view.list_search', function (require) { offset: this.state.offset || 0 }; this._search.originalDomain = this.state.domain ? this.state.domain.slice() : []; + + console.log('Stored original data:', this._search.originalData); } },