Commit 8d3eaa1c authored by webchick's avatar webchick

#560780 by quicksketch, ksenzee, Arancaytar, yched, and arianek: Added Image...

#560780 by quicksketch, ksenzee, Arancaytar, yched, and arianek: Added Image Field to image.module. Hellooooo, native image handling in core! :D
parent 33b09cc5
......@@ -127,11 +127,15 @@ Drupal 7.0, xxxx-xx-xx (development version)
hook_file_mimetype_mapping_alter().
* Added the hook_file_url_alter() hook, which makes it possible to serve
files from a CDN.
* Added a field specifically for uploading files, previously provided by
the contributed module FileField.
- Image handling:
* Improved image handling, including better support for add-on image
libraries.
* Added API and interface for creating advanced image thumbnails.
* Inclusion of additional effects such as rotate and desaturate.
* Added a field specifically for uploading images, previously provided by
the contributed module ImageField.
- Added aliased multi-site support:
* Added support for mapping domain names to sites directories.
- Added RDF support:
......
......@@ -507,14 +507,48 @@ function field_info_bundle_entity($bundle) {
/**
* Return array of all field data, keyed by field name.
*
* @param $bundle_type
* (optional) The bundle type on which to filter the list of fields. In the
* case of nodes, this is the node type.
* @param $field
* (optional) A field array or name on which to filter the list.
* @param $field_type
* (optional) A field type on which to filter the list.
* @return
* An array of Field objects. Each Field object has an additional
* property, bundles, which is an array of all the bundles to which
* this field belongs.
*/
function field_info_fields() {
$info = _field_info_collate_fields();
return $info['fields'];
function field_info_fields($bundle_type = NULL, $field = NULL, $field_type = NULL) {
// Build the list of fields to be used for retrieval.
if (isset($field)) {
if (is_string($field)) {
$field = field_info_field($field);
}
$fields = array($field['field_name'] => $field);
}
elseif (isset($bundle_type)) {
$instances = field_info_instances($bundle_type);
$fields = array();
foreach ($instances as $field_name => $instance) {
$fields[$field_name] = field_info_field($field_name);
}
}
else {
$info = _field_info_collate_fields();
$fields = $info['fields'];
}
// If a field type was given, filter the list down to fields of that type.
if (isset($field_type)) {
foreach ($fields as $key => $field) {
if ($field['type'] != $field_type) {
unset($fields[$key]);
}
}
}
return $fields;
}
/**
......
......@@ -170,9 +170,12 @@ function field_theme() {
);
$field_formatters = field_info_formatter_types(NULL);
foreach ($field_formatters as $key => $field_formatter) {
$items["field_formatter_$key"] = array(
$items['field_formatter_' . $key] = array(
'arguments' => array('element' => NULL),
);
if (isset($field_formatter['theme'])) {
$items['field_formatter_' . $key] += $field_formatter['theme'];
}
}
return $items;
}
......
......@@ -18,12 +18,12 @@ function file_field_info() {
'display_field' => 0,
'display_default' => 0,
'uri_scheme' => 'public',
'default_file' => 0,
),
'instance_settings' => array(
'file_extensions' => 'txt',
'file_directory' => '',
'max_filesize' => '',
'description_field' => 0,
),
'default_widget' => 'file_file',
'default_formatter' => 'file_default',
......@@ -51,11 +51,10 @@ function file_field_schema($field) {
'not null' => TRUE,
'default' => 1,
),
'data' => array(
'description' => 'Serialized additional data about the file, such as a description.',
'description' => array(
'description' => 'A description of the file.',
'type' => 'text',
'not null' => FALSE,
'serialize' => TRUE,
),
),
'indexes' => array(
......@@ -101,14 +100,6 @@ function file_field_settings_form($field, $instance, $has_data) {
'#disabled' => $has_data,
);
$form['default_file'] = array(
'#title' => t('Default file'),
'#type' => 'managed_file',
'#description' => t('If no file is uploaded, this file will be used on display.'),
'#default_value' => $field['settings']['default_file'],
'#upload_location' => 'public://default_files/',
);
return $form;
}
......@@ -118,15 +109,12 @@ function file_field_settings_form($field, $instance, $has_data) {
function file_field_instance_settings_form($field, $instance) {
$settings = $instance['settings'];
$form['#attached']['js'][] = drupal_get_path('module', 'file') . '/file.js';
$form['max_filesize'] = array(
$form['file_directory'] = array(
'#type' => 'textfield',
'#title' => t('Maximum upload size'),
'#default_value' => $settings['max_filesize'],
'#description' => t('Enter a value like "512" (bytes), "80 KB" (kilobytes) or "50 MB" (megabytes) in order to restrict the allowed file size. If left empty the file sizes will be limited only by PHP\'s maximum post and file upload sizes (current limit <strong>%limit</strong>).', array('%limit' => format_size(file_upload_max_size()))),
'#size' => 10,
'#element_validate' => array('_file_generic_settings_max_filesize'),
'#title' => t('File directory'),
'#default_value' => $settings['file_directory'],
'#description' => t('Optional subdirectory within the upload destination where files will be stored. Do not include preceding or trailing slashes.', array('%directory' => variable_get('file_directory_path', 'files') . '/')),
'#element_validate' => array('_file_generic_settings_file_directory_validate'),
'#weight' => 3,
);
......@@ -136,26 +124,28 @@ function file_field_instance_settings_form($field, $instance) {
'#type' => 'textfield',
'#title' => t('Allowed file extensions'),
'#default_value' => $extensions,
'#size' => 64,
'#description' => t('Separate extensions with a space or comma and do not include the leading dot. Leaving this blank will allow users to upload a file with any extension.'),
'#element_validate' => array('_file_generic_settings_extensions'),
'#weight' => 4,
'#weight' => 1,
);
$form['destination'] = array(
'#type' => 'fieldset',
'#title' => t('Upload destination'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
$form['max_filesize'] = array(
'#type' => 'textfield',
'#title' => t('Maximum upload size'),
'#default_value' => $settings['max_filesize'],
'#description' => t('Enter a value like "512" (bytes), "80 KB" (kilobytes) or "50 MB" (megabytes) in order to restrict the allowed file size. If left empty the file sizes will be limited only by PHP\'s maximum post and file upload sizes (current limit <strong>%limit</strong>).', array('%limit' => format_size(file_upload_max_size()))),
'#size' => 10,
'#element_validate' => array('_file_generic_settings_max_filesize'),
'#weight' => 5,
);
$form['destination']['file_directory'] = array(
'#type' => 'textfield',
'#title' => t('File directory'),
'#default_value' => $settings['file_directory'],
'#description' => t('Optional subdirectory within the upload destination where files will be stored. Do not include preceding or trailing slashes.', array('%directory' => variable_get('file_directory_path', 'files') . '/')),
'#element_validate' => array('_file_generic_settings_file_directory_validate'),
'#parents' => array('instance', 'settings', 'file_directory'),
$form['description_field'] = array(
'#type' => 'checkbox',
'#title' => t('Enable <em>Description</em> field'),
'#default_value' => isset($settings['description_field']) ? $settings['description_field'] : '',
'#description' => t('The description field allows users to enter a description about the uploaded file.'),
'#parents' => array('instance', 'settings', 'description_field'),
'#weight' => 11,
);
return $form;
......@@ -230,9 +220,7 @@ function file_field_load($obj_type, $objects, $field, $instances, $langcode, &$i
if (empty($item['fid']) || !isset($files[$item['fid']])) {
$items[$obj_id][$delta] = NULL;
}
// Unserialize the data column.
else {
$item['data'] = unserialize($item['data']);
$items[$obj_id][$delta] = array_merge($item, (array) $files[$item['fid']]);
}
}
......@@ -243,19 +231,10 @@ function file_field_load($obj_type, $objects, $field, $instances, $langcode, &$i
* Implement hook_field_sanitize().
*/
function file_field_sanitize($obj_type, $object, $field, $instance, $langcode, &$items) {
// If there are no files specified at all, use the default.
if (empty($items) && $field['settings']['default_file']) {
if ($file = file_load($field['settings']['default_file'])) {
$items[0] = (array) $file;
$items[0]['is_default'] = TRUE;
}
}
// Remove files from being displayed if they're not displayed.
else {
foreach ($items as $delta => $item) {
if (!file_field_displayed($item, $field)) {
unset($items[$delta]);
}
foreach ($items as $delta => $item) {
if (!file_field_displayed($item, $field)) {
unset($items[$delta]);
}
}
......@@ -274,11 +253,6 @@ function file_field_insert($obj_type, $object, $field, $instance, $langcode, &$i
* Implement hook_field_update().
*/
function file_field_update($obj_type, $object, $field, $instance, $langcode, &$items) {
// Serialize the data column before storing.
foreach ($items as $delta => $item) {
$items[$delta]['data'] = serialize($item['data']);
}
// Check for files that have been removed from the object.
// On new revisions, old files are always maintained in the previous revision.
......@@ -416,11 +390,10 @@ function file_field_formatter_info() {
function file_field_widget_info() {
return array(
'file_generic' => array(
'label' => t('Generic file'),
'label' => t('File'),
'field types' => array('file'),
'settings' => array(
'progress_indicator' => 'throbber',
'description_field' => 0,
),
'behaviors' => array(
'multiple values' => FIELD_BEHAVIOR_CUSTOM,
......@@ -446,26 +419,10 @@ function file_field_widget_settings_form($field, $instance) {
),
'#default_value' => $settings['progress_indicator'],
'#description' => t('The throbber display does not show the status of uploads but takes up space. The progress bar is helpful for monitoring progress on large uploads.'),
'#weight' => 2,
'#weight' => 16,
'#access' => file_progress_implementation(),
);
$form['additional'] = array(
'#type' => 'fieldset',
'#title' => t('Additional fields'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#weight' => 10,
);
$form['additional']['description_field'] = array(
'#type' => 'checkbox',
'#title' => t('Enable <em>Description</em> field'),
'#default_value' => $settings['description_field'],
'#description' => t('The description field allows users to enter a description about the uploaded file.'),
'#parents' => array('instance', 'widget', 'settings', 'description_field'),
);
return $form;
}
......@@ -477,8 +434,8 @@ function file_field_widget(&$form, &$form_state, $field, $instance, $langcode, $
$defaults = array(
'fid' => 0,
'display' => $field['settings']['display_default'],
'data' => array('description' => ''),
'display' => !empty($field['settings']['display_default']),
'description' => '',
);
// Retrieve any values set in $form_state, as will be the case during AJAX
......@@ -632,7 +589,7 @@ function file_field_widget_value($element, $input = FALSE, $form_state) {
$return += array(
'fid' => 0,
'display' => 1,
'data' => array(),
'description' => '',
);
return $return;
......@@ -653,17 +610,8 @@ function file_field_widget_process($element, &$form_state, $form) {
$element['#theme'] = 'file_widget';
// Data placeholder for widgets to store additional data.
$element['data'] = array(
'#tree' => TRUE,
'#title' => t('File data'),
'#collapsible' => TRUE,
'#collapsed' => TRUE,
'#access' => (bool) $item['fid'],
);
// Add the display field if enabled.
if ($field['settings']['display_field'] && $item['fid']) {
if (!empty($field['settings']['display_field']) && $item['fid']) {
$element['display'] = array(
'#type' => empty($item['fid']) ? 'hidden' : 'checkbox',
'#title' => t('Include file in display'),
......@@ -679,11 +627,11 @@ function file_field_widget_process($element, &$form_state, $form) {
}
// Add the description field if enabled.
if ($settings['description_field'] && $item['fid']) {
$element['data']['description'] = array(
if (!empty($instance['settings']['description_field']) && $item['fid']) {
$element['description'] = array(
'#type' => 'textfield',
'#title' => t('Description'),
'#value' => isset($item['data']['description']) ? $item['data']['description'] : '',
'#value' => isset($item['description']) ? $item['description'] : '',
'#type' => variable_get('file_description_type', 'textfield'),
'#maxlength' => variable_get('file_description_length', 128),
'#description' => t('The description may be used as the label of the link to the file.'),
......@@ -769,6 +717,7 @@ function theme_file_widget_multiple($variables) {
$element = $variables['element'];
$field = field_info_field($element['#field_name']);
$instance = field_info_instance($element['#field_name'], $element['#bundle']);
// Get our list of widgets in order.
$widgets = array();
......@@ -784,7 +733,7 @@ function theme_file_widget_multiple($variables) {
// Build up a table of applicable fields.
$headers = array();
$headers[] = t('File information');
if ($field['settings']['display_field']) {
if (!empty($field['settings']['display_field'])) {
$headers[] = array(
'data' => t('Display'),
'class' => array('checkbox'),
......@@ -812,7 +761,7 @@ function theme_file_widget_multiple($variables) {
// Render the "Display" option in its own own column.
$display = '';
if ($field['settings']['display_field']) {
if (!empty($field['settings']['display_field'])) {
unset($element[$key]['display']['#title']);
$display = array(
'data' => drupal_render($element[$key]['display']),
......@@ -830,7 +779,7 @@ function theme_file_widget_multiple($variables) {
$row = array();
$row[] = $information;
if ($field['settings']['display_field']) {
if (!empty($field['settings']['display_field'])) {
$row[] = $display;
}
$row[] = $weight;
......
......@@ -87,8 +87,11 @@ function file_theme() {
/**
* Implement hook_file_download().
*
* This function takes an extra parameter $field_type so that it may
* be re-used by other File-like modules, such as Image.
*/
function file_file_download($uri) {
function file_file_download($uri, $field_type = 'file') {
global $user;
// Get the file record based on the URI. If not in the database just return.
......@@ -101,11 +104,11 @@ function file_file_download($uri) {
}
// Find out which (if any) file fields contain this file.
$references = file_get_file_references($file);
$references = file_get_file_references($file, NULL, FIELD_LOAD_REVISION, $field_type);
// TODO: Check field-level access if available here.
$denied = NULL;
$denied = $file->status ? NULL : FALSE;
// Check access to content containing the file fields. If access is allowed
// to any of this content, allow the download.
foreach ($references as $field_name => $field_references) {
......@@ -610,11 +613,11 @@ function theme_file_link($variables) {
);
// Use the description as the link text if available.
if (empty($file->data['description'])) {
if (empty($file->description)) {
$link_text = check_plain($file->filename);
}
else {
$link_text = check_plain($file->data['description']);
$link_text = check_plain($file->description);
$options['attributes']['title'] = check_plain($file->filename);
}
......@@ -838,62 +841,28 @@ function file_icon_map($file) {
*/
/**
* Return an array of file fields in an bundle or by field name.
*
* @param $bundle_type
* (optional) The bundle type on which to filter the list of fields. In the
* case of nodes, this is the node type.
* @param $field
* (optional) A field array or name on which to filter the list.
*/
function file_get_field_list($bundle_type = NULL, $field = NULL) {
// Build the list of fields to be used for retrieval.
if (isset($field)) {
if (is_string($field)) {
$field = field_info_field($field);
}
$fields = array($field['field_name'] => $field);
}
elseif (isset($bundle_type)) {
$instances = field_info_instances($bundle_type);
$fields = array();
foreach ($instances as $field_name => $instance) {
$fields[$field_name] = field_info_field($field_name);
}
}
else {
$fields = field_info_fields();
}
// Filter down the list to just file fields.
foreach ($fields as $key => $field) {
if ($field['type'] != 'file') {
unset($fields[$key]);
}
}
return $fields;
}
/**
* Count the number of times the file is referenced within a field.
* Count the number of times the file is referenced.
*
* @param $file
* A file object.
* @param $field
* Optional. The CCK field array or field name as a string.
* (optional) A CCK field array or field name as a string. If provided,
* limits the reference check to the given field.
* @param $field_type
* (optional) The name of a field type. If provided, limits the reference
* check to fields of the given type.
* @return
* An integer value.
*/
function file_get_file_reference_count($file, $field = NULL) {
$fields = file_get_field_list(NULL, $field);
function file_get_file_reference_count($file, $field = NULL, $field_type = 'file') {
$fields = field_info_fields(NULL, $field, $field_type);
$types = field_info_fieldable_types();
$reference_count = 0;
foreach ($fields as $field) {
// TODO: Use a more efficient mechanism rather than actually retrieving
// all the references themselves, such as using a COUNT() query.
$references = file_get_file_references($file, $field);
$references = file_get_file_references($file, $field, FIELD_LOAD_REVISION, $field_type);
foreach ($references as $obj_type => $type_references) {
$reference_count += count($type_references);
}
......@@ -925,22 +894,26 @@ function file_get_file_reference_count($file, $field = NULL) {
/**
* Get a list of references to a file by bundle and ID.
* Get a list of references to a file.
*
* @param $file
* A file object.
* @param $field
* (optional) A field array to be used for this check.
* (optional) A field array to be used for this check. If given, limits the
* reference check to the given field.
* @param $age
* (optional) A constant that specifies which references to count. Use
* FIELD_LOAD_REVISION to retrieve all references within all revisions or
* FIELD_LOAD_CURRENT to retrieve references only in the current revisions.
* @param $field_type
* Optional. The name of a field type. If given, limits the reference check to
* fields of the given type.
* @return
* An integer value.
*/
function file_get_file_references($file, $field = NULL, $age = FIELD_LOAD_REVISION) {
function file_get_file_references($file, $field = NULL, $age = FIELD_LOAD_REVISION, $field_type = 'file') {
$references = drupal_static(__FUNCTION__, array());
$fields = file_get_field_list(NULL, $field);
$fields = field_info_fields(NULL, $field, $field_type);
foreach ($fields as $field_name => $file_field) {
if (!isset($references[$field_name])) {
......
......@@ -288,10 +288,10 @@ class FileFieldDisplayTestCase extends FileFieldTestCase {
'display_field' => '1',
'display_default' => '1',
);
$instance_settings = array();
$widget_settings = array(
$instance_settings = array(
'description_field' => '1',
);
$widget_settings = array();
$this->createFileField($field_name, $type_name, $field_settings, $instance_settings, $widget_settings);
$field = field_info_field($field_name);
$instance = field_info_instance($field_name, $type_name);
......
/* $Id$ */
/**
* Image upload widget.
*/
div.image-preview {
float: right; /* RTL */
padding: 0 0 10px 10px; /* RTL */
}
div.image-widget-data {
float: right; /* RTL */
}
/* $Id$ */
/**
* Image upload widget.
*/
div.image-preview {
float: left; /* RTL */
padding: 0 10px 10px 0; /* RTL */
}
div.image-widget-data {
float: left; /* RTL */
}
div.image-widget-data input.text-field {
width: auto;
}
<?php
// $Id$
/**
* @file
* Implement an image field, based on the file module's file field.
*/
/**
* Implement hook_field_info().
*/
function image_field_info() {
return array(
'image' => array(
'label' => t('Image'),
'description' => t('This field stores the ID of an image file as an integer value.'),
'settings' => array(
'uri_scheme' => 'public',
'default_image' => 0,
),
'instance_settings' => array(
'file_extensions' => 'png gif jpg jpeg',
'file_directory' => '',
'max_filesize' => '',
'alt_field' => 0,
'title_field' => 0,
'max_resolution' => '',
'min_resolution' => '',
),
'default_widget' => 'image_image',
'default_formatter' => 'image',
),
);
}
/**
* Implement hook_field_schema().
*/
function image_field_schema($field) {
return array(
'columns' => array(
'fid' => array(
'description' => 'The {files}.fid being referenced in this field.',
'type' => 'int',
'not null' => FALSE,
'unsigned' => TRUE,
),
'alt' => array(
'description' => "Alternative image text, for the image's 'alt' attribute.",
'type' => 'varchar',
'length' => 128,
'not null' => FALSE,
),
'title' => array(
'description' => "Image title text, for the image's 'title' attribute.",
'type' => 'varchar',
'length' => 128,
'not null' => FALSE,
),
),
'indexes' => array(
'fid' => array('fid'),
),
);
}
/**
* Implement hook_field_settings_form().
*/
function image_field_settings_form($field, $instance) {
$defaults = field_info_field_settings($field['type']);
$settings = array_merge($defaults, $field['settings']);
$scheme_options = array();
foreach (file_get_stream_wrappers() as $scheme => $stream_wrapper) {
if ($scheme != 'temporary') {
$scheme_options[$scheme] = $stream_wrapper['name'];
}
}
$form['uri_scheme'] = array(
'#type' => 'radios',
'#title' => t('Upload destination'),
'#options' => $scheme_options,
'#default_value' => $settings['uri_scheme'],
'#description' => t('Select where the final files should be stored. Private file storage has significantly more overhead than public files, but allows restricted access to files within this field.'),
);
$form['default_image'] = array(
'#title' => t('Default image'),
'#type' => 'managed_file',
'#description' => t('If no image is uploaded, this image will be shown on display.'),
'#default_value' => $field['settings']['default_image'],
'#upload_location' => 'public://default_images/',
);
return $form;