diff --git modules/field/field.info.inc modules/field/field.info.inc index e9616f2..08ea559 100644 --- modules/field/field.info.inc +++ modules/field/field.info.inc @@ -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; } /** diff --git modules/file/file.field.inc modules/file/file.field.inc index 5e509f6..1985edf 100644 --- modules/file/file.field.inc +++ modules/file/file.field.inc @@ -15,15 +15,16 @@ function file_field_info() { 'label' => t('File'), 'description' => t('This field stores the ID of a file as an integer value.'), 'settings' => array( - 'display_field' => 0, - 'display_default' => 0, 'uri_scheme' => 'public', 'default_file' => 0, ), 'instance_settings' => array( + 'display_field' => 0, + 'display_default' => 0, 'file_extensions' => 'txt', 'file_directory' => '', 'max_filesize' => '', + 'description_field' => 0, ), 'default_widget' => 'file_file', 'default_formatter' => 'file_default', @@ -43,7 +44,7 @@ function file_field_schema($field) { 'not null' => FALSE, 'unsigned' => TRUE, ), - 'display' => array( + 'display_file' => array( 'description' => 'Flag to control whether this file should be displayed when viewing content.', 'type' => 'int', 'size' => 'tiny', @@ -51,11 +52,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( @@ -73,19 +73,6 @@ function file_field_settings_form($field, $instance, $has_data) { $form['#attached']['js'][] = drupal_get_path('module', 'file') . '/file.js'; - $form['display_field'] = array( - '#type' => 'checkbox', - '#title' => t('Enable Display field'), - '#default_value' => $settings['display_field'], - '#description' => t('The display option allows users to choose if a file should be shown when viewing the content.'), - ); - $form['display_default'] = array( - '#type' => 'checkbox', - '#title' => t('Files displayed by default'), - '#default_value' => $settings['display_default'], - '#description' => t('This setting only has an effect if the display option is enabled.'), - ); - $scheme_options = array(); foreach (file_get_stream_wrappers() as $scheme => $stream_wrapper) { if ($scheme != 'temporary') { @@ -120,6 +107,19 @@ function file_field_instance_settings_form($field, $instance) { $form['#attached']['js'][] = drupal_get_path('module', 'file') . '/file.js'; + $form['display_field'] = array( + '#type' => 'checkbox', + '#title' => t('Enable Display field'), + '#default_value' => $settings['display_field'], + '#description' => t('The display option allows users to choose if a file should be shown when viewing the content.'), + ); + $form['display_default'] = array( + '#type' => 'checkbox', + '#title' => t('Files displayed by default'), + '#default_value' => $settings['display_default'], + '#description' => t('This setting only has an effect if the display option is enabled.'), + ); + $form['max_filesize'] = array( '#type' => 'textfield', '#title' => t('Maximum upload size'), @@ -127,7 +127,7 @@ function file_field_instance_settings_form($field, $instance) { '#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 %limit).', array('%limit' => format_size(file_upload_max_size()))), '#size' => 10, '#element_validate' => array('_file_generic_settings_max_filesize'), - '#weight' => 3, + '#weight' => 4, ); // Make the extension list a little more human-friendly by comma-separation. @@ -139,7 +139,7 @@ function file_field_instance_settings_form($field, $instance) { '#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' => 5, ); $form['destination'] = array( @@ -147,7 +147,7 @@ function file_field_instance_settings_form($field, $instance) { '#title' => t('Upload destination'), '#collapsible' => TRUE, '#collapsed' => TRUE, - '#weight' => 5, + '#weight' => 6, ); $form['destination']['file_directory'] = array( '#type' => 'textfield', @@ -158,6 +158,22 @@ function file_field_instance_settings_form($field, $instance) { '#parents' => array('instance', 'settings', 'file_directory'), ); + $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 Description 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', 'widget', 'settings', 'description_field'), + ); + return $form; } @@ -230,9 +246,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']]); } } @@ -253,7 +267,7 @@ function file_field_sanitize($obj_type, $object, $field, $instance, $langcode, & // Remove files from being displayed if they're not displayed. else { foreach ($items as $delta => $item) { - if (!file_field_displayed($item, $field)) { + if (!file_field_displayed($item, $instance)) { unset($items[$delta]); } } @@ -274,11 +288,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. @@ -375,14 +384,14 @@ function file_field_is_empty($item, $field) { * * @param $item * A field item array. - * @param $field - * A field array. + * @param $instance + * A field instance array. * @return * Boolean TRUE if the file will be displayed, FALSE if the file is hidden. */ -function file_field_displayed($item, $field) { - if (!empty($field['settings']['display_field'])) { - return (bool) $item['display']; +function file_field_displayed($item, $instance) { + if (!empty($instance['settings']['display_field'])) { + return (bool) $item['display_file']; } return TRUE; } @@ -393,7 +402,7 @@ function file_field_displayed($item, $field) { function file_field_formatter_info() { return array( 'file_default' => array( - 'label' => t('Generic file'), + 'label' => t('File'), 'field types' => array('file'), ), 'file_table' => array( @@ -416,11 +425,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 +454,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' => 3, '#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 Description 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,7 +469,7 @@ function file_field_widget(&$form, &$form_state, $field, $instance, $langcode, $ $defaults = array( 'fid' => 0, - 'display' => $field['settings']['display_default'], + 'display_file' => $instance['settings']['display_default'], 'data' => array('description' => ''), ); @@ -619,9 +611,9 @@ function file_field_widget_value($element, $input = FALSE, $form_state) { if ($input) { // Checkboxes lose their value when empty. // If the display field is present make sure its unchecked value is saved. - $field = field_info_field($element['#field_name']); - if (empty($input['display'])) { - $input['display'] = $field['settings']['display_field'] ? 0 : 1; + $instance = field_info_instance($element['#field_name'], $element['#bundle']); + if (empty($input['display_file'])) { + $input['display_file'] = $instance['settings']['display_field'] ? 0 : 1; } } @@ -631,7 +623,7 @@ function file_field_widget_value($element, $input = FALSE, $form_state) { // Ensure that all the required properties are returned even if empty. $return += array( 'fid' => 0, - 'display' => 1, + 'display_file' => 1, // TODO: Is this wise? "Include file in display" is currently always checked... 'data' => array(), ); @@ -663,23 +655,23 @@ function file_field_widget_process($element, &$form_state, $form) { ); // Add the display field if enabled. - if ($field['settings']['display_field'] && $item['fid']) { - $element['display'] = array( + if ($instance['settings']['display_field'] && $item['fid']) { + $element['display_file'] = array( '#type' => empty($item['fid']) ? 'hidden' : 'checkbox', '#title' => t('Include file in display'), - '#value' => isset($item['display']) ? $item['display'] : $field['settings']['display_default'], + '#value' => isset($item['display_file']) ? $item['display_file'] : $instance['settings']['display_default'], '#attributes' => array('class' => array('file-display')), ); } else { - $element['display'] = array( + $element['display_file'] = array( '#type' => 'hidden', '#value' => '1', ); } // Add the description field if enabled. - if ($settings['description_field'] && $item['fid']) { + if (!empty($settings['description_field']) && $item['fid']) { $element['data']['description'] = array( '#type' => 'textfield', '#title' => t('Description'), @@ -765,6 +757,7 @@ function theme_file_widget($element) { */ function theme_file_widget_multiple($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(); @@ -780,7 +773,7 @@ function theme_file_widget_multiple($element) { // Build up a table of applicable fields. $headers = array(); $headers[] = t('File information'); - if ($field['settings']['display_field']) { + if ($instance['settings']['display_field']) { $headers[] = array( 'data' => t('Display'), 'class' => array('checkbox'), @@ -808,10 +801,10 @@ function theme_file_widget_multiple($element) { // Render the "Display" option in its own own column. $display = ''; - if ($field['settings']['display_field']) { - unset($element[$key]['display']['#title']); + if ($instance['settings']['display_field']) { + unset($element[$key]['display_file']['#title']); $display = array( - 'data' => drupal_render($element[$key]['display']), + 'data' => drupal_render($element[$key]['display_file']), 'class' => array('checkbox'), ); } @@ -826,7 +819,7 @@ function theme_file_widget_multiple($element) { $row = array(); $row[] = $information; - if ($field['settings']['display_field']) { + if ($instance['settings']['display_field']) { $row[] = $display; } $row[] = $weight; diff --git modules/file/file.module modules/file/file.module index 7a2e263..fec71a1 100644 --- modules/file/file.module +++ modules/file/file.module @@ -830,62 +830,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); } @@ -917,22 +883,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])) { diff --git modules/file/tests/file.test modules/file/tests/file.test index 4aade36..cd42706 100644 --- modules/file/tests/file.test +++ modules/file/tests/file.test @@ -284,12 +284,13 @@ class FileFieldDisplayTestCase extends FileFieldTestCase { $field_name = 'field_' . strtolower($this->randomName()); $type_name = 'article'; $field_settings = array( + ); + $instance_settings = array( 'display_field' => '1', 'display_default' => '1', + 'description_field' => '1', ); - $instance_settings = array(); $widget_settings = array( - 'description_field' => '1', ); $this->createFileField($field_name, $type_name, $field_settings, $instance_settings, $widget_settings); $field = field_info_field($field_name); diff --git modules/image/image.css modules/image/image.css new file mode 100644 index 0000000..23bbf31 --- /dev/null +++ modules/image/image.css @@ -0,0 +1,15 @@ +/* $Id$ */ + +/** + * Image widget. + */ +div.image-preview { + float: left; + padding: 0 10px 10px 0; +} +div.image-widget-data { + float: left; +} +div.image-widget-data input.text-field { + width: auto; +} diff --git modules/image/image.field.inc modules/image/image.field.inc new file mode 100644 index 0000000..bbb6d4b --- /dev/null +++ modules/image/image.field.inc @@ -0,0 +1,499 @@ + 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_file' => 0, + ), + 'instance_settings' => array( + 'display_field' => 0, + 'display_default' => 0, + 'file_extensions' => 'png gif jpg jpeg', + 'file_directory' => '', + 'max_filesize' => '', + 'alt_field' => 0, + 'title_field' => 0, + 'description_field' => 0, + 'max_resolution' => '', + 'min_resolution' => '', + 'preview_image_style' => 'thumbnail', + ), + '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, + ), + 'display_file' => array( + 'description' => 'Flag to control whether this file should be displayed when viewing content.', + 'type' => 'int', + 'size' => 'tiny', + 'unsigned' => TRUE, + 'not null' => TRUE, + 'default' => 1, + ), + '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, + ), + 'description' => array( + 'description' => "A description of the file.", + 'type' => 'text', + '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']); + + $form['#attached']['js'][] = drupal_get_path('module', 'file') . '/file.js'; + + $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_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; + +} + +/** + * Implement hook_field_instance_settings_form(). + */ +function image_field_instance_settings_form($field, $instance) { + $settings = $instance['settings']; + + // Use the file field instance settings form as a basis. + $form = file_field_instance_settings_form($field, $instance); + + $form['display_field'] = array( + '#type' => 'checkbox', + '#title' => t('Enable Display field'), + '#default_value' => $settings['display_field'], + '#description' => t('The display option allows users to choose if a file should be shown when viewing the content.'), + ); + $form['display_default'] = array( + '#type' => 'checkbox', + '#title' => t('Files displayed by default'), + '#default_value' => $settings['display_default'], + '#description' => t('This setting only has an effect if the display option is enabled.'), + ); + + // Add maximum and minimum resolution settings. + $max_resolution = explode('x', $settings['max_resolution']) + array('', ''); + $form['max_resolution'] = array( + '#title' => t('Maximum image resolution'), + '#element_validate' => array('_image_field_resolution_validate'), + '#theme_wrappers' => array('form_element'), + '#weight' => 4.1, + '#description' => t('The maximum allowed image size expressed as WIDTHxHEIGHT (e.g. 640x480). Leave blank for no restriction. If a larger image is uploaded, it will be resized to reflect the given width and height. Resizing images on upload will cause the loss of EXIF data in the image.'), + ); + $form['max_resolution']['x'] = array( + '#type' => 'textfield', + '#default_value' => $max_resolution[0], + '#size' => 5, + '#maxlength' => 5, + '#field_suffix' => ' x ', + '#theme_wrappers' => array(), + ); + $form['max_resolution']['y'] = array( + '#type' => 'textfield', + '#default_value' => $max_resolution[1], + '#size' => 5, + '#maxlength' => 5, + '#field_suffix' => ' ' . t('pixels'), + '#theme_wrappers' => array(), + ); + + $min_resolution = explode('x', $settings['min_resolution']) + array('', ''); + $form['min_resolution'] = array( + '#title' => t('Minimum image resolution'), + '#element_validate' => array('_image_field_resolution_validate'), + '#theme_wrappers' => array('form_element'), + '#weight' => 4.2, + '#description' => t('The minimum allowed image size expressed as WIDTHxHEIGHT (e.g. 640x480). Leave blank for no restriction. If a smaller image is uploaded, it will be rejected.'), + ); + $form['min_resolution']['x'] = array( + '#type' => 'textfield', + '#default_value' => $min_resolution[0], + '#size' => 5, + '#maxlength' => 5, + '#field_suffix' => ' x ', + '#theme_wrappers' => array(), + ); + $form['min_resolution']['y'] = array( + '#type' => 'textfield', + '#default_value' => $min_resolution[1], + '#size' => 5, + '#maxlength' => 5, + '#field_suffix' => ' ' . t('pixels'), + '#theme_wrappers' => array(), + ); + + // Add title and alt configuration options. + $form['additional']['alt_field'] = array( + '#type' => 'checkbox', + '#title' => t('Enable Alt field'), + '#default_value' => $settings['alt_field'], + '#description' => t('The alt attribute may be used by search engines, screen readers, and when the image cannot be loaded.'), + //'#parents' => array('instance', 'widget', 'settings', 'alt_field'), + '#weight' => -2, + ); + $form['additional']['title_field'] = array( + '#type' => 'checkbox', + '#title' => t('Enable Title field'), + '#default_value' => $settings['title_field'], + '#description' => t('The title attribute is used as a tooltip when the mouse hovers over the image.'), + //'#parents' => array('instance', 'widget', 'settings', 'title_field'), + '#weight' => -1, + ); + + // Add settings for preview image style. + $form['preview_image_style'] = array( + '#title' => t('Preview image style'), + '#type' => 'select', + '#options' => array('' => '<' . t('no preview') . '>') + image_style_options(FALSE), + '#default_value' => $settings['preview_image_style'], + '#description' => t('The preview image will be shown while editing the content.'), + ); + + return $form; +} + +/** + * Implement hook_field_load(). + */ +function image_field_load($obj_type, $objects, $field, $instances, $langcode, &$items, $age) { + file_field_load($obj_type, $objects, $field, $instances, $langcode, &$items, $age); +} + +/** + * Implement hook_field_sanitize(). + */ +function image_field_sanitize($obj_type, $object, $field, $instance, $langcode, &$items) { + file_field_sanitize($obj_type, $object, $field, $instance, $langcode, &$items); +} + +/** + * Implement hook_field_insert(). + */ +function image_field_insert($obj_type, $object, $field, $instance, $langcode, &$items) { + image_field_update($obj_type, $object, $field, $instance, $langcode, &$items); +} + +/** + * Implement hook_field_update(). + */ +function image_field_update($obj_type, $object, $field, $instance, $langcode, &$items) { + file_field_update($obj_type, $object, $field, $instance, $langcode, &$items); +} + +/** + * Implement hook_field_delete(). + */ +function image_field_delete($obj_type, $object, $field, $instance, $langcode, &$items) { + file_field_delete($obj_type, $object, $field, $instance, $langcode, &$items); +} + +/** + * Implement hook_field_delete_revision(). + */ +function image_field_delete_revision($obj_type, $object, $field, $instance, $langcode, &$items) { + file_field_delete_revision($obj_type, $object, $field, $instance, $langcode, &$items); +} + +/** + * Implement hook_field_is_empty(). + */ +function image_field_is_empty($item, $field) { + return file_field_is_empty($item, $field); +} + +/** + * Implement hook_field_formatter_info_alter(). + */ +function image_field_formatter_info_alter(&$info) { + // Let image fields use generic file formatters. + $info['file_default']['field types'][] = 'image'; + $info['file_table']['field types'][] = 'image'; + $info['file_url_plain']['field types'][] = 'image'; +} + +/** + * Implement hook_file_references(). + */ +function image_file_references($file) { + $count = file_get_file_reference_count($file, NULL, 'image'); + return $count ? array('image' => $count) : NULL; +} + +/** + * Implement hook_field_widget_settings_form(). + */ +function image_field_widget_settings_form($field, $instance) { + // Use the file widget settings form. + $form = file_field_widget_settings_form($field, $instance); + + return $form; +} + +/** + * Element validate function for resolution fields. + */ +function _image_field_resolution_validate($element, &$form_state) { + if (!empty($element['x']['#value']) || !empty($element['y']['#value'])) { + foreach (array('x', 'y') as $dimension) { + $value = $element[$dimension]['#value']; + if (!is_numeric($value)) { + form_error($element[$dimension], t('Height and width values must be numeric.')); + return; + } + if (intval($value) == 0) { + form_error($element[$dimension], t('Both a height and width value must be specified in the !name field.', array('!name' => $element['#title']))); + return; + } + } + form_set_value($element, intval($element['x']['#value']) . 'x' . intval($element['y']['#value']), $form_state); + } + else { + form_set_value($element, '', $form_state); + } +} + +/** + * Implement hook_field_widget_info(). + */ +function image_field_widget_info() { + return array( + 'image_image' => array( + 'label' => t('Image'), + 'field types' => array('image'), + 'settings' => array( + 'progress_indicator' => 'throbber', + ), + 'behaviors' => array( + 'multiple values' => FIELD_BEHAVIOR_CUSTOM, + 'default value' => FIELD_BEHAVIOR_NONE, + ), + ), + ); +} + +/** + * Implementation of hook_field_widget(). + */ +function image_field_widget(&$form, &$form_state, $field, $instance, $items, $delta = 0) { + $elements = file_field_widget($form, $form_state, $field, $instance, $items, $delta); + $settings = $instance['settings']; + + foreach (element_children($elements) as $delta) { + // Add upload resolution validation. + if ($settings['max_resolution'] || $settings['min_resolution']) { + $elements[$delta]['#upload_validators']['file_validate_image_resolution'] = array($settings['max_resolution'], $settings['min_resolution']); + } + + // If not using custom extension validation, ensure this is an image. + $supported_extensions = array('png', 'gif', 'jpg', 'jpeg'); + $extensions = isset($elements[$delta]['#upload_validators']['file_validate_extensions'][0]) ? $elements[$delta]['#upload_validators']['file_validate_extensions'][0] : implode(' ', $supported_extensions); + $extensions = array_intersect(explode(' ', $extensions), $supported_extensions); + $elements[$delta]['#upload_validators']['file_validate_extensions'][0] = implode(' ', $extensions); + + // Add all extra functionality provided by the image widget. + $elements[$delta]['#process'][] = 'image_field_widget_process'; + } + + if ($field['cardinality'] == 1) { + // If there's only one field, return it as delta 0. + if (empty($elements[0]['#default_value']['fid'])) { + $elements[0]['#description'] = theme('file_upload_help', $instance['description'], $elements[0]['#upload_validators']); + } + } + else { + //$elements['#file_upload_description'] = theme('file_upload_help', '', $elements[0]['#upload_validators']); + } + return $elements; +} + +/** + * An element #process callback for the file_image field type. + * + * Expands the file_image type to include the alt and title fields. + */ +function image_field_widget_process($element, &$form_state, $form) { + $item = $element['#value']; + $item['fid'] = $element['fid']['#value']; + + $field = field_info_field($element['#field_name']); + $instance = field_info_instance($element['#field_name'], $element['#bundle']); + $settings = $instance['settings']; + + $element['#theme'] = 'image_widget'; + $element['#attached_css'][] = drupal_get_path('module', 'image') . '/image.css'; + + // Add the image preview. + if ($element['#file'] && $settings['preview_image_style']) { + $element['preview'] = array( + '#type' => 'markup', + '#markup' => theme('image_style', $settings['preview_image_style'], $element['#file']->uri, NULL, NULL, array(), FALSE), + ); + } + + // Add the additional alt and title fields. + $element['alt'] = array( + '#title' => t('Alternate Text'), + '#type' => 'textfield', + '#default_value' => isset($item['alt']) ? $item['alt'] : '', + '#description' => t('This text will be used by screen readers, search engines, or when the image cannot be loaded.'), + '#maxlength' => variable_get('image_alt_length', 80), // See http://www.gawds.org/show.php?contentid=28. + '#weight' => -2, + ); + $element['title'] = array( + '#type' => 'textfield', + '#title' => t('Title'), + '#default_value' => isset($item['title']) ? $item['title'] : '', + '#description' => t('The title is used as a tool tip when the user hovers the mouse over the image.'), + '#maxlength' => variable_get('image_title_length', 500), + '#weight' => -1, + ); + + // If fields are disabled, convert the type to "value" to save existing data. + if (!$settings['alt_field']) { + $element['alt']['#type'] = 'value'; + $element['alt']['#value'] = $element['alt']['#default_value']; + } + if (!$settings['title_field']) { + $element['title']['#type'] = 'value'; + $element['title']['#value'] = $element['title']['#default_value']; + } + + return $element; +} + +/** + * Theme the display of the image field widget. + */ +function theme_image_widget($element) { + $output = ''; + $output .= '
'; + + if (isset($element['preview'])) { + $output .= '
'; + $output .= drupal_render($element['preview']); + $output .= '
'; + } + + $output .= '
'; + if ($element['fid']['#value'] != 0) { + $element['filename']['#markup'] .= ' (' . format_size($element['#file']->filesize) . ') '; + } + $output .= drupal_render_children($element); + $output .= '
'; + $output .= '
'; + + return $output; +} + +/** + * Implement hook_field_formatter_info(). + */ +function image_field_formatter_info() { + $formatters = array( + 'image' => array( + 'label' => t('Image'), + 'field types' => array('image'), + ), + 'image_link_content' => array( + 'label' => t('Image linked to content'), + 'field types' => array('image'), + ), + 'image_link_file' => array( + 'label' => t('Image linked to file'), + 'field types' => array('image'), + ), + ); + + // TODO: Add image style formatters. + + return $formatters; +} + +/** + * Theme function for 'image' file field formatter. + */ +function theme_field_formatter_image($element) { + return theme('image', $element['#item']['uri'], $element['#item']['alt'], $element['#item']['title']); +} + +/** + * Theme function for 'image_link_content' file field formatter. + */ +function theme_field_formatter_image_link_content($element) { + list($id, $vid, $bundle) = field_extract_ids($element['#object_type'], $element['#object']); + return l(theme('field_formatter_image', $element), $element['#object_type'] . '/' . $id, array('html' => TRUE)); +} + +/** + * Theme function for 'image_link_file' file field formatter. + */ +function theme_field_formatter_image_link_file($element) { + return l(theme('field_formatter_image', $element), file_create_url($element['#item']['uri']), array('html' => TRUE)); +} diff --git modules/image/image.info modules/image/image.info index 16225d2..0887153 100644 --- modules/image/image.info +++ modules/image/image.info @@ -7,5 +7,6 @@ core = 7.x files[] = image.module files[] = image.admin.inc files[] = image.effects.inc +files[] = image.field.inc files[] = image.install files[] = image.test diff --git modules/image/image.module modules/image/image.module index 2ec6c4b..584e6e2 100644 --- modules/image/image.module +++ modules/image/image.module @@ -6,6 +6,9 @@ * Exposes global functionality for creating image styles. */ +// Load all Field module hooks for Image. +require_once DRUPAL_ROOT . '/modules/image/image.field.inc'; + /** * Implement of hook_help(). */ @@ -126,6 +129,7 @@ function image_menu() { */ function image_theme() { return array( + // Theme functions in image.module. 'image_style' => array( 'arguments' => array( 'style' => NULL, @@ -136,6 +140,8 @@ function image_theme() { 'getsize' => TRUE, ), ), + + // Theme functions in image.admin.inc. 'image_style_list' => array( 'arguments' => array('styles' => NULL), ), @@ -160,6 +166,20 @@ function image_theme() { 'image_rotate_summary' => array( 'arguments' => array('data' => NULL), ), + + // Theme functions in image.field.inc. + 'image_widget' => array( + 'arguments' => array('element' => NULL), + ), + 'field_formatter_image' => array( + 'arguments' => array('element' => NULL), + ), + 'field_formatter_image_link_content' => array( + 'arguments' => array('element' => NULL), + ), + 'field_formatter_image_link_file' => array( + 'arguments' => array('element' => NULL), + ), ); } @@ -464,7 +484,7 @@ function image_style_generate() { // acquiring the lock. $success = file_exists($destination) || image_style_create_derivative($style, $path, $destination); - if ($lock_acquired) { + if (!empty($lock_acquired)) { lock_release($lock_name); } @@ -773,6 +793,7 @@ function image_effect_delete($effect) { * TRUE on success. FALSE if unable to perform the image effect on the image. */ function image_effect_apply($image, $effect) { + module_load_include('inc', 'image', 'image.effects'); if (function_exists($effect['effect callback'])) { return call_user_func($effect['effect callback'], $image, $effect['data']); } @@ -810,7 +831,7 @@ function theme_image_style($style_name, $path, $alt = '', $title = '', $attribut if (!file_exists($style_path)) { $style_path = image_style_url($style_name, $path); } - return theme('image', file_create_url($style_path), $alt, $title, $attributes, $getsize); + return theme('image', $style_path, $alt, $title, $attributes, $getsize); } /**