1.20.x file.module | file_managed_file_process($element, &$form_state, $form) |
Render API callback: Expands the managed_file element type.
Expands the file type to include Upload and Remove buttons, as well as support for a default value.
This function is assigned as a #process callback in file_element_info().
File
- modules/
file/ file.module, line 1265 - Defines a "managed_file" Form API field and a "file" field for Field module.
Code
function file_managed_file_process($element, &$form_state, $form) {
$fid = isset($element['#value']['fid']) ? $element['#value']['fid'] : 0;
// Set some default element properties.
$element['#progress_indicator'] = empty($element['#progress_indicator']) ? 'none' : $element['#progress_indicator'];
$element['#file'] = $fid ? file_load($fid) : FALSE;
$element['#tree'] = TRUE;
// Token here is not generated with backdrop_token() as it does not need to
// be session-based.
$path = 'file/ajax/' . implode('/', $element['#array_parents']) . '/' . $form['form_build_id']['#value'];
$token = backdrop_hmac_base64($path, backdrop_get_private_key() . backdrop_get_hash_salt());
$path .= '/' . $token;
$ajax_settings = array(
'path' => $path,
'wrapper' => $element['#id'] . '-ajax-wrapper',
'effect' => 'none',
'progress' => array(
'type' => $element['#progress_indicator'],
'message' => $element['#progress_message'],
),
);
// Set up the buttons first since we need to check if they were clicked.
$element['upload_button'] = array(
'#name' => implode('_', $element['#parents']) . '_upload_button',
'#type' => 'submit',
'#value' => t('Upload'),
'#validate' => array(),
'#submit' => array('file_managed_file_submit'),
'#limit_validation_errors' => array($element['#parents']),
'#ajax' => $ajax_settings,
'#weight' => -5,
'#attributes' => array('class' => array('file-upload-button')),
);
// Force the progress indicator for the remove button to be either 'none' or
// 'throbber', even if the upload button is using something else.
$ajax_settings['progress']['type'] = ($element['#progress_indicator'] == 'none') ? 'none' : 'throbber';
$ajax_settings['progress']['message'] = NULL;
$element['remove_button'] = array(
'#name' => implode('_', $element['#parents']) . '_remove_button',
'#type' => 'submit',
'#value' => t('Remove'),
'#validate' => array(),
'#submit' => array('file_managed_file_submit'),
'#limit_validation_errors' => array($element['#parents']),
'#ajax' => $ajax_settings,
'#weight' => -5,
'#attributes' => array('class' => array('file-remove-button')),
);
// Add a button that will be used to select existing files if enabled.
$element['browse_button'] = array(
'#name' => implode('_', $element['#parents']) . '_browse_button',
'#type' => 'submit',
'#value' => t('Select existing file'),
'#validate' => array(),
'#submit' => array(),
'#limit_validation_errors' => array($element['#parents']),
'#ajax' => array(
'callback' => 'file_managed_file_browser_open',
'progress' => array(
'type' => 'throbber',
'message' => NULL,
),
),
'#weight' => -5,
'#attributes' => array('class' => array('file-browse-button')),
'#prefix' => '<span class="file-browse-text js-show"> ' . t('or') . ' ',
'#suffix' => '</span>',
'#access' => !empty($element['#browser_view']),
// Attaching the assets from the Filter module makes sure that the image
// browser works, even if no field on that form has a filter set.
'#attached' => array(
'library' => array(
array('filter', 'filter'),
),
),
);
$element['fid'] = array(
'#type' => 'hidden',
'#value' => $fid,
);
// Legacy server-side progress bar support. If not available, client-side
// upload progress will be used instead. Client-side support does not require
// a hidden field nor does it do AJAX requests to check on the progress,
// so no [#ajax][progress][path] is necessary.
// @todo: Remove in Backdrop 2.0.
if ($element['#progress_indicator'] == 'bar' && $implementation = file_progress_implementation()) {
$upload_progress_key = mt_rand();
if ($implementation == 'uploadprogress') {
$element['UPLOAD_IDENTIFIER'] = array(
'#type' => 'hidden',
'#value' => $upload_progress_key,
'#attributes' => array('class' => array('file-progress')),
// Uploadprogress extension requires this field to be at the top of the
// form.
'#weight' => -20,
);
}
elseif ($implementation == 'apc') {
$element['APC_UPLOAD_PROGRESS'] = array(
'#type' => 'hidden',
'#value' => $upload_progress_key,
'#attributes' => array('class' => array('file-progress')),
// Uploadprogress extension requires this field to be at the top of the
// form.
'#weight' => -20,
);
}
// Add the upload progress callback.
if ($implementation !== 'client') {
$element['upload_button']['#ajax']['progress']['path'] = 'file/progress/' . $upload_progress_key;
}
}
// The file upload field itself.
$element['upload'] = array(
'#name' => 'files[' . implode('_', $element['#parents']) . ']',
'#type' => 'file',
'#title' => t('Choose a file'),
'#title_display' => 'invisible',
'#size' => $element['#size'],
'#theme_wrappers' => array(),
'#weight' => -10,
);
if ($fid && $element['#file']) {
$element['filename'] = array(
'#type' => 'markup',
'#markup' => theme('file_link', array('file' => $element['#file'])) . ' ',
'#weight' => -10,
);
// Anonymous users who have uploaded a temporary file need a
// non-session-based token added so file_managed_file_value() can check
// that they have permission to use this file on subsequent submissions of
// the same form (for example, after an Ajax upload or form validation
// error).
if (!$GLOBALS['user']->uid && $element['#file']->status != FILE_STATUS_PERMANENT) {
$element['fid_token'] = array(
'#type' => 'hidden',
'#value' => backdrop_hmac_base64('file-' . $fid, backdrop_get_private_key() . backdrop_get_hash_salt()),
);
}
}
// Enable auto-uploading unless requested otherwise.
if (!isset($element['#auto_upload']) || $element['##auto_upload']) {
$element['upload']['#attributes']['data-file-auto-upload'] = '1';
}
// Add client-side validation of file extensions.
if (isset($element['#upload_validators']['file_validate_extensions'][0])) {
$extension_array = array_filter(explode(' ', $element['#upload_validators']['file_validate_extensions'][0]));
$extension_string = implode(',', $extension_array);
$element['upload']['#attributes']['data-file-extensions'] = $extension_string;
// Add support for mobile camera uploads if jpg is a valid extension.
// Browser support for HTML5 extension validation is still weak at this
// point, add more extensive extension support in the future.
if (in_array('jpg', $extension_array)) {
$element['upload']['#attributes']['accept'] = '*/*,capture=camera';
}
}
// Prefix and suffix used for Ajax replacement.
$element['#prefix'] = '<div id="' . $element['#id'] . '-ajax-wrapper">';
$element['#suffix'] = '</div>';
return $element;
}