details:   https://code.tryton.org/tryton/commit/23cedc854f49
branch:    default
user:      Nicolas Évrard <[email protected]>
date:      Fri Nov 21 16:09:28 2025 +0100
description:
        Replace jQuery's hide and show by our own implementation

        jQuery's implementation triggers forced reflows and style recomputation 
which
        hinders performances. Given that we only care about the node on which 
the call
        is done we can use a simpler and more efficient implementation.

        Closes #14330
diffstat:

 sao/src/common.js    |  16 +++++-----
 sao/src/sao.js       |  33 +++++++++++++++++++++--
 sao/src/screen.js    |  22 +++++++-------
 sao/src/session.js   |   8 ++--
 sao/src/tab.js       |   2 +-
 sao/src/view/form.js |  74 ++++++++++++++++++++++++++--------------------------
 sao/src/view/tree.js |  72 +++++++++++++++++++++++++-------------------------
 sao/src/window.js    |   4 +-
 8 files changed, 129 insertions(+), 102 deletions(-)

diffs (712 lines):

diff -r 862b305c0d33 -r 23cedc854f49 sao/src/common.js
--- a/sao/src/common.js Fri Mar 13 15:14:09 2026 +0100
+++ b/sao/src/common.js Fri Nov 21 16:09:28 2025 +0100
@@ -1014,9 +1014,9 @@
                 states = {'invisible': true};
             }
             if (states.invisible) {
-                this.el.hide();
+                this.el.sao_hide();
             } else {
-                this.el.show();
+                this.el.sao_show();
             }
             this.el.prop('disabled', Boolean(states.readonly));
             this.set_icon(states.icon || this.attributes.icon);
@@ -3746,7 +3746,7 @@
                     'text': '.',
                 }));
             }
-            this.el.hide();
+            this.el.sao_hide();
             jQuery(() => {
                 this.el.appendTo('body');
             });
@@ -3757,7 +3757,7 @@
             }
             return window.setTimeout(() => {
                 this.queries += 1;
-                this.el.show();
+                this.el.sao_show();
             }, timeout);
         },
         hide: function(timeoutID) {
@@ -3767,7 +3767,7 @@
             }
             if (this.queries <= 0) {
                 this.queries = 0;
-                this.el.hide();
+                this.el.sao_hide();
             }
         }
     });
@@ -3821,7 +3821,7 @@
             }).append(jQuery('<ul/>', {
                 'class': 'list-unstyled',
             })).appendTo(this.menu);
-            this.actions.hide();
+            this.actions.sao_hide();
 
             this.source = source;
             this.match_selected = match_selected;
@@ -3877,10 +3877,10 @@
             }
             this.actions.find('li.action').remove();
             if (jQuery.isEmptyObject(actions)) {
-                this.actions.hide();
+                this.actions.sao_hide();
                 return;
             }
-            this.actions.show();
+            this.actions.sao_show();
             actions.forEach(function(action) {
                 var action_id = action[0];
                 var content = action[1];
diff -r 862b305c0d33 -r 23cedc854f49 sao/src/sao.js
--- a/sao/src/sao.js    Fri Mar 13 15:14:09 2026 +0100
+++ b/sao/src/sao.js    Fri Nov 21 16:09:28 2025 +0100
@@ -88,7 +88,22 @@
         // continue
     }
 
-    // Add .uniqueId to jQuery
+    Sao._showHide = function(elements, show) {
+        for (let element of elements) {
+            let display = element.style.display;
+            if (show) {
+                if (display === 'none') {
+                    element.style.display = 'revert';
+                }
+            } else {
+                if (display !== 'none') {
+                    element.style.display = 'none';
+                }
+            }
+        }
+    }
+
+    // Add custom functions to jQuery
     jQuery.fn.extend({
         uniqueId: (function() {
             var uuid = 0;
@@ -99,7 +114,19 @@
                     }
                 });
             };
-        })()
+        })(),
+        sao_show: function() {
+            Sao._showHide(this.toArray(), true);
+            return this;
+        },
+        sao_hide: function() {
+            Sao._showHide(this.toArray(), false);
+            return this;
+        },
+        sao_toggle: function(bool) {
+            Sao._showHide(this.toArray(), bool);
+            return this;
+        },
     });
 
     window.onbeforeunload = function(e) {
@@ -818,7 +845,7 @@
             var view = screen.current_view;
             view.table.removeClass('table table-bordered');
             view.table.addClass('no-responsive');
-            view.table.find('thead').hide();
+            view.table.find('thead').sao_hide();
             view.table.find('colgroup > col.tree-menu').css('width', 0);
             var gs = new Sao.GlobalSearch();
             jQuery('#global-search').empty();
diff -r 862b305c0d33 -r 23cedc854f49 sao/src/screen.js
--- a/sao/src/screen.js Fri Mar 13 15:14:09 2026 +0100
+++ b/sao/src/screen.js Fri Nov 21 16:09:28 2025 +0100
@@ -52,7 +52,7 @@
                 'aria-label': Sao.i18n.gettext("Clear Search"),
                 'title': Sao.i18n.gettext("Clear Search"),
             }).append(Sao.common.ICONFACTORY.get_icon_img('tryton-clear'));
