public static function getScript()
{
$_aParams = func_get_args() + array(null);
$_oMsg = $_aParams[0];
$sCannotAddMore = $_oMsg->get('allowed_maximum_number_of_fields');
$sCannotRemoveMore = $_oMsg->get('allowed_minimum_number_of_fields');
return <<<JAVASCRIPTS
(function ( \$ ) {
/**
* Bind field-repeating events to repeatable buttons for individual fields.
* @remark This method can be called from a fields container or a cloned field container.
*/
\$.fn.updateAdminPageFrameworkRepeatableFields = function( aSettings ) {
var nodeThis = this;
var _sFieldsContainerID = nodeThis.find( '.repeatable-field-add-button' ).first().data( 'id' );
/* Store the fields specific options in an array */
if ( ! \$.fn.aAdminPageFrameworkRepeatableFieldsOptions ) {
\$.fn.aAdminPageFrameworkRepeatableFieldsOptions = [];
}
if ( ! \$.fn.aAdminPageFrameworkRepeatableFieldsOptions.hasOwnProperty( _sFieldsContainerID ) ) {
\$.fn.aAdminPageFrameworkRepeatableFieldsOptions[ _sFieldsContainerID ] = \$.extend({
max: 0, // These are the defaults.
min: 0,
fadein: 500,
fadeout: 500,
}, aSettings );
}
var _aOptions = \$.fn.aAdminPageFrameworkRepeatableFieldsOptions[ _sFieldsContainerID ];
/* Set the option values in the data attributes so that when a section is repeated and creates a brand new field container, it can refer to the options */
// @todo For nested fields, the `find()` method should be avoided.
\$( nodeThis ).find( '.admin-page-framework-repeatable-field-buttons' ).attr( 'data-max', _aOptions[ 'max' ] );
\$( nodeThis ).find( '.admin-page-framework-repeatable-field-buttons' ).attr( 'data-min', _aOptions[ 'min' ] );
\$( nodeThis ).find( '.admin-page-framework-repeatable-field-buttons' ).attr( 'data-fadein', _aOptions[ 'fadein' ] );
\$( nodeThis ).find( '.admin-page-framework-repeatable-field-buttons' ).attr( 'data-fadeout', _aOptions[ 'fadeout' ] );
/* The Add button behavior - if the tag id is given, multiple buttons will be selected.
* Otherwise, a field node is given and a single button will be selected. */
// @todo For nested fields, the `find()` method should be avoided.
\$( nodeThis ).find( '.repeatable-field-add-button' ).unbind( 'click' );
\$( nodeThis ).find( '.repeatable-field-add-button' ).click( function() {
\$( this ).addAdminPageFrameworkRepeatableField();
return false; // will not click after that
});
/* The Remove button behavior */
// @todo For nested fields, the `find()` method should be avoided.
\$( nodeThis ).find( '.repeatable-field-remove-button' ).unbind( 'click' );
\$( nodeThis ).find( '.repeatable-field-remove-button' ).click( function() {
\$( this ).removeAdminPageFrameworkRepeatableField();
return false; // will not click after that
});
/* If the number of fields is less than the set minimum value, add fields. */
var _sFieldID = nodeThis.find( '.repeatable-field-add-button' ).first().closest( '.admin-page-framework-field' ).attr( 'id' );
var _nCurrentFieldCount = jQuery( '#' + _sFieldsContainerID ).find( '.admin-page-framework-field' ).length;
if ( _aOptions[ 'min' ] > 0 && _nCurrentFieldCount > 0 ) {
if ( ( _aOptions[ 'min' ] - _nCurrentFieldCount ) > 0 ) {
\$( '#' + _sFieldID ).addAdminPageFrameworkRepeatableField( _sFieldID );
}
}
};
/**
* Adds a repeatable field.
*
* This method is called when the user presses the + repeatable button.
*/
\$.fn.addAdminPageFrameworkRepeatableField = function( sFieldContainerID ) {
if ( 'undefined' === typeof sFieldContainerID ) {
var sFieldContainerID = \$( this ).closest( '.admin-page-framework-field' ).attr( 'id' );
}
var nodeFieldContainer = \$( '#' + sFieldContainerID );
var nodeNewField = nodeFieldContainer.clone(); // clone without bind events.
var nodeFieldsContainer = nodeFieldContainer.closest( '.admin-page-framework-fields' );
var _sFieldsContainerID = nodeFieldsContainer.attr( 'id' );
// If the set maximum number of fields already exists, do not add.
if ( ! \$.fn.aAdminPageFrameworkRepeatableFieldsOptions.hasOwnProperty( _sFieldsContainerID ) ) {
var nodeButtonContainer = nodeFieldContainer.find( '.admin-page-framework-repeatable-field-buttons' );
\$.fn.aAdminPageFrameworkRepeatableFieldsOptions[ _sFieldsContainerID ] = {
max: nodeButtonContainer.attr( 'data-max' ), // These are the defaults.
min: nodeButtonContainer.attr( 'data-min' ),
fadein: nodeButtonContainer.attr( 'data-fadein' ),
fadeout: nodeButtonContainer.attr( 'data-fadeout' ),
};
}
var _iFadein = \$.fn.aAdminPageFrameworkRepeatableFieldsOptions[ _sFieldsContainerID ][ 'fadein' ];
var _iFadeout = \$.fn.aAdminPageFrameworkRepeatableFieldsOptions[ _sFieldsContainerID ][ 'fadeout' ];
// Show a warning message if the user tries to add more fields than the number of allowed fields.
var sMaxNumberOfFields = \$.fn.aAdminPageFrameworkRepeatableFieldsOptions[ _sFieldsContainerID ]['max'];
if ( sMaxNumberOfFields != 0 && nodeFieldsContainer.find( '.admin-page-framework-field' ).length >= sMaxNumberOfFields ) {
var nodeLastRepeaterButtons = nodeFieldContainer.find( '.admin-page-framework-repeatable-field-buttons' ).last();
var sMessage = \$( this ).formatPrintText( '{$sCannotAddMore}', sMaxNumberOfFields );
var nodeMessage = \$( '<span class=\\"repeatable-error repeatable-field-error\\" id=\\"repeatable-error-' + _sFieldsContainerID + '\\" >' + sMessage + '</span>' );
if ( nodeFieldsContainer.find( '#repeatable-error-' + _sFieldsContainerID ).length > 0 ) {
nodeFieldsContainer.find( '#repeatable-error-' + _sFieldsContainerID ).replaceWith( nodeMessage );
} else {
nodeLastRepeaterButtons.before( nodeMessage );
}
nodeMessage.delay( 2000 ).fadeOut( _iFadeout );
return;
}
// Empty values.
nodeNewField.find( 'input:not([type=radio], [type=checkbox], [type=submit], [type=hidden]),textarea' ).val( '' ); // empty the value
nodeNewField.find( 'input[type=checkbox]' ).prop( 'checked', false ); // uncheck checkboxes.
nodeNewField.find( '.repeatable-error' ).remove(); // remove error messages.
// Add the cloned new field element.
if ( _iFadein ) {
nodeNewField
.hide()
.insertAfter( nodeFieldContainer )
.delay( 100 )
.fadeIn( _iFadein );
} else {
nodeNewField.insertAfter( nodeFieldContainer );
}
// 3.6.0+ Increment name and id attributes of the newly cloned field.
_incrementFieldAttributes( nodeNewField, nodeFieldsContainer );
/**
* Rebind the click event to the + and - buttons - important to update AFTER inserting the clone to the document node since the update method needs to count the fields.
* Also do this after updating the attributes since the script needs to check the last added id for repeatable field options such as 'min'.
*/
nodeNewField.updateAdminPageFrameworkRepeatableFields();
// It seems radio buttons of the original field need to be reassigned. Otherwise, the checked items will be gone.
nodeFieldContainer.find( 'input[type=radio][checked=checked]' ).prop( 'checked', 'checked' );
// Call back the registered functions.
// @deprecated 3.8.8 Kept for backward compatibility as some custom field types rely on this method.
nodeNewField.trigger(
'admin-page-framework_added_repeatable_field',
[
nodeNewField.data( 'type' ), // field type slug
nodeNewField.attr( 'id' ), // element tag id
0, // call type // call type, 0 : repeatable fields, 1: repeatable sections, 2: nested repeatable fields.
0, // section index - @todo find the section index
0 // field index - @todo find the field index
]
);
// 3.8.8+ _nested and inline_mixed field types have nested fields. The above
\$( nodeNewField ).find( '.admin-page-framework-field' ).addBack().trigger(
'admin-page-framework_repeated_field',
[
0, // call type, 0 : repeatable fields, 1: repeatable sections
jQuery( nodeNewField ).closest( '.admin-page-framework-fields' ) // model container
]
);
// If more than one fields are created, show the Remove button.
// @todo find() may not be appropriate for nested fields.
var nodeRemoveButtons = nodeFieldsContainer.find( '.repeatable-field-remove-button' );
if ( nodeRemoveButtons.length > 1 ) {
nodeRemoveButtons.css( 'visibility', 'visible' );
}
// Display/hide delimiters.
nodeFieldsContainer.children( '.admin-page-framework-field' ).children( '.delimiter' ).show().last().hide();
// Return the newly created element. The media uploader needs this
return nodeNewField;
};
/**
* Increments digits in field attributes.
* @since 3.8.0
*/
var _incrementFieldAttributes = function( oElement, oFieldsContainer ) {
var _iFieldCount = Number( oFieldsContainer.attr( 'data-largest_index' ) );
var _iIncrementedFieldCount = _iFieldCount + 1;
oFieldsContainer.attr( 'data-largest_index', _iIncrementedFieldCount );
var _sFieldTagIDModel = oFieldsContainer.attr( 'data-field_tag_id_model' );
var _sFieldNameModel = oFieldsContainer.attr( 'data-field_name_model' );
var _sFieldFlatNameModel = oFieldsContainer.attr( 'data-field_name_flat_model' );
var _sFieldAddressModel = oFieldsContainer.attr( 'data-field_address_model' );
oElement.incrementAttribute(
'id', // attribute name
_iFieldCount, // increment from
_sFieldTagIDModel // digit model
);
oElement.find( 'label' ).incrementAttribute(
'for', // attribute name
_iFieldCount, // increment from
_sFieldTagIDModel // digit model
);
oElement.find( 'input,textarea,select' ).incrementAttribute(
'id', // attribute name
_iFieldCount, // increment from
_sFieldTagIDModel // digit model
);
oElement.find( 'input,textarea,select' ).incrementAttribute(
'name', // attribute name
_iFieldCount, // increment from
_sFieldNameModel // digit model
);
// Update the hidden input elements that contain field names for nested elements.
oElement.find( 'input[type=hidden].element-address' ).incrementAttributes(
[ 'name', 'value', 'data-field_address_model' ], // attribute names - these elements contain id values in the 'name' attribute.
_iFieldCount,
_sFieldAddressModel // digit model - this is
);
// For checkbox, select, and radio input types
oElement.find( 'input[type=radio][data-id],input[type=checkbox][data-id],select[data-id]' ).incrementAttribute(
'data-id', // attribute name
_iFieldCount, // increment from
_sFieldTagIDModel // digit model
);
// 3.8 For nested repeatable fields
oElement.find( '.admin-page-framework-field,.admin-page-framework-fields,.admin-page-framework-fieldset' ).incrementAttributes(
[ 'id', 'data-field_tag_id_model', 'data-field_id' ],
_iFieldCount,
_sFieldTagIDModel
);
oElement.find( '.admin-page-framework-fields' ).incrementAttributes(
[ 'data-field_name_model' ],
_iFieldCount,
_sFieldNameModel
);
oElement.find( '.admin-page-framework-fields' ).incrementAttributes(
[ 'data-field_name_flat', 'data-field_name_flat_model' ],
_iFieldCount,
_sFieldFlatNameModel
);
oElement.find( '.admin-page-framework-fields' ).incrementAttributes(
[ 'data-field_address', 'data-field_address_model' ],
_iFieldCount,
_sFieldAddressModel
);
}
/**
* Removes a repeatable field.
This method is called when the user presses the - repeatable button.
*/
\$.fn.removeAdminPageFrameworkRepeatableField = function() {
/* Need to remove the element: the field container */
var nodeFieldContainer = \$( this ).closest( '.admin-page-framework-field' );
var nodeFieldsContainer = \$( this ).closest( '.admin-page-framework-fields' );
var _sFieldsContainerID = nodeFieldsContainer.attr( 'id' );
/* If the set minimum number of fields already exists, do not remove */
var sMinNumberOfFields = \$.fn.aAdminPageFrameworkRepeatableFieldsOptions[ _sFieldsContainerID ][ 'min' ];
if ( sMinNumberOfFields != 0 && nodeFieldsContainer.find( '.admin-page-framework-field' ).length <= sMinNumberOfFields ) {
var nodeLastRepeaterButtons = nodeFieldContainer.find( '.admin-page-framework-repeatable-field-buttons' ).last();
var sMessage = \$( this ).formatPrintText( '{$sCannotRemoveMore}', sMinNumberOfFields );
var nodeMessage = \$( '<span class=\\"repeatable-error repeatable-field-error\\" id=\\"repeatable-error-' + _sFieldsContainerID + '\\">' + sMessage + '</span>' );
if ( nodeFieldsContainer.find( '#repeatable-error-' + _sFieldsContainerID ).length > 0 ) {
nodeFieldsContainer.find( '#repeatable-error-' + _sFieldsContainerID ).replaceWith( nodeMessage );
} else {
nodeLastRepeaterButtons.before( nodeMessage );
}
var _iFadeout = \$.fn.aAdminPageFrameworkRepeatableFieldsOptions[ _sFieldsContainerID ][ 'fadeout' ]
? \$.fn.aAdminPageFrameworkRepeatableFieldsOptions[ _sFieldsContainerID ][ 'fadeout' ]
: 500;
nodeMessage.delay( 2000 ).fadeOut( _iFadeout );
return;
}
/* Remove the field */
var _iFadeout = \$.fn.aAdminPageFrameworkRepeatableFieldsOptions[ _sFieldsContainerID ][ 'fadeout' ]
? \$.fn.aAdminPageFrameworkRepeatableFieldsOptions[ _sFieldsContainerID ][ 'fadeout' ]
: 500;
nodeFieldContainer.fadeOut( _iFadeout, function() {
\$( this ).remove();
var nodeRemoveButtons = nodeFieldsContainer.find( '.repeatable-field-remove-button' );
if ( 1 === nodeRemoveButtons.length ) {
nodeRemoveButtons.css( 'visibility', 'hidden' );
}
} );
};
}( jQuery ));
JAVASCRIPTS;
}