Index: modules/image/image.info =================================================================== RCS file: /cvs/drupal/drupal/modules/image/image.info,v retrieving revision 1.2 diff -u -r1.2 image.info --- modules/image/image.info 21 Jul 2009 07:09:46 -0000 1.2 +++ modules/image/image.info 29 Aug 2009 19:29:46 -0000 @@ -7,5 +7,6 @@ files[] = image.module files[] = image.admin.inc files[] = image.effects.inc +files[] = image.field.inc files[] = image.install files[] = image.test Index: modules/image/image.module =================================================================== RCS file: /cvs/drupal/drupal/modules/image/image.module,v retrieving revision 1.16 diff -u -r1.16 image.module --- modules/image/image.module 26 Aug 2009 03:20:39 -0000 1.16 +++ modules/image/image.module 29 Aug 2009 19:29:53 -0000 @@ -6,6 +6,9 @@ * Exposes global functionality for creating image styles. */ +// Load all Field module hooks for Image. +require(DRUPAL_ROOT . '/modules/image/image.field.inc'); + /** * Implement of hook_help(). */ @@ -126,6 +129,7 @@ */ function image_theme() { return array( + // image.module. 'image_style' => array( 'arguments' => array( 'style' => NULL, @@ -136,6 +140,8 @@ 'getsize' => TRUE, ), ), + + // image.admin.inc. 'image_style_list' => array( 'arguments' => array('styles' => NULL), ), @@ -160,6 +166,20 @@ 'image_rotate_summary' => array( 'arguments' => array('data' => NULL), ), + + // 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 @@ // 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 @@ * 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 @@ 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); } /** Index: modules/image/image.css =================================================================== RCS file: modules/image/image.css diff -N modules/image/image.css --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/image/image.css 1 Jan 1970 00:00:00 -0000 @@ -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; +} Index: modules/image/image.field.inc =================================================================== RCS file: modules/image/image.field.inc diff -N modules/image/image.field.inc --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ modules/image/image.field.inc 1 Jan 1970 00:00:00 -0000 @@ -0,0 +1,327 @@ + t('Maximum image resolution'), + '#element_validate' => array('_image_field_resolution_validate'), + '#theme_wrappers' => array('form_element'), + '#weight' => 3.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' => 3.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 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.'), + ); + + // 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, + ); + + 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( + 'file_image' => array( + 'label' => t('Image'), + 'field types' => array('file'), + 'settings' => array( + 'progress_indicator' => 'throbber', + 'alt_field' => 0, + 'title_field' => 0, + 'description_field' => 0, + 'max_resolution' => '', + 'min_resolution' => '', + 'preview_image_style' => 'thumbnail', + 'default_file_extensions' => 'png gif jpg jpeg', + ), + '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['widget']['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, title, and caption 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['widget']['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['data']['alt'] = array( + '#title' => t('Alternate Text'), + '#type' => 'textfield', + '#default_value' => isset($item['data']['alt']) ? $item['data']['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['data']['title'] = array( + '#type' => 'textfield', + '#title' => t('Title'), + '#default_value' => isset($item['data']['title']) ? $item['data']['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['data']['alt']['#type'] = 'value'; + $element['data']['alt']['#value'] = $element['data']['alt']['#default_value']; + } + if (!$settings['title_field']) { + $element['data']['title']['#type'] = 'value'; + $element['data']['title']['#value'] = $element['data']['title']['#default_value']; + } + + return $element; +} + +/** + * Implement hook_field_create_instance(). + */ +function image_field_create_instance($instance) { + // If creating a new image widget, set some matching formatters. + if (isset($instance['widget']['type']) && $instance['widget']['type'] == 'file_image') { + if (!isset($instance['display'])) { + $instance['display']['full']['type'] = 'image'; + $instance['display']['teaser']['type'] = 'image'; + } + if (!isset($instance['settings']['file_extensions'])) { + $instance['settings']['file_extensions'] = 'png jpg gif'; + } + field_update_instance($instance); + } +} + +/** + * 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('file'), + ), + 'image_link_content' => array( + 'label' => t('Image linked to content'), + 'field types' => array('file'), + ), + 'image_link_file' => array( + 'label' => t('Image linked to file'), + 'field types' => array('file'), + ), + ); + + // 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']['data']['alt'], $element['#item']['data']['title']); +} + +/** + * Theme function for 'image_link_content' file field formatter. + */ +function theme_field_formatter_image_link_content($element) { + list($id, $vid, $bundle) = field_attach_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)); +}