-            but_clear.hide();
+            but_clear.sao_hide();
             but_clear.click(() => {
                 this.search_entry.val('').change();
                 this.do_search();
@@ -60,9 +60,9 @@
 
             this.search_entry.on('keyup change', () => {
                 if (this.search_entry.val()) {
-                    but_clear.show();
+                    but_clear.sao_show();
                 } else {
-                    but_clear.hide();
+                    but_clear.sao_hide();
                 }
                 this.bookmark_match();
             });
@@ -400,15 +400,15 @@
             this.but_bookmark.prop(
                 'disabled', jQuery.isEmptyObject(this.bookmarks()));
             this.bookmark_match();
-            this.filter_box.show();
+            this.filter_box.sao_show();
             if (this.tab) {
-                this.tab.show();
+                this.tab.sao_show();
             }
         },
         hide_filter: function() {
-            this.filter_box.hide();
+            this.filter_box.sao_hide();
             if (this.tab) {
-                this.tab.hide();
+                this.tab.sao_hide();
             }
         },
         set: function(widget) {
@@ -738,7 +738,7 @@
                     this, placeholder, el);
                 if (~navigator.userAgent.indexOf("Firefox")) {
                     // time input on Firefox does not have a pop-up
-                    entry.find('.icon-input').hide();
+                    entry.find('.icon-input').sao_hide();
                 }
                 return entry;
             },
@@ -1406,12 +1406,12 @@
                     let view_tree = this.fields_view_tree[
                         this.current_view.view_id] || {};
                     if ('active' in view_tree.fields) {
-                        this.screen_container.but_active.show();
+                        this.screen_container.but_active.sao_show();
                     } else {
-                        this.screen_container.but_active.hide();
+                        this.screen_container.but_active.sao_hide();
                     }
                 } else {
-                    this.screen_container.but_active.hide();
+                    this.screen_container.but_active.sao_hide();
                 }
             }
             return jQuery.when.apply(jQuery, deferreds).then(
diff -r 862b305c0d33 -r 23cedc854f49 sao/src/session.js
--- a/sao/src/session.js        Fri Mar 13 15:14:09 2026 +0100
+++ b/sao/src/session.js        Fri Nov 21 16:09:28 2025 +0100
@@ -229,12 +229,12 @@
             'class': 'form-control',
             'id': 'database',
             'name': 'database',
-        }).hide();
+        }).sao_hide();
         dialog.database_input = jQuery('<input/>', {
             'class': 'form-control',
             'id': 'database',
             'name': 'database',
-        }).hide();
+        }).sao_hide();
         dialog.login_input = jQuery('<input/>', {
             'class': 'form-control',
             'id': 'login',
@@ -389,10 +389,10 @@
                 }
             }
             el.prop('readonly', databases.length == 1);
