Skip to content

Commit 158cd10

Browse files
authored
Merge pull request #828 from alleyinteractive/hotfix/displayif-performance
Fix performance regression in fm_renumber
2 parents f5cc00c + ec77ea3 commit 158cd10

File tree

1 file changed

+49
-20
lines changed

1 file changed

+49
-20
lines changed

js/fieldmanager.js

Lines changed: 49 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -70,32 +70,59 @@ var init_label_macros = function() {
7070
} );
7171
}
7272

73-
var fm_renumber = function( $wrappers ) {
73+
/**
74+
* Renumber all fields within one or more wrappers based on their sequential
75+
* position in the DOM.
76+
*
77+
* When fields/groups are added, removed, or rearranged, impacted fields' names
78+
* need to be adjusted. For instance, if a field's name is group[1][field][2]
79+
* and that group is moved to the top of the list, the field's name needs to be
80+
* adjusted to group[0][field][2] or else the new position will not be saved
81+
* when the data is posted to the server.
82+
*
83+
* @param {jQuery} $wrappers - Wrapping containers of items that need to be
84+
* renumbered.
85+
*/
86+
var fm_renumber = function( $wrappers ) {
7487
var fmtemp = parseInt( Math.random() * 100000, 10 );
7588
$wrappers.each( function() {
7689
var level_pos = $( this ).data( 'fm-array-position' ) - 0;
7790
var order = 0;
91+
var modified_elements = [];
7892
if ( level_pos > 0 ) {
7993
$( this ).find( '> .fm-item' ).each( function() {
94+
// Do not manipulate prototypes (templates).
8095
if ( $( this ).hasClass( 'fmjs-proto' ) ) {
81-
return; // continue
96+
return; // continue;
8297
}
98+
99+
// TODO: nested fields get iterated over multiple times, is this avoidable?
83100
$( this ).find( '.fm-element, .fm-incrementable' ).each( function() {
84-
var fname = $(this).attr( 'name' );
101+
var $element = $( this );
102+
var fname = $element.attr( 'name' );
103+
85104
if ( fname ) {
86-
fname = fname.replace( /\]/g, '' );
87-
parts = fname.split( '[' );
88-
if ( parts[ level_pos ] != order ) {
105+
parts = fname.replace( /\]/g, '' ).split( '[' );
106+
if ( Number.parseInt(parts[ level_pos ], 10) !== order ) {
89107
parts[ level_pos ] = order;
90108
var new_fname = parts[ 0 ] + '[' + parts.slice( 1 ).join( '][' ) + ']';
109+
110+
// If the name hasn't updated, skip unnecessary DOM updates.
111+
if ( new_fname === fname ) {
112+
return; // continue;
113+
}
114+
91115
// Rename the field and add a temporary prefix to prevent name collisions.
92-
$( this ).attr( 'name', 'fmtemp_' + ( ++fmtemp ).toString() + '_' + new_fname );
93-
if ( $( this ).attr( 'id' ) && $( this ).attr( 'id' ).match( '-proto' ) && ! new_fname.match( 'proto' ) ) {
94-
$( this ).attr( 'id', 'fm-edit-dynamic-' + dynamic_seq );
95-
if ( $( this ).parent().hasClass( 'fm-option' ) ) {
96-
$( this ).parent().find( 'label' ).attr( 'for', 'fm-edit-dynamic-' + dynamic_seq );
116+
$element.attr( 'name', 'fmtemp_' + ( ++fmtemp ).toString() + '_' + new_fname );
117+
modified_elements.push( $element );
118+
119+
// If this field is newly generated from a prototype, update [id]s and [for]s.
120+
if ( $element.attr( 'id' ) && $element.attr( 'id' ).match( '-proto' ) && ! new_fname.match( 'proto' ) ) {
121+
$element.attr( 'id', 'fm-edit-dynamic-' + dynamic_seq );
122+
if ( $element.parent().hasClass( 'fm-option' ) ) {
123+
$element.parent().find( 'label' ).attr( 'for', 'fm-edit-dynamic-' + dynamic_seq );
97124
} else {
98-
var parent = $( this ).closest( '.fm-item' );
125+
var parent = $element.closest( '.fm-item' );
99126
if ( parent.length && parent.find( '.fm-label label' ).length ) {
100127
parent.find( '.fm-label label' ).attr( 'for', 'fm-edit-dynamic-' + dynamic_seq );
101128
}
@@ -105,22 +132,24 @@ var fm_renumber = function( $wrappers ) {
105132
}
106133
}
107134
}
108-
if ( $( this ).hasClass( 'fm-incrementable' ) ) {
109-
$( this ).attr( 'id', 'fm-edit-dynamic-' + dynamic_seq );
135+
if ( $element.hasClass( 'fm-incrementable' ) ) {
136+
$element.attr( 'id', 'fm-edit-dynamic-' + dynamic_seq );
110137
dynamic_seq++;
111138
}
112139
} );
113140
order++;
114141
} );
115142
}
116-
$( this ).find( '.fm-wrapper' ).each( function() {
117-
fm_renumber( $( this ) );
118-
} );
143+
144+
// Iterate over subgroups.
145+
fm_renumber( $( this ).find( '.fm-wrapper' ) );
119146

120147
// Remove temporary name prefix in renumbered fields.
121-
$( '.fm-element[name^="fmtemp_"], .fm-incrementable[name^="fmtemp_"]' ).each( function() {
122-
$( this ).attr( 'name', $( this ).attr( 'name' ).replace( /^fmtemp_\d+_/, '' ) );
123-
} );
148+
if ( modified_elements.length ) {
149+
$.each( modified_elements, function( index, $element ) {
150+
$element.attr( 'name', $element.attr( 'name' ).replace( /^fmtemp_\d+_/, '' ) );
151+
} );
152+
}
124153
} );
125154
}
126155

0 commit comments

Comments
 (0)