Index: imagefield.css =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/imagefield/imagefield.css,v retrieving revision 1.2.4.1 diff -u -r1.2.4.1 imagefield.css --- imagefield.css 17 Dec 2007 04:47:05 -0000 1.2.4.1 +++ imagefield.css 11 Apr 2008 12:18:35 -0000 @@ -1,9 +1,3 @@ -div.imagefield-edit-image-row { - border: 1px solid #e5e5e5; - padding: 5px; - margin-bottom: 10px; -} - div.imagefield-edit-preview img { border: 1px solid #e5e5e5; } Index: imagefield.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/imagefield/imagefield.module,v retrieving revision 1.30.2.6.2.49 diff -u -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 11 Apr 2008 12:18:38 -0000 @@ -10,85 +10,17 @@ */ -function imagefield_menu($maycache) { +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, - ); - } - } - } - return $items; -} + $items['imagefield/js'] = array( + 'page callback' => 'imagefield_js', + 'access callback' => 'user_access', + 'access arguments' => array('access content'), + 'type' => MENU_CALLBACK, + ); -/** - * transfer a file that is in a 'preview' state. - * @todo multiple support - */ -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, - )); - } - } - } + return $items; } function imagefield_perm() { @@ -100,7 +32,10 @@ */ 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.') + ), ); } @@ -147,10 +82,8 @@ 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); - } + if ($file = file_save_upload('default_image_upload', file_directory_path())) { + form_set_value(array('#parents' => array('default_image')), (array) $file); } break; @@ -160,8 +93,8 @@ 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; @@ -194,6 +127,175 @@ } +/** + * Implementation of hook_content_is_empty(). + */ +function imagefield_content_is_empty($item, $field) { + return empty($item['fid']) ? TRUE : FALSE; +} + +/** + * Implementation of hook_elements(). + */ +function imagefield_elements() { + $elements = array(); + $elements['image'] = array( + '#input' => TRUE, + '#columns' => array('fid', 'title', 'alt'), + //'#after_build' => array('_imagefield_widget_prepare_form_values'), + '#process' => array('imagefield_process'), + ); + return $elements; +} + +/** + * Process the image type element before displaying the field. + */ +function imagefield_process($element, $edit, $form_state, $form) { + $field = $form['#field_info'][$element['#field_name']]; + + $fieldname = $field['field_name']; + drupal_add_css(drupal_get_path('module', 'imagefield') .'/imagefield.css'); + + $element['#type'] = 'imagefield'; + $element['#theme'] = 'imagefield'; + + // Convert default value to an array for data consistency. + if (!$element['#multiple']) { + $element['#files'] = array($element['#default_value']['fid'] = $element['#default_value']); + } + elseif (!empty($element['#default_value'])) { + $element['#files'] = array(); + foreach ($element['#default_value'] as $file) { + $element['#files'][$file['fid']] = $file; + } + } + else { + $element['#files'] = array(); + } + + // Load in any needed file information. + $placeholders = array_fill(0, count($element['#files']), "'%s'"); + $result = db_query('SELECT * FROM {files} WHERE fid IN ('. implode(',', $placeholders) .')', array_keys($element['#files'])); + while ($db_file = db_fetch_array($result)) { + $element['#files'][$db_file['fid']] = array_merge($element['#files'][$db_file['fid']], $db_file); + } + + foreach ($element['#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 (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']; + } + + $element[$fid]['admin_preview'] = array( + '#type' => 'markup', + '#value' => theme('imagefield_image', $file, $file['alt'], $file['title'], array('width' => '150'), FALSE), + ); + + $element[$fid]['description'] = array( + '#type' => 'markup', + '#value' => '' . t('Filename: ') . '' . $file['filename'], + ); + + $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, + ); + } + + $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, + ); + } + + 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'])), + ); + } + + $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' => 'value', '#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.'), + ); + } + + + // Seperate from tree becase of that silly things won't be + // displayed if they are a child of '#type' = form issue + $element['new'][$field['field_name'] .'_upload'] = array( + '#type' => 'file', + '#description' => $field['widget']['description'], + '#weight' => 9, + ); + + $element['new']['upload'] = array( + '#type' => 'button', + '#value' => t('Upload'), + '#weight' => 10, + '#ahah' => array( + 'wrapper' => $element['#id'] .'-wrapper', + 'path' => 'imagefield/js', + ), + ); + + $element['file'] = array( + '#type' => 'file', + '#title' => $field['widget']['title'], + '#description' => $field['widget']['description'], + ); + + return $element; +} + function imagefield_default_item() { return array( 'fid' => 0, @@ -297,7 +399,6 @@ } } $items = array_values($items); // compact deltas - imagefield_clear_field_session($fieldname); break; // called before content.module defaults. @@ -356,6 +457,7 @@ 'image' => array( 'label' => 'Image', 'field types' => array('image'), + 'multiple values' => CONTENT_HANDLE_MODULE, ), ); } @@ -363,7 +465,7 @@ /** * Implementation of hook_widget_settings(). */ -function imagefield_widget_settings($op, $widget) { +function imagefield_widget_settings($op, &$widget) { switch ($op) { case 'callbacks': return array('default value' => CONTENT_CALLBACK_CUSTOM); @@ -386,13 +488,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'), @@ -427,13 +522,13 @@ 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'); } } @@ -515,24 +610,21 @@ /** * Implementation of hook_widget(). */ -function imagefield_widget($op, &$node, $field, &$items) { - switch ($op) { - case 'default value': - return array(); - - case 'prepare form values': - _imagefield_widget_prepare_form_values($node, $field, $items); - return; - - case 'form': - return _imagefield_widget_form($node, $field, $items); - - case 'validate': - _imagefield_widget_validate($node, $field, $items); - return; - } -} - +function imagefield_widget(&$form, &$form_state, $field, $items, $delta = 0) { + $items = array( + array('fid' => 1, 'alt' => 'Some alt', 'title' => 'Some title'), + array('fid' => 5, 'alt' => 'Some alt 2', 'title' => 'Some title 2'), + ); + $element = array( + '#type' => $field['widget']['type'], + '#default_value' => $items, + '#multiple' => $field['multiple'], + '#image_preview' => TRUE, + '#image_alt' => $field['widget']['custom_alt'], + '#image_title' => $field['widget']['custom_title'], + ); + return $element; +} function _imagefield_widget_prepare_form_values(&$node, $field, &$items) { $fieldname = $field['field_name']; @@ -542,7 +634,7 @@ } // Attach new files - if ($file = file_check_upload($fieldname . '_upload')) { + if (FALSE && $file = file_save_upload($fieldname . '_upload')) { $file = (array)$file; // Validation must happen immediately after the image is uploaded so we @@ -567,7 +659,7 @@ $file['fid'] = 'upload'; $file['preview'] = $filepath; - // If a single field, mark any other images for deletion and delete files in session + // If a single field, mark any other images for deletion. if (!$field['multiple']) { if (is_array($items)) { foreach ($items as $delta => $session_file) { @@ -575,204 +667,13 @@ $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']); - - // 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; } } -} - -function _imagefield_widget_form($node, $field, &$items) { - drupal_add_js('misc/progress.js'); - drupal_add_js('misc/upload.js'); - - $fieldname = $field['field_name']; - drupal_add_css(drupal_get_path('module', 'imagefield') .'/imagefield.css'); - - $form = array(); - - $form[$fieldname] = array( - '#type' => 'fieldset', - '#title' => t($field['widget']['label']), - '#weight' => $field['widget']['weight'], - '#collapsible' => TRUE, - '#collapsed' => FALSE, - '#tree' => TRUE, - '#prefix' => '