-            el.show();
+            el.sao_show();
             el.val(database || '');
         }, function() {
-            dialog.database_input.show();
+            dialog.database_input.sao_show();
         });
 
         jQuery.when(Sao.Authentication.services()).then(function(services) {
diff -r 862b305c0d33 -r 23cedc854f49 sao/src/tab.js
--- a/sao/src/tab.js    Fri Mar 13 15:14:09 2026 +0100
+++ b/sao/src/tab.js    Fri Nov 21 16:09:28 2025 +0100
@@ -802,7 +802,7 @@
 
             this.sidebar = jQuery('<div/>', {
                 'class': 'sidebar',
-            }).hide().appendTo(this.main);
+            }).sao_hide().appendTo(this.main);
             this.sidebar_content = jQuery('<div/>', {
                 'class': 'sidebar-content',
             }).appendTo(jQuery('<div/>', {
diff -r 862b305c0d33 -r 23cedc854f49 sao/src/view/form.js
--- a/sao/src/view/form.js      Fri Mar 13 15:14:09 2026 +0100
+++ b/sao/src/view/form.js      Fri Nov 21 16:09:28 2025 +0100
@@ -345,7 +345,7 @@
             var field;
             var promesses = [];
             if (this.scan_code_btn) {
-                this.scan_code_btn.el.toggle(Boolean(record));
+                this.scan_code_btn.el.sao_toggle(Boolean(record));
             }
             if (record) {
                 // Force to set fields in record
@@ -789,10 +789,10 @@
             }
         },
         show: function() {
-            this.el.show();
+            this.el.sao_show();
         },
         hide: function() {
-            this.el.hide();
+            this.el.sao_hide();
         }
     });
 
@@ -1092,7 +1092,7 @@
                 this._current = record.id;
             } else {
                 this._current = null;
-                this.el.hide();
+                this.el.sao_hide();
                 return;
             }
             pyson_ctx.context = context;
@@ -1200,9 +1200,9 @@
                     return number != 0;
                 });
                 if (non_empty.length) {
-                    this.el.show();
+                    this.el.sao_show();
                 } else {
-                    this.el.hide();
+                    this.el.sao_hide();
                 }
             }
         },
@@ -1412,9 +1412,9 @@
         set_invisible: function(invisible) {
             this.visible = !invisible;
             if (invisible) {
-                this.el.hide();
+                this.el.sao_hide();
             } else {
-                this.el.show();
+                this.el.sao_show();
             }
         },
         focus: function() {
@@ -1942,9 +1942,9 @@
             this.el.find('input').prop('readonly', readonly);
             if (this.icon){
                 if (readonly) {
-                    this.icon.hide();
+                    this.icon.sao_hide();
                 } else {
-                    this.icon.show();
+                    this.icon.sao_show();
                 }
             }
         },
