Newer
Older
<?php
// $Id$
/**
* @file
* Defines a file field type.
*
* Uses content.module to store the fid, and Drupal's {files} table
* to store the actual file data.
include_once(drupal_get_path('module', 'filefield') .'/field_file.inc');
/**
* Implementation of hook_menu().
*/
function filefield_menu() {
$items = array();
$items['filefield/js/upload/%/%/%'] = array(
'page callback' => 'filefield_js',
'page arguments' => array(3, 4, 5, 'filefield_file_upload_js'),
'access arguments' => array('view content'),
'type' => MENU_CALLBACK,
);
$items['filefield/js/delete/%/%/%'] = array(
'page callback' => 'filefield_js',
'page arguments' => array(3, 4, 5, 'filefield_file_edit_delete_js'),
'access arguments' => array('view content'),
'type' => MENU_CALLBACK,
);
return $items;
}
* Implementation of hook_perm().
function filefield_perm() {
return array('view filefield uploads');
}
/**
* Implementation of hook_elements().
*/
function filefield_elements() {
$elements = array();
$elements['filefield_file_upload'] = array(
'#input' => TRUE,
'#process' => array('filefield_file_upload_process'),
'#value_callback' => 'filefield_file_upload_value',
'#replaced_file' => NULL,
);
$elements['filefield_file_edit'] = array(
'#input' => TRUE,
'#process' => array('filefield_file_edit_process'),
'#value_callback' => 'filefield_file_edit_value',
);
$elements['filefield_generic_edit'] = array(
'#input' => TRUE,
'#process' => array('filefield_generic_edit_process'),
);
return $elements;
}
/**
* Implementation of hook_theme().
*/
function filefield_theme() {
return array(
'filefield_container_item' => array(
'arguments' => array('element' => NULL),
),
'filefield_file_upload' => array(
'arguments' => array('element' => NULL),
),
'filefield_file_edit' => array(
'arguments' => array('element' => NULL),
),
'filefield_generic_edit' => array(
'arguments' => array('element' => NULL),
),
'filefield_formatter_default' => array(
'arguments' => array('element' => NULL),
),
'filefield' => array(
'arguments' => array('file' => NULL),
),
'filefield_icon' => array(
'arguments' => array('file' => NULL),
),
);
/**
* Implementation of hook_field_info().
*/
function filefield_field_info() {
return array(
'file' => array(
'label' => 'File',
'description' => t('Store an arbitrary file.'),
),
);
}
/**
* Implementation of hook_field_settings().
*/
function filefield_field_settings($op, $field) {
switch ($op) {
case 'form':
$form = array();
$form['force_list'] = array(
'#type' => 'checkbox',
'#title' => t('Always list files'),
'#default_value' => isset($field['force_list']) ? $field['force_list'] : 0,
'#description' => t('If enabled, the "List" checkbox will be hidden and files are always shown. Otherwise, the user can choose for each file whether it should be listed or not.'),
);
return $form;
case 'save':
return array('force_list');
case 'database columns':
$columns = array(
'fid' => array('type' => 'int', 'not null' => FALSE),
'description' => array('type' => 'varchar', 'length' => 255, 'not null' => FALSE, 'sortable' => TRUE),
'list' => array('type' => 'int', 'size' => 'tiny', 'not null' => FALSE),
);
return $columns;
case 'views data':
$data = content_views_field_views_data($field);
$db_info = content_database_info($field);
$table_alias = content_views_tablename($field);
// By defining the relationship, we already have a "Has file" filter
// plus all the filters that Views already provides for files.
// No need for having a filter by ourselves.
unset($data[$table_alias][$field['field_name'] .'_fid']['filter']);
// Add a relationship for related file.
$data[$table_alias][$field['field_name'] .'_fid']['relationship'] = array(
'base' => 'files',
'field' => $db_info['columns']['fid']['column'],
'handler' => 'views_handler_relationship',
);
return $data;
}
}
/**
* Implementation of hook_content_is_empty().
*
* The result of this determines whether content.module will save
* the value of the field.
function filefield_content_is_empty($item, $field) {
if (empty($item['fid'])) {
return TRUE;
return FALSE;
}
/**
* Implementation of hook_field().
*/
function filefield_field($op, $node, $field, &$items, $teaser, $page) {
$field_name = $field['field_name'];
switch ($op) {
// Called after content.module loads default data.
case 'load':
if (empty($items)) {
return array();
}
foreach ($items as $delta => $item) {
// Despite hook_content_is_empty(), CCK still doesn't filter out
// empty items from $op = 'load', so we need to do that ourselves.
if (empty($item['fid']) || !($file = field_file_load($item['fid']))) {
unset($items[$delta]);
}
else {
$items[$delta] = array_merge($item, $file);
Darrel O'Pry
committed
}
$items = array_values($items); // compact deltas
return array($field_name => $items);
case 'insert':
case 'update':
foreach ($items as $delta => $item) {
$items[$delta] = field_file_save($node, $item);
// Remove items from the array if they have been deleted.
if (empty($items[$delta])) {
unset($items[$delta]);
}
$items = array_values($items); // compact deltas
case 'presave':
// Extract previous (permanent) files from the items array that have been
// deleted or replaced, so that insert/update can remove them properly.
foreach ($items as $delta => $item) {
if (!empty($item['replaced_file'])) {
$items[] = $item['replaced_file'];
}
}
case 'delete revision':
foreach ($items as $delta => $item) {
if (field_file_delete($item)) {
$items[$delta] = array();
}
}
$items = array_values($items); // compact deltas
break;
case 'delete':
foreach ($items as $delta => $item) {
field_file_delete($item);
}
break;
case 'sanitize':
foreach ($items as $delta => $item) {
// Cleanup $items during node preview.
if (empty($item['fid']) || !empty($item['delete'])) {
unset($items[$delta]);
}
else {
// Load the complete file if a filepath is not available.
if (!empty($item['fid']) && empty($item['filepath'])) {
$items[$delta] = array_merge($item, field_file_load($item['fid']));
}
// Add nid so formatters can create a link to the node.
$items[$delta]['nid'] = $node->nid;
}
}
break;
}
}
/**
* Implementation of hook_widget_info().
*/
function filefield_widget_info() {
return array(
'filefield_combo' => array(
'label' => 'File',
'field types' => array('file'),
'multiple values' => CONTENT_HANDLE_CORE,
'callbacks' => array('default value' => CONTENT_CALLBACK_CUSTOM),
),
);
}
Jakob Petsovits
committed
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
/**
* Implementation of hook_widget_settings().
*/
function filefield_widget_settings($op, $widget) {
switch ($op) {
case 'form':
$form = array();
$form['file_extensions'] = array (
'#type' => 'textfield',
'#title' => t('Permitted upload file extensions'),
'#default_value' => is_string($widget['file_extensions']) ? $widget['file_extensions'] : 'txt',
'#size' => 64,
'#description' => t('Extensions a user can upload to this field. Separate extensions with a space and do not include the leading dot. Leaving this blank will allow users to upload a file with any extension.'),
);
$form['file_path'] = array(
'#type' => 'textfield',
'#title' => t('File path'),
'#default_value' => is_string($widget['file_path']) ? $widget['file_path'] : '',
'#description' => t('Optional subdirectory within the "%dir" directory where files will be stored. Do not include trailing slash.', array('%dir' => variable_get('file_directory_path', 'files'))),
'#element_validate' => array('_filefield_widget_settings_file_path_validate'),
);
if (module_exists('token')) {
$form['file_path']['#suffix'] = theme('token_help', 'user');
}
// Let extension modules add their settings to the form.
foreach (module_implements('filefield_widget_settings') as $module) {
$function = $module .'_filefield_widget_settings';
$function('form_alter', $widget, $form);
}
return $form;
case 'validate':
module_invoke_all('filefield_widget_settings', $op, $widget, NULL);
break;
case 'save':
$core_settings = array('file_extensions', 'file_path');
$additional_settings = module_invoke_all(
'filefield_widget_settings', $op, $widget, NULL
);
return array_merge($core_settings, $additional_settings);
}
}
function _filefield_widget_settings_file_path_validate($element, &$form_state) {
// Strip slashes from the beginning and end of $widget['file_path']
$form_state['values']['file_path'] = trim($form_state['values']['file_path'], '\\/');
}
/**
* Implementation of hook_widget().
*/
function filefield_widget(&$form, &$form_state, $field, $items, $delta = 0) {
drupal_add_css(drupal_get_path('module', 'filefield') .'/filefield.css');
if (!$file = field_file_load($items[$delta]['fid'])) {
return filefield_file_upload_form($form, $form_state, $field, $delta, $items[$delta]);
$file = array_merge($items[$delta], $file);
return filefield_file_edit_form($form, $form_state, $field, $delta, $file);
Jakob Petsovits
committed
/**
* Render either an upload or edit container item so that the children elements
* always appear inside a nice table, whatever $field['multiple'] might be.
*/
function theme_filefield_container_item($element) {
$field = $element['#field'];
$children = !empty($element['#children']) ? $element['#children'] : '';
// CCK renders a nice table for multiple-value fields, that's just fine as is.
if ($field['multiple']) {
return theme('form_element', $element, $children);
}
// If the field is single-value, we still want to have a table, for the looks.
$header = array();
$rows = array(array($children));
$attributes = array('class' => 'filefield-file-container-table');
$table = theme('table', $header, $rows, $attributes);
return theme('form_element', $element, $table);
}
/**
* The filefield widget for not (yet) existing files.
*/
function filefield_file_upload_form(&$form, &$form_state, $field, $delta, $item = NULL) {
$form['#attributes']['enctype'] = 'multipart/form-data';
//drupal_add_js('misc/progress.js');
//drupal_add_js('misc/upload.js');
//drupal_add_js(drupal_get_path('module', 'filefield') .'/filefield.js');
$id = 'filefield-'. $field_name_css .'-'. $delta .'-form';
$replaced_file = (isset($item) && isset($item['replaced_file']))
? $item['replaced_file'] : NULL;
$widget = array(
'#type' => 'filefield_file_upload',
'#field' => $field,
'#delta' => $delta,
'#replaced_file' => $replaced_file,
'#prefix' => '<div id="'. $id .'" class="filefield-file-form"><div class="filefield-file-upload">',
'#suffix' => '</div></div>',
);
// Buttons inside custom form elements are not registered by the Forms API,
// so we make the "Upload" button a regular child element and not a part
// of the filefield_file_upload widget.
$widget[$field['field_name'] .'_'. $delta .'_upload'] = array(
'#type' => 'submit',
'#value' => t('Upload'),
'#submit' => array('filefield_file_upload_submit'), // without JavaScript
'#ahah' => array( // with JavaScript
'path' => 'filefield/js/upload/'. $field['field_name'] .'/'. $field['type_name'] .'/'. $delta,
'wrapper' => $id,
'method' => 'replace',
'effect' => 'fade',
),
'#weight' => 10,
'#field' => $field,
'#delta' => $delta,
);
return $widget;
}
/**
* The 'process' callback for 'filefield_file_upload' form elements.
* Called after defining the form and while building it, transforms the
* barebone element array into a file selection widget.
*/
function filefield_file_upload_process($element, $edit, &$form_state, $form) {
$field = $element['#field'];
$field_name = $field['field_name'];
// Construct the upload description out of user supplied text,
// maximum upload file size, and (optionally) allowed extensions.
$upload_description = t('Maximum file size: !size.', array(
'!size' => format_size(file_upload_max_size()),
));
if (!empty($field['widget']['file_extensions'])) {
$upload_description .= ' ' . t('Allowed extensions: %ext.', array(
'%ext' => $field['widget']['file_extensions'],
$element[$field_name .'_'. $element['#delta']] = array(
'#type' => 'file',
'#description' => $upload_description,
'#attributes' => array(
'class' => 'filefield filefield-'. $field_name,
'accept' => str_replace(' ', '|', trim($field['widget']['file_extensions']))
),
'#weight' => -1,
// Emulate how FAPI normalizes the _FILES array since this won't go through form_builder
'#name' => 'files['. $field_name .'_'. $element['#delta'] .']',
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
return $element;
}
/**
* Theme function for the file upload container element.
*/
function theme_filefield_file_upload($element) {
return theme('filefield_container_item', $element);
}
/**
* Value callback for 'filefield_upload' form elements.
* Uploads and validates a file if one has been specified,
* and returns the fid of that file as result value.
*/
function filefield_file_upload_value($element, $edit = FALSE) {
return empty($element['#value'])
? array('fid' => 0, 'replaced_file' => $element['#replaced_file'])
: $element['#value'];
}
/**
* Submit callback for the "Upload" button next to each file upload field.
*/
function filefield_file_upload_submit($form, &$form_state) {
$field = $form_state['clicked_button']['#field'];
$delta = $form_state['clicked_button']['#delta'];
filefield_file_upload($form_state, $field, $delta);
// Rebuild the form with the new uploaded-file state (hopefully).
node_form_submit_build_node($form, $form_state);
}
/**
* Form callback for the "Upload" button with JavaScript enabled,
* invoked by filefield_js().
*/
function filefield_file_upload_js(&$form, &$form_state, $field, $delta) {
// Upload the file retrieve the replacement form element, an edit form.
$file = filefield_file_upload($form_state, $field, $delta);
if (empty($file['fid'])) {
return filefield_file_upload_form($form, $form_state, $field, $delta, $file);
}
return filefield_file_edit_form($form, $form_state, $field, $delta, $file);
}
function filefield_file_upload(&$form_state, $field, $delta) {
$field_name = $field['field_name'];
$file = &$form_state['values'][$field_name][$delta];
$replaced_file = $file['replaced_file'];
if (module_exists('token')) {
global $user;
$widget_file_path = token_replace($field['widget']['file_path'], 'user', $user);
}
else {
$widget_file_path = $field['widget']['file_path'];
}
$validators = array(
'file_validate_extensions' => array($field['widget']['file_extensions']),
$complete_file_path = file_directory_path() .'/'. $widget_file_path;
if (!filefield_check_directory($widget_file_path, $upload_name)) {
// @todo: watchdog.
$file = array('fid' => 0, 'replaced_file' => $replaced_file);
return $file;
}
if (!$file = file_save_upload($upload_name, $validators, $complete_file_path)) {
// @todo: watchdog.
$file = array('fid' => 0, 'replaced_file' => $replaced_file);
return $file;
}
$file_default_properties = array(
'list' => 1,
'description' => $file->filename,
);
$file = array_merge($file_default_properties, (array) $file);
/**
* The filefield widget for previously uploaded files.
*/
function filefield_file_edit_form(&$form, &$form_state, $field, $delta, $file) {
$field_name_css = str_replace('_', '-', $field['field_name']);
$id = 'filefield-'. $field_name_css .'-'. $delta .'-form';
$classes = array(
'filefield-'. $field_name_css .'-form',
'filefield-file-form',
);
$widget = array(
'#type' => 'filefield_file_edit',
'#default_value' => $file,
'#prefix' => '<div id="'. $id .'" class="'. implode(' ', $classes) .'"><div class="filefield-file-edit">',
'#suffix' => '</div></div>',
);
// Buttons inside custom form elements are not registered by the Forms API,
// so we make the "Delete" button a regular child element and not a part
// of the filefield_file_upload widget.
$widget['flags'] = array(
'#type' => 'markup',
'#value' => '',
'#prefix' => '<div class="filefield-file-edit-flags">',
'#suffix' => '</div>',
);
$widget['flags'][$field['field_name'] .'_'. $delta .'_delete'] = array(
'#type' => 'submit',
'#value' => t('Delete'),
'#submit' => array('filefield_file_edit_delete_submit'), // without JavaScript
'#ahah' => array( // with JavaScript
'path' => 'filefield/js/delete/'. $field['field_name'] .'/'. $field['type_name'] .'/'. $delta,
'wrapper' => $id,
'method' => 'replace',
'effect' => 'fade',
),
'#field' => $field,
'#delta' => $delta,
'#file' => $file,
);
// Only show the list checkbox if files are not forced to be listed.
if (!$field['force_list']) {
$widget['flags']['list'] = array(
'#type' => 'checkbox',
'#title' => t('List'),
'#default_value' => $file['list'],
);
}
$edit_widget_info = filefield_widget_for_file($field, $file);
$widget['edit'] = array(
'#type' => $edit_widget_info['form element'],
'#field' => $field,
'#delta' => $delta,
'#default_value' => $file,
'#prefix' => '<div class="filefield-file-edit-widget">',
'#suffix' => '</div>',
);
return $widget;
}
/**
* Theme function for the file edit container element.
*/
function theme_filefield_file_edit($element) {
return theme('filefield_container_item', $element);
}
/**
* Custom value callback for file edit widgets, so that we don't need to rely
* on a tree structure but can assemble the file to our likings.
*/
function filefield_file_edit_value($element, $edit = FALSE) {
$file = $element['#default_value'];
if (!is_array($edit)) {
return $file;
}
$file_fixed_properties = array(
'list' => isset($edit['flags']['list'])
? $edit['flags']['list']
: $file['list'],
'delete' => 0,
'fid' => $file['fid'],
'uid' => $file['uid'],
'status' => $file['status'],
'filename' => $file['filename'],
'filepath' => $file['filepath'],
'filemime' => $file['filemime'],
'filesize' => $file['filesize'],
'timestamp' => $file['timestamp'],
);
if (is_array($edit['edit'])) {
$file = array_merge($file, $edit['edit']);
}
$file = array_merge($file, $file_fixed_properties);
return $file;
}
/**
* Submit callback for the "Delete" button next to each file item.
*/
function filefield_file_edit_delete_submit($form, &$form_state) {
$field = $form_state['clicked_button']['#field'];
$delta = $form_state['clicked_button']['#delta'];
filefield_file_edit_delete($form_state, $field, $delta);
// Rebuild the form with the new deleted-file state.
node_form_submit_build_node($form, $form_state);
}
/**
* Form callback for the "Delete" button with JavaScript enabled,
* invoked by filefield_js().
*/
function filefield_file_edit_delete_js(&$form, &$form_state, $field, $delta) {
// Mark the file as deleted and retrieve the replacement form element,
// an upload form.
$file = filefield_file_edit_delete($form_state, $field, $delta);
return filefield_file_upload_form($form, $form_state, $field, $delta, $file);
}
/**
* Update the form state so that the file for the given field and delta
* is marked as deleted.
*/
function filefield_file_edit_delete(&$form_state, $field, $delta) {
$field_name = $field['field_name'];
$file = &$form_state['values'][$field_name][$delta];
if (isset($file['status']) && $file['status'] == FILE_STATUS_PERMANENT) {
$file['delete'] = 1;
$file = array(
'fid' => 0,
'replaced_file' => $file,
);
}
else { // temporary file, get rid of it before it's even saved
$empty_file = array(
'fid' => 0,
'replaced_file' => $file['replaced_file'], // remember permanent files from before
);
field_file_delete($file);
$file = $empty_file;
}
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
return $file;
}
/**
* Shared AHAH callback for uploads and deletions. It just differs in a few
* unimportant details (what happens to the file, and which form is used as
* a replacement) so these details are taken care of by a form callback.
*/
function filefield_js($field_name, $type_name, $delta, $form_callback) {
$field = content_fields($field_name, $type_name);
if (empty($field) || empty($_POST['form_build_id'])) {
// Invalid request.
print drupal_to_js(array('data' => ''));
exit;
}
// Build the new form.
$form_state = array('submitted' => FALSE);
$form_build_id = $_POST['form_build_id'];
$form = form_get_cache($form_build_id, $form_state);
if (!$form) {
// Invalid form_build_id.
print drupal_to_js(array('data' => ''));
exit;
}
// form_get_cache() doesn't yield the original $form_state,
// but form_builder() does. Needed for retrieving the file array.
$built_form = $form;
$built_form_state = $form_state;
$built_form = form_builder($_POST['form_id'], $built_form, $built_form_state);
$form_element = $form_callback($built_form, $built_form_state, $field, $delta);
// Add the new element at the right place in the form.
if (module_exists('fieldgroup') && ($group_name = _fieldgroup_field_get_group($type_name, $field_name))) {
$form[$group_name][$field_name][$delta] = $form_element;
}
else {
$form[$field_name][$delta] = $form_element;
}
// Write the (unbuilt, updated) form back to the form cache.
form_set_cache($form_build_id, $form, $form_state);
// Render the form for output.
$form += array(
'#post' => $_POST,
'#programmed' => FALSE,
);
drupal_alter('form', $form, array(), 'filefield_js');
$form_state = array('submitted' => FALSE);
$form = form_builder('filefield_js', $form, $form_state);
$field_form = empty($group_name) ? $form[$field_name] : $form[$group_name][$field_name];
$output = theme('status_messages') . drupal_render($field_form[$delta]);
// For some reason, file uploads don't like drupal_json() with its manual
// setting of the text/javascript HTTP header. So use this one instead.
print drupal_to_js(array('status' => TRUE, 'data' => $output));
exit;
}
/**
* Determine which widget will be used for displaying the edit form
* for the given file.
*/
Jakob Petsovits
committed
function filefield_widget_for_file($field, $file) {
$file_widget_info = module_invoke_all('file_widget_info');
drupal_alter('file_widget_info', $file_widget_info);
$compatible_widget_info = array();
foreach ($file_widget_info as $element_name => $info) {
$info['form element'] = $element_name;
Jakob Petsovits
committed
$priority_callback = $info['priority callback'];
$priority = $priority_callback($field, $file);
if (!is_numeric($priority)) {
continue; // this widget is not interested in our file
}
$compatible_widget_info[$priority] = $info;
}
// Return the element with highest priority.
krsort($compatible_widget_info);
return reset($compatible_widget_info);
}
/**
* Implementation of hook_file_widget_info().
*/
Jakob Petsovits
committed
function filefield_file_widget_info() {
return array(
'filefield_generic_edit' => array(
'priority callback' => 'filefield_generic_edit_priority',
Jakob Petsovits
committed
),
);
}
/**
* Priority callback for the 'filefield_generic' widget:
* Really low priority for all files, as this is the most basic fallback.
*/
function filefield_generic_edit_priority($field, $file) {
Jakob Petsovits
committed
return -1;
}
* The 'process' callback for 'filefield_generic_edit' form elements.
* Called after defining the form and while building it, transforms the
* barebone element array into an icon and and a text field for editing
* the file description.
function filefield_generic_edit_process($element, $edit, &$form_state, $form) {
$field = $element['#field'];
$delta = $element['#delta'];
$file = $element['#value'];
Jakob Petsovits
committed
$url = file_create_url($file['filepath']);
$prefix = isset($element['#prefix']) ? $element['#prefix'] : '';
$suffix = isset($element['#suffix']) ? $element['#suffix'] : '';
$element['#prefix'] = $prefix .'<div class="filefield-generic-edit">';
$element['#suffix'] = '</div>'. $suffix;
$element['icon'] = array(
'#type' => 'markup',
Jakob Petsovits
committed
'#value' => theme('filefield_icon', $file),
);
$element['description'] = array(
Jakob Petsovits
committed
'#type' => 'textfield',
'#default_value' => (strlen($file['description']))
? $file['description']
: $file['filename'],
Jakob Petsovits
committed
'#maxlength' => 256,
'#description' => t('Size: !size, URL: !url', array(
'!size' => format_size($file['filesize']),
'!url' => l($url, $url),
)),
'#required' => TRUE,
'#prefix' => '<div class="filefield-generic-edit-description">',
'#suffix' => '</div>',
Jakob Petsovits
committed
);
return $element;
}
/**
* Theme function for the 'filefield_generic_edit' form element.
*/
function theme_filefield_generic_edit($element) {
return theme('form_element', $element, $element['#children']);
Jakob Petsovits
committed
}
function _filefield_widget_prepare_form_values($node, $field, &$items) {
$field_name = $field['field_name'];
// Attach new files.
if ($file = file_check_upload($field_name .'_upload')) {
$file = (array)$file;
// let extended validation from other module happen so we get all error messages.
// if you implement hook_filefield_file() return FALSE to stop the upload.
if (empty($errors)) {
$errors = module_invoke_all('filefield', 'file_validate', $node, $field, $file);
}
foreach(module_implements('filefield') as $module) {
$function = $module .'_filefield';
$function('file_prepare', $node, $field, $file);
}
function _filefield_widget_form($node, $field, &$items) {
$form[$field_name] = array(
'#type' => 'fieldset',
'#title' => t($field['widget']['label']),
'#description' => t('Changes made to the attachments are not permanent until you save this post.'),
);
return $form;
}
Jakob Petsovits
committed
* Implementation of hook_field_formatter_info().
*/
function filefield_field_formatter_info() {
return array(
'default' => array(
'label' => t('Default'),
'field types' => array('file'),
'multiple values' => CONTENT_HANDLE_CORE,
),
/**
* Theme function for the 'default' filefield field formatter.
*/
function theme_filefield_formatter_default($element) {
$file = $element['#item'];
if (!$file['fid']) {
return '';
$field = content_fields($element['#field_name'], $element['#type_name']);
if($field['force_list']) {
$file['list'] = 1; // always show the files if that option is enabled
drupal_add_css(drupal_get_path('module', 'filefield') .'/filefield.css');
return theme('filefield', $file);
$dashed_mime = check_plain(strtr($file['filemime'], array('/' => '-')));
Jakob Petsovits
committed
if ($icon_url = filefield_icon_url($file)) {
$icon = '<img class="field-icon-'. $dashed_mime .'" src="'. $icon_url .'" />';
}
return '<div class="filefield-icon field-icon-'. $dashed_mime .'">'. $icon .'</div>';
Darrel O'Pry
committed
function theme_filefield($file) {
if (user_access('view filefield uploads') && is_file($file['filepath']) && $file['list']) {
$path = ($file['fid'] == 'upload')
? file_create_filename($file['filename'], file_create_path($field['widget']['file_path']))
: $file['filepath'];
$icon = theme('filefield_icon', $file);
$url = file_create_url($path);
$desc = $file['description'];
return '<div class="filefield-item">'. $icon . l($desc, $url) .'</div>';
Jakob Petsovits
committed
return '';
Darrel O'Pry
committed
function filefield_file_download($file) {
$file = file_create_path($file);
Darrel O'Pry
committed
$result = db_query("SELECT * FROM {files} WHERE filepath = '%s'", $file);
if (!$file = db_fetch_object($result)) {
// We don't really care about this file.
return;
}
Darrel O'Pry
committed
// @todo: check the node for this file to be referenced in a field
// to determine if it is managed by filefield. and do the access denied part here.
if (!user_access('view filefield uploads')) {
// sorry you do not have the proper permissions to view filefield uploads.
return -1;
}
/* @todo: D6 port - files don't have any direct connection with nodes anymore
$node = node_load($file->nid);
if (!node_access('view', $node)) {
// You don't have permission to view the node
// this file is attached to.
return -1;
Darrel O'Pry
committed
}
// Well I guess you can see this file.
$name = mime_header_encode($file->filename);
$type = mime_header_encode($file->filemime);
// Serve images and text inline for the browser to display rather than download.
$disposition = ereg('^(text/|image/)', $file->filemime) ? 'inline' : 'attachment';
return array(
'Content-Type: '. $type .'; name='. $name,
'Content-Length: '. $file->filesize,
'Content-Disposition: '. $disposition .'; filename='. $name,
'Cache-Control: private',
);
Darrel O'Pry
committed
}
/**
* Create the file directory relative to the 'files' dir recursively for every
* directory in the path.
Darrel O'Pry
committed
* @param $directory
* The directory path under files to check, such as 'photo/path/here'
* @param $form_item
* An optional string containing the name of a form item that any errors
* will be attached to. (See field_file_check_directory() for more details.)
*/
function filefield_check_directory($directory, $form_item = NULL) {
$directory = field_file_strip_path($directory);
foreach (explode('/', $directory) as $dir) {
Darrel O'Pry
committed
$dirs[] = $dir;
$path = file_create_path(implode($dirs, '/'));
if (!field_file_check_directory($path, FILE_CREATE_DIRECTORY, $form_item)) {
watchdog('filefield', t('FileField failed to create directory (%d) at (%p).', array('%d' => $directory, '%p' => $path)), WATCHDOG_ERROR);
return FALSE;
}
Darrel O'Pry
committed
}
return TRUE;
}
* Implementation of hook_token_list():
* Provide a user readable list of filefield tokens.
function filefield_token_list($type = 'all') {
if ($type == 'field' || $type == 'all') {
$tokens = array();
$tokens['file']['fid'] = t("File ID");
$tokens['file']['description'] = t("File description");
$tokens['file']['filename'] = t("File name");
$tokens['file']['filepath'] = t("File path");
$tokens['file']['filemime'] = t("File MIME type");
$tokens['file']['filesize'] = t("File size (in bytes)");
$tokens['file']['filesize_formatted'] = t("File size (pretty printed)");
$tokens['file']['view'] = t("Fully formatted HTML file tag");
return $tokens;
}
}
/**
* Implementation of hook_token_values():
* Provide the concrete token values for a given file item.
*/
function filefield_token_values($type, $object = NULL) {
if ($type == 'field') {
$item = $object[0];
$tokens['fid'] = $item['fid'];
$tokens['description'] = $item['description'];
$tokens['filename'] = $item['filename'];
$tokens['filepath'] = $item['filepath'];
$tokens['filemime'] = $item['filemime'];
$tokens['filesize'] = $item['filesize'];
$tokens['filesize_formatted'] = format_size($item['filesize']);
$tokens['view'] = $item['view'];
return $tokens;
}
}