Index: imagefield.css =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/imagefield/imagefield.css,v retrieving revision 1.2.4.1 diff -u -p -r1.2.4.1 imagefield.css --- imagefield.css 17 Dec 2007 04:47:05 -0000 1.2.4.1 +++ imagefield.css 14 Apr 2008 19:18:56 -0000 @@ -1,14 +1,8 @@ -div.imagefield-edit-image-row { - border: 1px solid #e5e5e5; - padding: 5px; - margin-bottom: 10px; -} - div.imagefield-edit-preview img { border: 1px solid #e5e5e5; } -div.imagefield-edit-preview { +div.imagefield-edit-preview { float: left; } @@ -26,7 +20,9 @@ div.imagefield-edit-image-detail { } div.imagefield-edit-image-flags div.form-item { - float: right; + float: right; } - +div.imagefield-element input.form-submit { + margin: 0 0.5em 0 0; +} Index: imagefield.info =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/imagefield/imagefield.info,v retrieving revision 1.4.4.2 diff -u -p -r1.4.4.2 imagefield.info --- imagefield.info 6 Dec 2007 09:25:39 -0000 1.4.4.2 +++ imagefield.info 14 Apr 2008 19:18:56 -0000 @@ -1,5 +1,6 @@ ; $Id: imagefield.info,v 1.4.4.2 2007/12/06 09:25:39 dopry Exp $ name = Image Field description = Defines an image field type. -dependencies = content +core = 6.x +dependencies[] = content package = CCK Index: imagefield.install =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/imagefield/imagefield.install,v retrieving revision 1.2.4.1 diff -u -p -r1.2.4.1 imagefield.install --- imagefield.install 18 Apr 2007 21:02:19 -0000 1.2.4.1 +++ imagefield.install 14 Apr 2008 19:18:57 -0000 @@ -73,6 +73,22 @@ function imagefield_update_2() { return $ret; } +/** + * Upgrade to CCK 2 and Drupal 6. + */ +function imagefield_update_6100() { + include_once('./'. drupal_get_path('module', 'content') .'/content_crud.inc'); + $fields = content_fields(); + foreach ($fields as $field) { + // Convert max_number_images to CCK's multiple limit. + if ($field['type'] == 'image' && $field['widget']['max_number_images'] > 0) { + $field['multiple'] = $field['widget']['max_number_images']; + $field = array_merge($field, $field['widget']); + content_field_instance_update($field); + } + } + return array(); +} Index: imagefield.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/imagefield/imagefield.module,v retrieving revision 1.30.2.6.2.49 diff -u -p -r1.30.2.6.2.49 imagefield.module --- imagefield.module 2 Apr 2008 16:06:00 -0000 1.30.2.6.2.49 +++ imagefield.module 14 Apr 2008 19:18:57 -0000 @@ -4,93 +4,30 @@ /** * @file * Defines an image field type. - * imagefield uses content.module to store the fid, and the drupal files + * imagefield uses content.module to store the fid, and the drupal files * table to store the actual file data. * */ - -function imagefield_menu($maycache) { +/** + * Implementation of hook_menu(). + */ +function imagefield_menu() { $items = array(); - if ($maycache) { - $items[] = array( - 'path' => 'imagefield/js', - 'callback' => 'imagefield_js', - //'access' => user_access(), - 'access' => TRUE, - 'type' => MENU_CALLBACK - ); - } - elseif ($_SESSION['imagefield']) { - // do this variable_get once.... - $download_method = variable_get('file_downloads', FILE_DOWNLOADS_PUBLIC); - - // Iterate over each field stored in session imagefield looking - // for files in a preview state to add menu items for. This - // allows us to preview new uploads before a node is submitted. - foreach ($_SESSION['imagefield'] as $fieldname => $files) { - // move on to the next field if there is nothing to process in files. - if (empty($files)) continue; - - foreach($files as $delta => $file) { - // If the file is not a preview do not display it. - if (empty($file['preview'])) continue; - - // filepath to pass into _imagefield_preview - $filepath = $file['preview']; - - // build url path for private files menu item. - if ($download_method == FILE_DOWNLOADS_PRIVATE) { - // strip out the file_directory_path. It shouldn't be a part - // of the URL with private downloads. - if (strpos($file['preview'], file_directory_path()) !== FALSE) { - $file['preview'] = trim(substr($file['preview'], strlen(file_directory_path())), '\\/'); - } - $file['preview'] = 'system/files/' . $file['preview']; - } - $items[] = array( - 'path' => $file['preview'], - 'callback' => '_imagefield_preview', - 'callback arguments' => array($filepath), - 'access' => TRUE, - 'type' => MENU_CALLBACK, - ); - } - } - } + $items['imagefield/js'] = array( + 'page callback' => 'imagefield_js', + 'access callback' => 'user_access', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); + return $items; } /** - * transfer a file that is in a 'preview' state. - * @todo multiple support + * Implementation of hook_perm(). */ -function _imagefield_preview($filepath) { - foreach ($_SESSION['imagefield'] as $fieldname => $files) { - foreach ($files as $delta => $file) { - if ($file['preview'] == $filepath) { - // Emulate a normal file transfer by setting cache flags that will - // prevent the image from needing to be resent on previews. Without - // setting the cache headers, transfered images still get the expire - // headers set in drupal_page_header(). - $modified_time = filemtime($file['filepath']); - $last_modified = gmdate('D, d M Y H:i:s', $modified_time) .' GMT'; - $etag = '"'.md5($last_modified).'"'; - - file_transfer($file['filepath'], array( - 'Content-Type: '. mime_header_encode($file['filemime']), - 'Content-Length: '. $file['filesize'], - 'Cache-Control: max-age=1209600', - 'Expires: '. gmdate('D, d M Y H:i:s', time() + 1209600) .' GMT', // Two weeks. - 'Last-Modified: '. $last_modified, - 'ETag: '. $etag, - )); - } - } - } -} - function imagefield_perm() { return array('view imagefield uploads'); } @@ -100,7 +37,10 @@ function imagefield_perm() { */ function imagefield_field_info() { return array( - 'image' => array('label' => 'Image'), + 'image' => array( + 'label' => t('Image'), + 'description' => t('Store an image file and text for alt and title tags.'), + ), ); } @@ -109,14 +49,12 @@ function imagefield_field_info() { */ function imagefield_field_settings($op, $field) { switch ($op) { - case 'callbacks': - return array('view' => CONTENT_CALLBACK_CUSTOM); - case 'form': $form = array(); $form['default'] = array( '#type' => 'fieldset', '#title' => t('Default image'), + '#element_validate' => array('_imagefield_field_settings_default_validate'), ); // Present a thumbnail of the current default image. $form['default']['use_default_image'] = array( @@ -144,24 +82,14 @@ function imagefield_field_settings($op, ); return $form; - case 'validate': - // We save the upload here because we can't know the correct - // file path until we save the file. - if ($file = file_check_upload('default_image_upload')) { - if ($file = file_save_upload('default_image_upload', file_directory_path())) { - form_set_value(array('#parents' => array('default_image')), (array) $file); - } - } - - break; case 'save': return array('default_image', 'use_default_image'); case 'database columns': $columns = array( 'fid' => array('type' => 'int', 'not null' => TRUE, 'default' => '0'), - 'title' => array('type' => 'varchar', length => 255, 'not null' => TRUE, 'default' => "''", 'sortable' => TRUE), - 'alt' => array('type' => 'varchar', length => 255, 'not null' => TRUE, 'default' => "''", 'sortable' => TRUE), + 'title' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '', 'sortable' => TRUE), + 'alt' => array('type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '', 'sortable' => TRUE), ); return $columns; @@ -178,7 +106,20 @@ function imagefield_field_settings($op, } /** - * Custom filter for imagefield NOT NULL + * Element specific validation for imagefield default value. + * Validated in a separate function from imagefield_field() to get access to the $form_state + * variable. + */ +function _imagefield_field_settings_default_validate($element, &$form_state) { + // We save the upload here because we can't know the correct + // file path until we save the file. + if ($file = file_save_upload('default_image_upload', array(), file_directory_path())) { + $form_state['values']['default_image'] = (array)$file; + } +} + +/** + * Custom filter for imagefield NOT NULL. */ function imagefield_views_handler_filter_is_not_null($op, $filter, $filterinfo, &$query) { if ($op == 'handler') { @@ -194,72 +135,48 @@ function imagefield_views_handler_filter } -function imagefield_default_item() { - return array( - 'fid' => 0, - 'title' => '', - 'alt' => '', - ); -} - /** - * insert a file into the database. + * Make a temporary file permanent in the files table. + * * @param $node - * node object file will be associated with. + * Node object this file is be associated with. * @param $file - * file to be inserted, passed by reference since fid should be attached. - * + * File to be inserted, passed by reference since fid should be attached. */ function imagefield_file_insert($node, &$file, $field) { - $fieldname = $field['field_name']; - - // allow tokenized paths. - if (function_exists('token_replace')) { - global $user; - $widget_image_path = token_replace($field['widget']['image_path'],'user', $user); - } - else { - $widget_image_path = $field['widget']['image_path']; + if ($file['flags']['delete'] == TRUE) { + if (_imagefield_file_delete($file, $field['field_name'])) { + return array(); + } } - - $filepath = file_create_path($widget_image_path) . '/' . $file['filename']; - - if (imagefield_check_directory($widget_image_path) && $file = file_save_upload((object)$file, $filepath)) { + elseif (isset($file['fid']) && $file['fid'] > 0) { + $file = (object)$file; + file_set_status($file, FILE_STATUS_PERMANENT); $file = (array)$file; - $file['fid'] = db_next_id('{files}_fid'); - db_query("INSERT into {files} (fid, nid, filename, filepath, filemime, filesize) - VALUES (%d, %d, '%s','%s','%s',%d)", - $file['fid'], $node->nid, $file['filename'], $file['filepath'], $file['filemime'], $file['filesize']); - module_invoke_all('imagefield_file', 'save', $file); - return (array)$file; - } - else { - // Include file name in upload error. - form_set_error(NULL, t('Image upload was unsuccessful.')); - return FALSE; + return $file; } } - /** - * update the file record if necessary + * Update the file record if necessary. + * * @param $node + * Node object this file is be associated with. * @param $file + * A single CCK image field item to be updated. * @param $field + * The field definition for this image field. */ function imagefield_file_update($node, &$file, $field) { - $file = (array)$file; + $file = (array)$file; if ($file['flags']['delete'] == TRUE) { - if(_imagefield_file_delete($file, $field['field_name'])) { + if (_imagefield_file_delete($file, $field['field_name'])) { return array(); } } - if ($file['fid'] == 'upload') { - return imagefield_file_insert($node, $file, $field); - } else { // if fid is not numeric here we should complain. - // else we update the file table. + // else we update the file table. } return $file; } @@ -296,8 +213,6 @@ function imagefield_field($op, $node, $f unset($items[$delta]); } } - $items = array_values($items); // compact deltas - imagefield_clear_field_session($fieldname); break; // called before content.module defaults. @@ -311,7 +226,7 @@ function imagefield_field($op, $node, $f $item['flags']['hidden'] = TRUE; $item['flags']['delete'] = TRUE; } - + // Update each file item. $items[$delta] = imagefield_file_update($node, $item, $field); @@ -324,30 +239,29 @@ function imagefield_field($op, $node, $f } } } - $items = array_values($items); // compact deltas - imagefield_clear_field_session($fieldname); break; case 'delete': foreach ($items as $delta => $item) { - _imagefield_file_delete($item, $field['field_name']); + _imagefield_file_delete($item, $field['field_name']); } break; - case 'view': - $context = $teaser ? 'teaser' : 'full'; - $formatter = isset($field['display_settings'][$context]['format']) ? $field['display_settings'][$context]['format'] : 'default'; + case 'sanitize': + // Cleanup $items during node preview. + foreach ($items as $delta => $item) { + if (empty($item['fid']) || $item['flags']['delete']) { + unset($items[$delta]); + } + } + + // If completely empty, check for a default image. if ($field['use_default_image'] && empty($items) ) { $items[0] = $field['default_image']; } - foreach ($items as $delta => $item) { - $items[$delta]['view'] = content_format($field, $item, $formatter, $node); - } - return theme('field', $node, $field, $items, $teaser, $page); } } - /** * Implementation of hook_widget_info(). */ @@ -356,6 +270,8 @@ function imagefield_widget_info() { 'image' => array( 'label' => 'Image', 'field types' => array('image'), + 'multiple values' => CONTENT_HANDLE_MODULE, + 'callbacks' => array('default value' => CONTENT_CALLBACK_CUSTOM), ), ); } @@ -365,52 +281,42 @@ function imagefield_widget_info() { */ function imagefield_widget_settings($op, $widget) { switch ($op) { - case 'callbacks': - return array('default value' => CONTENT_CALLBACK_CUSTOM); - case 'form': $form = array(); - $form['max_resolution'] = array ( - '#type' => 'textfield', - '#title' => t('Maximum resolution for Images'), + $form['max_resolution'] = array( + '#type' => 'textfield', + '#title' => t('Maximum resolution for Images'), '#default_value' => $widget['max_resolution'] ? $widget['max_resolution'] : 0, - '#size' => 15, - '#maxlength' => 10, - '#description' => + '#size' => 15, + '#maxlength' => 10, + '#description' => t('The maximum allowed image size expressed as WIDTHxHEIGHT (e.g. 640x480). Set to 0 for no restriction. If a larger image is uploaded, it will be resized to reflect the given width and height.'), ); - $form['max_filesize'] = array ( - '#type' => 'textfield', - '#title' => t('Maximum filesize for Images'), + $form['max_filesize'] = array( + '#type' => 'textfield', + '#title' => t('Maximum filesize for Images'), '#default_value' => $widget['max_filesize'] ? $widget['max_filesize'] : 0, - '#size' => 6, + '#size' => 6, '#description' => t('The maximum allowed image file size expressed in kilobytes. Set to 0 for no restriction.') ); - $form['max_number_images'] = array ( - '#type' => 'textfield', - '#title' => t('Maximum number of images'), - '#default_value' => $widget['max_number_images'] ? $widget['max_number_images'] : 0, - '#size' => 4, - '#description' => t('The maximum number of images allowed. Set to 0 for no restriction. This only applies if multiple values are enabled.') - ); $form['image_path'] = array( - '#type' => 'textfield', - '#title' => t('Image path'), - '#default_value' => $widget['image_path'] ? $widget['image_path'] : '', - '#description' => t('Optional subdirectory within the "%dir" directory where images will be stored. Do not include trailing slash.', array('%dir' => variable_get('file_directory_path', 'files'))), + '#type' => 'textfield', + '#title' => t('Image path'), + '#default_value' => $widget['image_path'] ? $widget['image_path'] : '', + '#description' => t('Optional subdirectory within the "%dir" directory where images will be stored. Do not include trailing slash.', array('%dir' => variable_get('file_directory_path', 'files'))), ); if (function_exists('token_replace')) { $form['image_path']['#description'] .= ' '. t('You can use the following tokens in the image path.'); $form['image_path']['#suffix'] = theme('token_help', 'user'); } - $form['file_extensions'] = array ( - '#type' => 'textfield', - '#title' => t('Permitted upload file extensions.'), + $form['file_extensions'] = array( + '#type' => 'textfield', + '#title' => t('Permitted upload file extensions.'), '#default_value' => $widget['file_extensions'] ? $widget['file_extensions'] : 'jpg jpeg png gif', - '#size' => 64, - '#maxlength' => 64, + '#size' => 64, + '#maxlength' => 64, '#description' => t('Extensions a user can upload to this field. Seperate extensions with a space and do not include the leading dot.') - ); + ); $form['custom_alt'] = array( '#type' => 'checkbox', @@ -427,13 +333,13 @@ function imagefield_widget_settings($op, return $form; case 'validate': - // strip slashes from the beginning and end of $widget['image_path'] - $widget['image_path'] = trim($widget['image_path'], '\\/'); - form_set_value(array('#parents' => array('image_path')), $widget['image_path']); + if (!preg_match('!^[^/].*[^/]$!', $widget['image_path'])) { + form_set_error('image_path', t('Image paths should not start or end with slashes.')); + } break; case 'save': - return array('max_resolution', 'max_filesize', 'max_number_images', 'image_path', 'file_extensions', 'custom_alt', 'custom_title'); + return array('max_resolution', 'max_filesize', 'image_path', 'file_extensions', 'custom_alt', 'custom_title'); } } @@ -441,7 +347,7 @@ function imagefield_widget_settings($op, * Implementation of hook_form_alter(). Set the appropriate * attibutes to allow file uploads on the field settings form. */ -function imagefield_form_alter($form_id, &$form) { +function imagefield_form_alter(&$form, $form_state, $form_id) { if ($form_id == '_content_admin_field') { $form['#attributes'] = array('enctype' => 'multipart/form-data'); } @@ -450,16 +356,16 @@ function imagefield_form_alter($form_id, /** * Create the image directory relative to the 'files' dir recursively for every * directory in the path. - * + * * @param $directory * The directory path under files to check, such as 'photo/path/here' * @param $form_element * A form element to throw an error on if the directory is not writable - */ + */ function imagefield_check_directory($directory, $form_element = array()) { - foreach(explode('/', $directory) as $dir) { + foreach (explode('/', $directory) as $dir) { $dirs[] = $dir; - $path = file_create_path(implode($dirs,'/')); + $path = file_create_path(implode($dirs, '/')); file_check_directory($path, FILE_CREATE_DIRECTORY, $form_element['#parents'][0]); } return true; @@ -473,41 +379,17 @@ function _imagefield_scale_image($file, $result = image_scale($file['filepath'], $file['filepath'], $width, $height); if ($result) { $file['filesize'] = filesize($file['filepath']); - drupal_set_message(t('The image %filename was resized to fit within the maximum allowed resolution of %resolution pixels', array('%resolution' => $resolution, '%filename' => $file['filename']))); + drupal_set_message(t('The image %filename was resized to fit within the maximum allowed resolution of %resolution pixels', array('%resolution' => $resolution, '%filename' => $file['filename']))); } } } return $file; } - -function imagefield_clear_session() { - if (is_array($_SESSION['imagefield']) && count($_SESSION['imagefield'])) { - foreach (array_keys($_SESSION['imagefield']) as $fieldname) { - imagefield_clear_field_session($fieldname); - } - unset($_SESSION['imagefield']); - } -} - -function imagefield_clear_field_session($fieldname) { - if (is_array($_SESSION['imagefield'][$fieldname]) && count($_SESSION['imagefield'][$fieldname])) { - foreach ($_SESSION['imagefield'][$fieldname] as $delta => $file) { - if (is_file($file['filepath'])) { - file_delete($file['filepath']); - } - } - unset($_SESSION['imagefield'][$fieldname]); - } -} - function _imagefield_file_delete($file, $fieldname) { if (is_numeric($file['fid'])) { db_query('DELETE FROM {files} WHERE fid = %d', $file['fid']); } - else { - unset($_SESSION['imagefield'][$fieldname][$file['sessionid']]); - } module_invoke_all('imagefield_file', 'delete', $file); return file_delete($file['filepath']); } @@ -515,369 +397,266 @@ function _imagefield_file_delete($file, /** * Implementation of hook_widget(). */ -function imagefield_widget($op, &$node, $field, &$items) { - switch ($op) { - case 'default value': - return array(); +function imagefield_widget(&$form, &$form_state, $field, $items) { + $element = array( + '#type' => $field['widget']['type'], + '#title' => $field['widget']['label'], + '#default_value' => $items, + '#required' => $field['required'], + '#multiple' => $field['multiple'], + '#element_validate' => array('_imagefield_widget_validate'), + '#field' => $field, + ); + return $element; +} - case 'prepare form values': - _imagefield_widget_prepare_form_values($node, $field, $items); - return; +/** + * Implementation of hook_elements(). + */ +function imagefield_elements() { + $elements = array(); + $elements['image'] = array( + '#input' => TRUE, + '#columns' => array('fid', 'title', 'alt'), + '#process' => array('imagefield_element_process'), + ); + return $elements; +} - case 'form': - return _imagefield_widget_form($node, $field, $items); +/** + * Process the image type element before displaying the field. + */ +function imagefield_element_process($element, $edit, &$form_state, $form) { + $field = $element['#field']; + $fieldname = $field['field_name']; + drupal_add_css(drupal_get_path('module', 'imagefield') .'/imagefield.css'); - case 'validate': - _imagefield_widget_validate($node, $field, $items); - return; + // Pull in form state saved in storage. + form_get_cache($_POST['form_build_id'], $form_state); + if (isset($form_state['storage'][$fieldname])) { + $form_state['values'][$fieldname] = $form_state['storage'][$fieldname]; + // Unset the storage to keep the form from unnecessarily rebuilding. + unset($form_state['storage'][$fieldname]); } -} + // Change the type and theme to prevent FAPI from trying to output with the + // theme_image() function. + $element['#type'] = 'imagefield'; + $element['#theme'] = 'imagefield'; + $element['#tree'] = TRUE; -function _imagefield_widget_prepare_form_values(&$node, $field, &$items) { - $fieldname = $field['field_name']; - // clean up the session if we weren't posted. - if (!count($_POST)) { - imagefield_clear_session(); + $files = array(); + if (isset($form_state['values'])) { + // Set a default value if available. + if (!isset($form_state[$fieldname]) && isset($element['#default_value'])) { + $form_state['values'][$fieldname] = $element['#default_value']; + } + + foreach ($form_state['values'][$fieldname] as $delta => $file) { + if (!empty($file['fid'])) { + $files[$file['fid']] = array_merge($file, _imagefield_file_load($file['fid'])); + } + } } - // Attach new files - if ($file = file_check_upload($fieldname . '_upload')) { - $file = (array)$file; + $form_state['values'][$fieldname] = $files; + $element['#files'] = $files; - // Validation must happen immediately after the image is uploaded so we - // can discard the file if it turns out not to be a valid mime type - $valid_image = _imagefield_widget_upload_validate($node, $field, $items, $file); - //$valid_image = TRUE; + foreach ($files as $fid => &$file) { + $element[$fid]['flags']['delete'] = array( + '#type' => 'checkbox', + '#title' => t('Delete'), + '#default_value' => isset($file['flags']['delete']) ? $file['flags']['delete'] : 0, + ); - if ($valid_image) { - $file = _imagefield_scale_image($file, $field['widget']['max_resolution']); + $element[$fid]['admin_preview'] = array( + '#type' => 'markup', + '#value' => theme('imagefield_image', $file, $file['alt'], $file['title'], array('width' => '150'), FALSE), + ); - // Allow tokenized paths if available - if (function_exists('token_replace')) { - global $user; - $widget_image_path = token_replace($field['widget']['image_path'],'user', $user); - } - else { - $widget_image_path = $field['widget']['image_path']; - } - imagefield_check_directory($widget_image_path); - $filepath = file_create_filename($file['filename'], file_create_path($widget_image_path)); - - $file['fid'] = 'upload'; - $file['preview'] = $filepath; - - // If a single field, mark any other images for deletion and delete files in session - if (!$field['multiple']) { - if (is_array($items)) { - foreach ($items as $delta => $session_file) { - $items[$delta]['flags']['hidden'] = TRUE; - $items[$delta]['flags']['delete'] = TRUE; - } - } - imagefield_clear_field_session($fieldname); - } - // Add the file to the session - $file_id = count($items) + count($_SESSION['imagefield'][$fieldname]); - $file['sessionid'] = $file_id; - $_SESSION['imagefield'][$fieldname][$file_id] = $file; - } - else { - // Delete the invalid file - file_delete($file['filepath']); + $element[$fid]['description'] = array( + '#type' => 'markup', + '#value' => ''. t('Filename: ') .''. $file['filename'], + ); - // If a single field and a valid file is in the session, mark existing image for deletion - if (!$field['multiple']) { - if (count($_SESSION['imagefield'][$fieldname]) && count($items)) { - foreach ($items as $delta => $session_file) { - $items[$delta]['flags']['hidden'] = TRUE; - $items[$delta]['flags']['delete'] = TRUE; - } - } - } - } - } - - // Load files from preview state. before committing actions. - if (is_array($_SESSION['imagefield'][$fieldname]) && count($_SESSION['imagefield'][$fieldname])) { - foreach($_SESSION['imagefield'][$fieldname] as $delta => $file) { - $items[] = $file; + $element[$fid]['alt'] = array( + '#type' => 'hidden', + '#value' => $file['filename'], + ); + // overwrite with an input field if custom_alt is flagged; + if ($field['widget']['custom_alt']) { + $element[$fid]['alt'] = array( + '#type' => 'textfield', + '#title' => t('Alternate text'), + '#default_value' => $file['alt'], + '#description' => t('Alternate text to be displayed if the image cannot be displayed.'), + '#maxlength' => 255, + '#size' => 10, + ); } - } -} -function _imagefield_widget_form($node, $field, &$items) { - drupal_add_js('misc/progress.js'); - drupal_add_js('misc/upload.js'); + $element[$fid]['title'] = array( + '#type' => 'hidden', + '#value' => $file['filename'], + ); + // overwrite with an input field if custom_title is flagged; + if ($field['widget']['custom_title']) { + $element[$fid]['title'] = array( + '#type' => 'textfield', + '#title' => t('Title'), + '#default_value' => $file['title'], + '#description' => t('Text to be displayed on mouse overs.'), + '#maxlength' => 255, + '#size' => 10, + ); + } - $fieldname = $field['field_name']; - drupal_add_css(drupal_get_path('module', 'imagefield') .'/imagefield.css'); - - $form = array(); + elseif ($file['filepath'] && $file['flags']['hidden']) { + // Render all the form values of this item if it is hidden. + $element[$fid]['flags']['hidden'] = array('#type' => 'value', '#value' => $file['flags']['hidden']); + $element[$fid]['flags']['delete'] = array('#type' => 'value', '#value' => $file['flags']['delete']); + $element[$fid]['title'] = array('#type' => 'value', '#value' => $file['title']); + $element[$fid]['alt'] = array('#type' => 'value', '#value' => $file['alt']); + } + + if ($element['#multiple']) { + $element[$fid]['weight'] = array( + '#type' => 'weight', + '#delta' => max('10', count($element['#files'])), + ); + } - $form[$fieldname] = array( - '#type' => 'fieldset', - '#title' => t($field['widget']['label']), - '#weight' => $field['widget']['weight'], - '#collapsible' => TRUE, - '#collapsed' => FALSE, - '#tree' => TRUE, - '#prefix' => '
', - '#suffix' => '
', - ); - - $form[$fieldname]['new'] = array( - '#tree' => FALSE, - '#prefix' => '
', - '#suffix' => '
', - '#weight' => 100, - ); + $element[$fid]['filename'] = array('#type' => 'value', '#value' => $file['filename']); + $element[$fid]['filepath'] = array('#type' => 'value', '#value' => $file['filepath']); + $element[$fid]['preview'] = array('#type' => 'value', '#value' => $file['preview']); + $element[$fid]['filemime'] = array('#type' => 'value', '#value' => $file['filemime']); + $element[$fid]['filesize'] = array('#type' => 'value', '#value' => $file['filesize']); + $element[$fid]['fid'] = array('#type' => 'hidden', '#value' => $file['fid']); + } + + // Special handling for single value fields + if (!$field['multiple']) { + $element['replace'] = array( + '#type' => 'markup', + '#value' => t('If a new image is chosen, the current image will be replaced upon submitting the form.'), + ); + } - $max_images = $field['widget']['max_number_images']; - if ($field['multiple'] && $max_images && $max_images <= count($items)) { - $form[$fieldname]['#prefix'] = '
'; - $form[$fieldname]['new']['#prefix'] = '
'; - $form[$fieldname]['new']['#value'] = format_plural($max_images, 'You can only attach one image to this field. Delete the image if you wish to be able to upload a different one.', 'You can only attach @count images to this field. Delete an image if you wish to be able to upload different images.'); + $max_images = $field['multiple']; + if ($field['multiple'] && $max_images && $max_images <= count($element['#files'])) { + $element['new']['#type'] = 'markup'; + $element['new']['#value'] = format_plural($max_images, 'You can only attach one image to this field. Delete the image if you wish to be able to upload a different one.', 'You can only attach @count images to this field. Delete an image if you wish to be able to upload different images.'); } else { - // Seperate from tree becase of that silly things won't be + // Seperate from tree becase of that silly things won't be // displayed if they are a child of '#type' = form issue - $form[$fieldname]['new'][$fieldname .'_upload'] = array( + $element['new'][$fieldname .'_upload'] = array( '#type' => 'file', + '#title' => $field['widget']['label'], '#description' => $field['widget']['description'], '#tree' => FALSE, '#weight' => 9, ); - $form[$fieldname]['new']['upload'] = array( + $element['new']['upload'] = array( '#type' => 'button', '#value' => t('Upload'), - '#name' => 'cck_imagefield_'.$fieldname.'_op', - '#id' => form_clean_id($fieldname .'-attach-button'), - '#tree' => FALSE, + '#ahah' => array( + 'wrapper' => $element['#id'] .'-wrapper', + 'path' => 'imagefield/js/'. $field['type_name'] .'/'. $field['field_name'], + 'progress' => array('type' => 'bar', 'message' => t('Uploading image...')), + ), '#weight' => 10, ); - // The class triggers the js upload behaviour. - $form[$fieldname .'-attach-url'] = array('#type' => 'hidden', '#value' => url('imagefield/js', NULL, NULL, TRUE), '#attributes' => array('class' => 'upload')); } + return $element; +} - // @todo split following if block into its own function. - // Store the file data object to be carried on. - if (is_array($items) && count($items)) { - foreach($items as $delta => $file) { - if ($file['filepath'] && !$file['flags']['hidden']) { - $form[$fieldname][$delta] = array ( - '#theme' => 'imagefield_edit_image_row', - ); +/** + * Validate the widget. + */ +function _imagefield_widget_validate($element, &$form_state) { + $field = $element['#field']; + $fieldname = $field['field_name']; + $items =& $form_state['values'][$fieldname]; - $form[$fieldname][$delta]['flags']['delete'] = array( - '#type' => 'checkbox', - '#title' => t('Delete'), - '#default_value' => isset($file['flags']['delete']) ? $file['flags']['delete'] : 0, - ); - - if (function_exists('token_replace')) { - global $user; - $filename = $file['fid'] == 'upload' ? file_create_filename($file['filename'], file_create_path(token_replace($field['widget']['image_path'], 'user', $user))) : $file['filepath']; - } else { - $filename = $file['fid'] == 'upload' ? file_create_filename($file['filename'], file_create_path($field['widget']['image_path'])) : $file['filepath']; - } - - $form[$fieldname][$delta]['admin_preview'] = array( - '#type' => 'markup', - '#value' => theme('imagefield_image', $file, $file['alt'], $file['title'], array('width' => '150'), FALSE), - ); - - $form[$fieldname][$delta]['description'] = array( - '#type' => 'markup', - '#value' => '' . t('Filename: ') . '' . $file['filename'], - ); + // Allow tokenized paths. + if (function_exists('token_replace')) { + global $user; + $widget_image_path = file_directory_path() .'/'. token_replace($field['widget']['image_path'], 'user', $user); + } + else { + $widget_image_path = file_directory_path() .'/'. $field['widget']['image_path']; + } - $form[$fieldname][$delta]['alt'] = array( - '#type' => 'hidden', - '#value' => $file['filename'], - ); - // overwrite with an input field if custom_alt is flagged; - if ($field['widget']['custom_alt']) { - $form[$fieldname][$delta]['alt'] = array( - '#type' => 'textfield', - '#title' => t('Alternate text'), - '#default_value' => $file['alt'], - '#description' => t('Alternate text to be displayed if the image cannot be displayed.'), - '#maxlength' => 255, - '#size' => 10, - ); - } - - $form[$fieldname][$delta]['title'] = array( - '#type' => 'hidden', - '#value' => $file['filename'], - ); - // overwrite with an input field if custom_title is flagged; - if ($field['widget']['custom_title']) { - $form[$fieldname][$delta]['title'] = array( - '#type' => 'textfield', - '#title' => t('Title'), - '#default_value' => $file['title'], - '#description' => t('Text to be displayed on mouse overs.'), - '#maxlength' => 255, - '#size' => 10, - ); - } - - // Special handling for single value fields - if (!$field['multiple']) { - $form[$fieldname][$delta]['replace'] = array( - '#type' => 'markup', - '#value' => t('If a new image is chosen, the current image will be replaced upon submitting the form.'), - ); - } - } - elseif ($file['filepath'] && $file['flags']['hidden']) { - // Render all the form values of this item if it is hidden. - $form[$fieldname][$delta]['flags']['hidden'] = array('#type' => 'value', '#value' => $file['flags']['hidden']); - $form[$fieldname][$delta]['flags']['delete'] = array('#type' => 'value', '#value' => $file['flags']['delete']); - $form[$fieldname][$delta]['title'] = array('#type' => 'value', '#value' => $file['title']); - $form[$fieldname][$delta]['alt'] = array('#type' => 'value', '#value' => $file['alt']); + $validators = array( + 'file_validate_extensions' => array($field['widget']['file_extensions']), + 'file_validate_size' => array($field['widget']['max_filesize']), + ); + + // Attach new files. + if ($file = file_save_upload($fieldname .'_upload', $validators, $widget_image_path)) { + $file = (array)$file; + $file = _imagefield_scale_image($file, $field['widget']['max_resolution']); + $items[$file['fid']] = $file; + } + + // If a single field, mark any other images for deletion. + if (count($items)) { + foreach ($items as $delta => $item_file) { + if (!$field['multiple']) { + $items[$delta]['flags']['hidden'] = TRUE; + $items[$delta]['flags']['delete'] = TRUE; } - if (isset($file['sessionid'])) { - $form[$fieldname][$delta]['sessionid'] = array('#type' => 'value', '#value' => $file['sessionid']); + if (empty($items[$delta]['fid'])) { + unset($items[$delta]); } - $form[$fieldname][$delta]['filename'] = array('#type' => 'value', '#value' => $file['filename']); - $form[$fieldname][$delta]['filepath'] = array('#type' => 'value', '#value' => $file['filepath']); - $form[$fieldname][$delta]['preview'] = array('#type' => 'value', '#value' => $file['preview']); - $form[$fieldname][$delta]['filemime'] = array('#type' => 'value', '#value' => $file['filemime']); - $form[$fieldname][$delta]['filesize'] = array('#type' => 'value', '#value' => $file['filesize']); - $form[$fieldname][$delta]['fid'] = array('#type' => 'value', '#value' => $file['fid']); } } - - - // Some useful info for our js callback. - $form['vid'] = array( - '#type' => 'hidden', - '#value' => $node->vid, - '#tree' => FALSE, - ); - $form['nid'] = array( - '#type' => 'hidden', - '#value' => $node->nid, - '#tree' => FALSE, - ); - $form['type'] = array( - '#type' => 'hidden', - '#value' => $node->type, - '#tree' => FALSE, - ); - - return $form; -} - -/** - * Validate the widget. - */ -function _imagefield_widget_validate($node, $field, $items) { - - if ($field['required']) { + if ($element['#required']) { // Sum all the items marked for deletion, so we can make sure the end user // isn't deleting all of the images. $deleted = 0; - foreach($items as $item) { - if ($item['flags']['delete']) { + foreach ($items as $delta => $item) { + if (is_numeric($delta) && $item['flags']['delete']) { $deleted++; } } - if (!count($items)) { - form_set_error($field['field_name'], $field['widget']['label'] .' is required. Please upload an image.'); + if (!count($items)) { + form_set_error($field['field_name'], t('%field is required. Please upload an image.', array('%field' => $field['widget']['label']))); } else if (count($items) == $deleted ) { - form_set_error($field['field_name'], $field['widget']['label'] .' is required. Please uncheck at least one delete checkbox or upload another image.'); + form_set_error($field['field_name'], t('%field is required. Please uncheck at least one delete checkbox or upload another image.', array('%field' => $field['widget']['label']))); } } -} -function _imagefield_widget_upload_validate($node, $field, $items, $file) { - // initialize our validation state, innocent until proven guilty. - $valid = TRUE; - - // do we even need to test file extensions? - if (!empty($field['widget']['file_extensions'])) { - // pop out the extensions and turn file_extensions into an array. - $ext = strtolower(array_pop(explode('.', $file['filename']))); - $allowed_extensions = array_unique(explode(' ', strtolower(trim($field['widget']['file_extensions'])))); - // is it the file extension in the allowed_extensions array? - if (!in_array($ext, $allowed_extensions)) { - // sorry no.. - form_set_error($field['field_name'], t('Files with the extension %ext are not allowed. Please upload a file with an extension from the following list: %allowed_extensions', array('%ext' => $ext, '%allowed_extensions' => $field['widget']['file_extensions']))); - $valid = FALSE; - } - } - - // If max filesize is set - if (!empty($field['widget']['max_filesize'])) { - if ($file['filesize'] > ($field['widget']['max_filesize'] * 1024)) { - form_set_error($field['field_name'], t('The file you uploaded has a filesize greater than the maximum allowed filesize of %sizekb.', array('%size' => $field['widget']['max_filesize']))); - $valid = FALSE; - } - } - - // is the mime type a match for image. - if (strpos($file['filemime'], 'image/') !== 0) { - // sorry no it isn't. do not pass go, do not collect $200. - form_set_error($field['field_name'], t('Mime Type mismatch. Only image files may be upload. You uploaded a file with mime type: %mime', array('%mime' => $file['filemime']))); - $valid = FALSE; - } - - // If max number of images is set - if ($field['multiple'] && !empty($field['widget']['max_number_images'])) { - $count = count($items) + count($_SESSION['imagefield'][$field['field_name']]); - if ($count >= $field['widget']['max_number_images']) { - form_set_error($field['field_name'], t('You are only allowed to upload up to %maximages images.', array('%maximages' => $field['widget']['max_number_images']))); - $valid = FALSE; - } + // Prevent more than the maximum limit. + if ($field['multiple'] > 0 && count($items) > $field['multiple']) { + form_set_error($field['field_name']['new'], t('You are only allowed to upload up to %maximages images.', array('%maximages' => $field['widget']['max_number_images']))); } - return $valid; + $form_state['rebuild'] = TRUE; } - /** * Implementation of hook_field_formatter_info(). */ function imagefield_field_formatter_info() { $formatters = array( 'default' => array( - 'label' => 'Default', + 'label' => t('Default'), 'field types' => array('image'), ), ); return $formatters; } -/** - * Implementation of hook_field_formatter(). - * - */ -function imagefield_field_formatter($field, $item, $formatter, $node = NULL) { - if (empty($item['fid']) && $field['use_default_image']) { - $item = $field['default_image']; - } - // If there is no image on the database, use default. - if (empty($item['filepath'])) { - $item = array_merge($item, _imagefield_file_load($item['fid'])); - } - if (!empty($item['filepath'])) { - return theme('imagefield_image', $item, $item['alt'], $item['title']); - } -} - - function _imagefield_file_load($fid = NULL) { // Don't bother if we weren't passed and fid. - if (!empty($fid) && is_numeric($fid)) { + if (!empty($fid) && is_numeric($fid)) { $result = db_query('SELECT * FROM {files} WHERE fid = %d', $fid); $file = db_fetch_array($result); if ($file) { @@ -888,13 +667,103 @@ function _imagefield_file_load($fid = NU return array(); } +/** + * Implementation of hook_theme(). + */ +function imagefield_theme() { + return array( + 'imagefield_view_image' => array( + 'arguments' => array('file' => NULL, 'alt' => '', 'title' => '', 'attributes' => NULL, 'getsize' => TRUE), + ), + 'imagefield_edit_image_row' => array( + 'arguments' => array('element' => NULL), + ), + 'imagefield_image' => array( + 'arguments' => array('file' => NULL, 'alt' => '', 'title' => '', 'attributes' => NULL, 'getsize' => TRUE), + ), + 'imagefield' => array( + 'arguments' => array('element' => NULL), + ), + 'imagefield_row' => array( + 'arguments' => array('element' => NULL), + ), + 'imagefield_formatter_default' => array( + 'arguments' => array('element' => NULL), + ), + ); +} + +/** + * Theme function for 'default' text field formatter. + */ +function theme_imagefield_formatter_default($element) { + $item = $element['#item']; + + // Load the complete file if a filepath is not available. + if (!empty($item['fid']) && empty($item['filepath'])) { + $item = array_merge($item, _imagefield_file_load($item['fid'])); + } + if (!empty($item['filepath'])) { + return theme('imagefield_image', $item, $item['alt'], $item['title']); + } +} + function theme_imagefield_view_image($file, $alt = '', $title = '', $attributes = NULL, $getsize = TRUE) { return theme('imagefield_image', $file, $alt, $title, $attributes , $getsize); } +/** + * FormAPI theme function. Theme the output of an image field. + */ +function theme_imagefield(&$element) { + $output = ''; + + // Always add tabledrag in case a table is created after uploads. + if ($element['#multiple']) { + drupal_add_tabledrag($element['#id'] .'-table', 'order', 'sibling', $element['#id'] .'-weight'); + } + + // Print out the existing images. + if ($element['#multiple'] && !empty($element['#files'])) { + $rows = array(); + foreach ($element['#files'] as $fid => $file) { + $element[$fid]['weight']['#attributes']['class'] = isset($element[$fid]['weight']['#attributes']['class']) ? ($element[$fid]['weight']['#attributes']['class'] .' '. $element['#id'] .'-weight') : $element['#id'] .'-weight'; + + $row = array(); + $row[] = array('data' => '', 'class' => 'content-multiple-drag'); + $row[] = theme('imagefield_row', $element[$fid]); + $row[] = drupal_render($element[$fid]['weight']); + $rows[] = array('data' => $row, 'class' => 'draggable'); + } + + $table = theme('table', array(), $rows, array('id' => $element['#id'] .'-table')); + $table_element = array( + '#type' => 'element', + '#title' => $element['#title'], + '#required' => $element['#required'], + ); + $output .= theme('form_element', $table_element, $table); + unset($element['new'][$element['#field']['field_name'] .'_upload']['#title']); + } + elseif (!empty($element['#files'])) { + $fid = array_shift(array_keys($element['#files'])); + $output .= theme('imagefield_row', $element[$fid]); + } + else { + $element['new'][$element['#field']['field_name'] .'_upload']['#required'] = $element['#required']; + } + + // Additional image information and upload controls. + if (isset($element['replace'])) { + $output .= '
'. drupal_render($element['replace']) .'
'; + } + $output .= drupal_render($element['new']); + $output = '
'. $output .'
'; + return $output; +} -function theme_imagefield_edit_image_row($element) { +function theme_imagefield_row($element) { $output = '
'. drupal_render($element['admin_preview']) .'
'; $output .= '
'; $output .= '
'. drupal_render($element['flags']) .'
'; @@ -902,47 +771,34 @@ function theme_imagefield_edit_image_row $output .= '
'; $output .= drupal_render($element['alt']); $output .= drupal_render($element['title']); + $output .= drupal_render($element['fid']); $output .= '
'; - //$output .= '
'. $element['fid']['#value'] .'
'; - $output = '
'. $output .'
'; if (isset($element['replace'])) { $output .= '
'. drupal_render($element['replace']) .'
'; } - return $output; + return $output; } function theme_imagefield_image($file, $alt = '', $title = '', $attributes = NULL, $getsize = TRUE) { $file = (array)$file; - if (!is_file($file['filepath'])) { + if (!is_file($file['filepath'])) { return; } if (!$getsize || (list($width, $height, $type, $image_attributes) = @getimagesize($file['filepath']))) { $attributes = drupal_attributes($attributes); - $path = ($file['fid'] == 'upload') ? $file['preview'] : $file['filepath']; $alt = empty($alt) ? $file['alt'] : $alt; $title = empty($title) ? $file['title'] : $title; - $url = file_create_url($path); + $url = file_create_url($file['filepath']); return ''.
         check_plain($alt) .''; } } /** - * formats an array of images. - * @param images - * array of individually themed images - * @return - * html string - */ -function theme_imagefield_multiple($images) { - return implode("\n", $images); -} - -/** * implementation of hook_filedownload * replicated from upload.module. * - * conditionally included since we're just replicating the + * conditionally included since we're just replicating the * work of upload.module for now. */ @@ -988,53 +844,31 @@ if (!function_exists('upload_file_downlo /** * Menu-callback for JavaScript-based uploads. */ -function imagefield_js() { - // Parse fieldname from submit button. - $matches = array(); - foreach(array_keys($_POST) as $key) { - if (preg_match('/cck_imagefield_(.*)_op/', $key, $matches)) { - break; - } - } - $fieldname = $matches[1]; - - - $node = (object)$_POST; - // Load field data. - $field = content_fields($fieldname, $node->type); - +function imagefield_js($node_type, $fieldname) { + $field = content_fields($fieldname, $node_type); - // Load fid's stored by content.module - $items = array(); - $values = content_field('load', $node, $field, $items, FALSE, FALSE); - $items = $values[$fieldname]; - - // Load additional field data - imagefield_field('load', $node, $field, $items, FALSE, FALSE); + $form_state = array('values' => $_POST); + $form_state['values'][$fieldname] = isset($form_state['values'][$fieldname]) ? $form_state['values'][$fieldname] : array(); - // Handle uploads and validation. - _imagefield_widget_prepare_form_values($node, $field, $items); - _imagefield_widget_validate($node, $field, $items); - - if(is_array($node->{$fieldname}) && count($node->{$fieldname}) > 0) { - foreach($node->{$fieldname} as $key => $image) { - // Set the alt and title from POST - $items[$key]['alt'] = $image['alt']; - $items[$key]['title'] = $image['title']; - $items[$key]['flags']['delete'] = $image['flags']['delete']; - } - } - - // Get our new form baby, yeah tiger, get em! - $form = _imagefield_widget_form($node, $field, $items); - - foreach (module_implements('form_alter') as $module) { - $function = $module .'_form_alter'; - $function('imagefield_js', $form); - } - $form = form_builder('imagefield_js', $form); + // Load in the form cache. + $form = form_get_cache($_POST['form_build_id'], $form_state); - $output = theme('status_messages') . drupal_render($form); + // Handle new uploads. + _imagefield_widget_validate($form[$fieldname], $form_state); + + // Add the new element to the stored form and form_state then resave. + $form[$fieldname] = imagefield_widget($form, $form_state, $field, $form_state['values'][$fieldname]); + $form_state['storage'][$fieldname] = $form_state['values'][$fieldname]; + form_set_cache($_POST['form_build_id'], $form, $form_state); + + // Render the form for output. + $form['#post'] = $_POST; + $form['#programmed'] = TRUE; + $form_state['submitted'] = FALSE; + + drupal_alter('form', $form, $form_state, 'imagefield_js'); + $form = form_builder('imagefield_js', $form, $form_state); + $output = theme('status_messages') . drupal_render($form[$fieldname]); // We send the updated file attachments form. print drupal_to_js(array('status' => TRUE, 'data' => $output));