@@ -1986,7 +1986,7 @@
             Sao.View.Form.Time._super.init.call(this, view, attributes);
             if (~navigator.userAgent.indexOf("Firefox")) {
                 // time input on Firefox does not have a pop-up
-                this.input.parent().hide();
+                this.input.parent().sao_hide();
             }
         },
         get_format: function() {
@@ -2067,18 +2067,18 @@
         input.attr('step', 1);
         input.attr('lang', Sao.i18n.BC47(Sao.i18n.getlang()));
 
-        input.hide().on('focusout', function() {
+        input.sao_hide().on('focusout', function() {
             if (input[0].checkValidity()) {
                 switch_id(input, input_text);
-                input.hide();
-                input_text.show();
+                input.sao_hide();
+                input_text.sao_show();
             }
         });
         input_text.on('focusin', function() {
             if (!input.prop('readonly')) {
                 switch_id(input, input_text);
-                input_text.hide();
-                input.show();
+                input_text.sao_hide();
+                input.sao_show();
                 window.setTimeout(function() {
                     input.focus();
                 });
@@ -2145,10 +2145,10 @@
             var set_symbol = function(el, text) {
                 if (text) {
                     el.text(text);
-                    el.show();
+                    el.sao_show();
                 } else {
                     el.text('');
-                    el.hide();
+                    el.sao_hide();
                 }
             };
             Sao.View.Form.Integer._super.display.call(this);
@@ -2186,8 +2186,8 @@
         },
         focus: function() {
             if (!this.input.prop('readonly')) {
-                this.input_text.hide();
-                this.input.show().focus();
+                this.input_text.sao_hide();
+                this.input.sao_show().focus();
             } else {
                 this.input_text.focus();
             }
@@ -2736,8 +2736,8 @@
 
             if (!record) {
                 this.entry.val('');
-                this.but_primary.parent().hide();
-                this.but_secondary.parent().hide();
+                this.but_primary.parent().sao_hide();
+                this.but_secondary.parent().sao_hide();
                 return;
             }
             this.set_text(field.get_client(record));
@@ -2767,10 +2767,10 @@
                 var icon_input = button.parent();
                 var type = 'input-icon-' + items[3];
                 if (!icon_name) {
-                    icon_input.hide();
+                    icon_input.sao_hide();
                     icon_input.parent().removeClass(type);
                 } else {
-                    icon_input.show();
+                    icon_input.sao_show();
                     icon_input.parent().addClass(type);
                     
Sao.common.ICONFACTORY.get_icon_url(icon_name).then(function(url) {
                         button.find('img').attr('src', url);
@@ -4488,13 +4488,13 @@
         },
         update_buttons: function(value) {
             if (value) {
-                this.but_save_as.show();
-                this.but_select.hide();
-                this.but_clear.show();
+                this.but_save_as.sao_show();
+                this.but_select.sao_hide();
+                this.but_clear.sao_show();
             } else {
-                this.but_save_as.hide();
-                this.but_select.show();
-                this.but_clear.hide();
+                this.but_save_as.sao_hide();
+                this.but_select.sao_show();
+                this.but_clear.sao_hide();
             }
         },
         select: function() {
@@ -4624,7 +4624,7 @@
                     this.text.val('');
                 }
                 this.size.val('');
-                this.but_save_as.hide();
+                this.but_save_as.sao_hide();
                 return;
             }
             var size;
@@ -4638,9 +4638,9 @@
             if (this.text) {
                 this.text.val(this.filename_field.get(record) || '');
                 if (size) {
-                    this.but_open.parent().show();
+                    this.but_open.parent().sao_show();
                 } else {
-                    this.but_open.parent().hide();
+                    this.but_open.parent().sao_hide();
                 }
             }
             this.update_buttons(Boolean(size));
@@ -4669,7 +4669,7 @@
             Sao.View.Form.Binary._super.set_readonly.call(this, readonly);
             var record = this.record;
             this.but_select.toggleClass('disabled', readonly || !record);
-            this.input_select.toggle(!readonly && Boolean(record));
+            this.input_select.sao_toggle(!readonly && Boolean(record));
             this.but_clear.prop('disabled', readonly || !record);
             if (this.text) {
                 this.text.prop('readonly', readonly);
@@ -4962,7 +4962,7 @@
         },
         set_url: function(value) {
             this.button.attr('href', value);
-            this.button.toggle(Boolean(value));
+            this.button.sao_toggle(Boolean(value));
         },
         set_invisible: function(invisible) {
             Sao.View.Form.URL._super.set_invisible.call(this, invisible);
@@ -5040,9 +5040,9 @@
             Sao.View.Form.HTML._super.set_readonly.call(this, readonly);
             this.el.find('button').prop('disabled', readonly || !this.record);
             if (readonly) {
-                this.el.find('a').hide();
+                this.el.find('a').sao_hide();
             } else {
-                this.el.find('a').show();
+                this.el.find('a').sao_show();
             }
         },
         translate_dialog: function(languages) {
diff -r 862b305c0d33 -r 23cedc854f49 sao/src/view/tree.js
--- a/sao/src/view/tree.js      Fri Mar 13 15:14:09 2026 +0100
+++ b/sao/src/view/tree.js      Fri Nov 21 16:09:28 2025 +0100
@@ -942,9 +942,9 @@
             expanded = expanded || this.get_expanded_paths();
 
             if (this.selection_mode == Sao.common.SELECTION_MULTIPLE) {
-                this.selection.show();
+                this.selection.sao_show();
             } else {
-                this.selection.hide();
+                this.selection.sao_hide();
             }
 
             const group_records = (group, root) => {
@@ -1054,7 +1054,7 @@
                         column.col.data('hidden-width', 
column.col.css('width'))
                     }
                     column.col.css('width', 0);
-                    column.col.hide();
+                    column.col.sao_hide();
                 } else if (!column.col.hasClass('draggable-handle') &&
                     !column.col.hasClass('optional') &&
                     !column.col.hasClass('selection-state') &&
@@ -1078,11 +1078,11 @@
                         width = `${width}em`;
                     }
                     min_width.push(width);
-                    column.col.show();
+                    column.col.sao_show();
                 }
             }
-            this.table.find('thead > tr > th .resizer').show();
-            this.table.find('thead > tr > th:visible:last .resizer').hide();
+            this.table.find('thead > tr > th .resizer').sao_show();
+            this.table.find('thead > tr > th:visible:last 
.resizer').sao_hide();
             if (this.children_field) {
                 this.columns.every(column => {
                     if (column.col.hasClass('draggable-handle') ||
@@ -1221,8 +1221,8 @@
                 }
             }
 
-            to_hide.addClass('invisible').hide();
-            to_show.removeClass('invisible').show();
+            to_hide.addClass('invisible').sao_hide();
+            to_show.removeClass('invisible').sao_show();
         },
         update_with_selection: function() {
             let selected_records = this.selected_records;
@@ -1824,11 +1824,11 @@
                     break;
                 case Sao.common.SELECTION_SINGLE:
                     this.selection.attr('type', 'radio');
-                    this.selection.show();
+                    this.selection.sao_show();
                     break;
                 case Sao.common.SELECTION_MULTIPLE:
                     this.selection.attr('type', 'checkbox');
-                    this.selection.show();
+                    this.selection.sao_show();
                     break;
             }
 
@@ -2260,11 +2260,11 @@
             this.tree.columns.forEach((col, idx) => {
                 var td = this._get_column_td(idx);
                 var static_el = this.get_static_el(td);
-                static_el.empty().append(col.render(this.record)).show();
+                static_el.empty().append(col.render(this.record)).sao_show();
                 this.get_editable_el(td)
                     .empty()
                     .data('widget', null)
-                    .hide()
+                    .sao_hide()
                     .parents('.treeview td').addBack().removeClass('edited');
             });
         },
@@ -2289,8 +2289,8 @@
                     widget.display(this.record, col.field);
 
                     var static_el = this.get_static_el(td);
-                    static_el.hide();
-                    editable_el.show();
+                    static_el.sao_hide();
+                    editable_el.sao_show();
                     editable_el.parents('.treeview td').addBack()
                         .addClass('edited');
 
@@ -2429,7 +2429,7 @@
                     }
                 } else if (event_.which == Sao.common.ESC_KEYCODE) {
                     this.tree.edit_row(null);
-                    this.get_static_el().show().find('[tabindex=0]').focus();
+                    
this.get_static_el().sao_show().find('[tabindex=0]').focus();
                 }
             } else {
                 widget.display(this.record, column.field);
@@ -2474,9 +2474,9 @@
                 field.set_state(record, ['invisible']);
                 var invisible = field.get_state_attrs(record).invisible;
                 if (invisible) {
-                    cell.hide();
+                    cell.sao_hide();
                 } else {
-                    cell.show();
+                    cell.sao_show();
                 }
                 if (this.protocol) {
                     value = field.get(record);
@@ -2526,7 +2526,7 @@
                         // clean previous color if the new one is not valid
                         img_tag.css('background-color', '');
                         img_tag.css('background-color', value);
-                        img_tag.toggle(Boolean(value));
+                        img_tag.sao_toggle(Boolean(value));
                     } else {
                         Sao.common.ICONFACTORY.get_icon_url(value)
                             .done(url => {
@@ -2593,7 +2593,7 @@
                 var invisible = field.get_state_attrs(record).invisible;
                 if (invisible) {
                     cell.text('');
-                    cell.hide();
+                    cell.sao_hide();
                     return;
                 }
                 var result = field.get_symbol(record, this.attributes.symbol);
@@ -2601,10 +2601,10 @@
                     position = result[1];
                 if (Math.round(position) === this.position) {
                     cell.text(symbol);
-                    cell.show();
+                    cell.sao_show();
                 } else {
                     cell.text('');
-                    cell.hide();
+                    cell.sao_hide();
                 }
             };
             if (!record.is_loaded(this.attributes.name)) {
@@ -2658,9 +2658,9 @@
                 this.field.set_state(record);
                 var state_attrs = this.field.get_state_attrs(record);
                 if (state_attrs.invisible) {
-                    cell.hide();
+                    cell.sao_hide();
                 } else {
-                    cell.show();
+                    cell.sao_show();
                 }
             };
             const render_error = () => {
@@ -2686,10 +2686,10 @@
             cells.push(this.header);
             for (const cell of cells) {
                 if (visible) {
-                    cell.show();
+                    cell.sao_show();
                     cell.removeClass('invisible');
                 } else {
-                    cell.hide();
+                    cell.sao_hide();
                     cell.addClass('invisible');
                 }
             }
@@ -3065,9 +3065,9 @@
                     });
             }
             if (!text) {
-                button.hide();
+                button.sao_hide();
             } else {
-                button.show();
+                button.sao_show();
             }
         },
         save_as: function(record) {
@@ -3149,9 +3149,9 @@
             this.field.set_state(record);
             var state_attrs = this.field.get_state_attrs(record);
             if (state_attrs.readonly) {
-                cell.hide();
+                cell.sao_hide();
             } else {
-                cell.show();
+                cell.sao_show();
             }
             return cell;
         }
@@ -3220,10 +3220,10 @@
             cells.push(this.header);
             for (const cell of cells) {
                 if (visible) {
-                    cell.show();
+                    cell.sao_show();
                     cell.removeClass('invisible');
                 } else {
-                    cell.hide();
+                    cell.sao_hide();
                     cell.addClass('invisible');
                 }
             }
@@ -3257,7 +3257,7 @@
     Sao.View.Tree.ButtonMultiple = Sao.class_(Sao.common.Button, {
         set_state: function(records) {
             if (!records.length) {
-                this.el.hide();
+                this.el.sao_hide();
                 this.el.prop('disabled', true);
                 this.set_icon(null);
                 return;
@@ -3275,9 +3275,9 @@
                 icons.add(r_states.icon || this.attributes.icon);
             }
             if (states.invisible) {
-                this.el.hide();
+                this.el.sao_hide();
             } else {
-                this.el.show();
+                this.el.sao_show();
             }
             this.el.prop('disabled', Boolean(states.readonly));
             if (icons.size == 1) {
@@ -3357,9 +3357,9 @@
         set_readonly: function(readonly) {
             Sao.View.EditableTree.URL._super.set_readonly.call(this, readonly);
             if (readonly) {
-                this.input.hide();
+                this.input.sao_hide();
             } else {
-                this.input.show();
+                this.input.sao_show();
             }
         },
     });
diff -r 862b305c0d33 -r 23cedc854f49 sao/src/window.js
--- a/sao/src/window.js Fri Mar 13 15:14:09 2026 +0100
+++ b/sao/src/window.js Fri Nov 21 16:09:28 2025 +0100
@@ -275,7 +275,7 @@
                 this.wid_text = jQuery('<input/>', {
                     type: 'input'
                 }).appendTo(menu);
-                this.wid_text.hide();
+                this.wid_text.sao_hide();
 
                 var buttons = jQuery('<div/>', {
                     'class': 'input-group-btn'
@@ -332,7 +332,7 @@
                 this.but_next.click(disable_during(this.next.bind(this)));
 
                 if (this.domain) {
-                    this.wid_text.show();
+                    this.wid_text.sao_show();
 
                     this.but_add = jQuery('<button/>', {
                         'class': 'btn btn-default btn-sm',

Reply via email to