Removing trailing whitespace.
[project/filefield.git] / filefield_widget.inc
CommitLineData
9412a7cc
JP
1<?php
2// $Id$
3/**
4 * @file
5 * FileField: Defines a CCK file field type.
6 *
7 * Uses content.module to store the fid and field specific metadata,
8 * and Drupal's {files} table to store the actual file data.
9 *
10 * This file contains CCK widget related functionality.
11 */
12
22e736e6 13/**
7e784adc 14 * @file
15 *
22e736e6 16 * FileField Widget Settings Hooks.
6f0f10d4
DP
17 * @todo: move description property to filefield_widget widget callbacks
18 * (filefield_widget_widget_{$op}).
22e736e6
DP
19 */
20
21function filefield_widget_settings_form($widget) {
22 $form = array();
23 $form['file_extensions'] = array(
24 '#type' => 'textfield',
25 '#title' => t('Permitted upload file extensions'),
26 '#default_value' => is_string($widget['file_extensions']) ? $widget['file_extensions'] : 'txt',
27 '#size' => 64,
28 '#description' => t('Extensions a user can upload to this field. Separate extensions with a space and do not include the leading dot. Leaving this blank will allow users to upload a file with any extension.'),
29 '#weight' => 1,
30 );
31 $form['path_settings'] = array(
32 '#type' => 'fieldset',
33 '#title' => t('Path settings'),
34 '#collapsible' => true,
35 '#collapsed' => true,
36 '#weight' => 6,
37 );
38
39 $form['path_settings']['file_path'] = array(
40 '#type' => 'textfield',
41 '#title' => t('File path'),
42 '#default_value' => is_string($widget['file_path']) ? $widget['file_path'] : '',
43 '#description' => t('Optional subdirectory within the "%dir" directory where files will be stored. Do not include trailing slash.', array('%dir' => variable_get('file_directory_path', 'files'))),
44 '#element_validate' => array('_filefield_widget_settings_file_path_validate'),
45 '#suffix' => theme('token_help', 'user'),
46 );
47
48 $form['max_filesize'] = array(
49 '#type' => 'fieldset',
50 '#title' => t('File size restrictions'),
51 '#description' => t('Limits for the size of files that a user can upload. Note that these settings only apply to newly uploaded files, whereas existing files are not affected.'),
52 '#weight' => 6,
53 '#collapsible' => TRUE,
54 '#collapsed' => TRUE,
55 );
7e784adc 56 // upload validator. @todo: consider replacing with global
d6caa409 57 // && node validate.
22e736e6
DP
58 $form['max_filesize']['max_filesize_per_file'] = array(
59 '#type' => 'textfield',
60 '#title' => t('Maximum upload size per file'),
61 '#default_value' => is_string($widget['max_filesize_per_file'])
62 ? $widget['max_filesize_per_file']
63 : '',
64 '#description' => t('Specify the size limit that applies to each file separately. Enter a value like "512" (bytes), "80K" (kilobytes) or "50M" (megabytes) in order to restrict the allowed file size. If you leave this this empty the file sizes will be limited only by PHP\'s maximum post and file upload sizes.'),
65 '#element_validate' => array('_filefield_widget_settings_max_filesize_per_file_validate'),
66 );
d6caa409
DP
67
68 // node validate.
22e736e6
DP
69 $form['max_filesize']['max_filesize_per_node'] = array(
70 '#type' => 'textfield',
71 '#title' => t('Maximum upload size per node'),
72 '#default_value' => is_string($widget['max_filesize_per_node'])
73 ? $widget['max_filesize_per_node']
74 : '',
75 '#description' => t('Specify the total size limit for all files in field on a given node. Enter a value like "512" (bytes), "80K" (kilobytes) or "50M" (megabytes) in order to restrict the total size of a node. Leave this empty if there should be no size restriction.'),
76 '#element_validate' => array('_filefield_widget_settings_max_filesize_per_node_validate'),
77 );
78 return $form;
79}
80
81function filefield_widget_settings_save($widget) {
82 return array(
83 'file_extensions', 'file_path', 'max_filesize_per_file',
84 'max_filesize_per_node', 'file_widgets'
85 );
86}
87
88function _filefield_widget_settings_file_path_validate($element, &$form_state) {
89 // Strip slashes from the beginning and end of $widget['file_path']
90 $form_state['values']['file_path'] = trim($form_state['values']['file_path'], '\\/');
91}
92
93function _filefield_widget_settings_max_filesize_per_file_validate($element, &$form_state) {
94 if (empty($form_state['values']['max_filesize_per_file'])) {
95 return; // Empty means no size restrictions, so don't throw an error.
96 }
97 else if (!is_numeric(parse_size($form_state['values']['max_filesize_per_file']))) {
98 form_error($element, t('The "Maximum file size for each file" option must contain a valid value. You can either leave the text field empty or enter a string like "512" (bytes), "80K" (kilobytes) or "50M" (megabytes).'));
99 }
100}
101
102function _filefield_widget_settings_max_filesize_per_node_validate($element, &$form_state) {
103 if (empty($form_state['values']['max_filesize_per_node'])) {
104 return; // Empty means no size restrictions, so don't throw an error.
105 }
106 else if (!is_numeric(parse_size($form_state['values']['max_filesize_per_node']))) {
107 form_error($element, t('The "Maximum file size per node" option must contain a valid value. You can either leave the text field empty or enter a string like "512" (bytes), "80K" (kilobytes) or "50M" (megabytes).'));
108 }
109}
110
8ffd8e3d
DP
111function filefield_save_upload($element) {
112 $upload_name = $element['#field_name'] .'_'. $element['#delta'];
113 $field_instance = content_fields($element['#field_name'], $element['#type_name']);
114
115 if (empty($_FILES['files']['name'][$upload_name])) {
116 return 0;
117 }
118
119 $dest = $field_instance['widget']['file_path'];
120 if (module_exists('token')) {
121 global $user;
122 $dest = token_replace($dest, 'user', $user);
123 }
124
125 $dest = file_directory_path() .'/'. $dest;
126 if (!field_file_check_directory($dest, FILE_CREATE_DIRECTORY)) {
127 watchdog('imagefield', 'The upload directory %directory for the file field %field (content type %type) could not be created or is not accessible. A newly uploaded file could not be saved in this directory as a consequence, and the upload was canceled.', array('%directory' => $dest, '%field' => $element['#field_name'], '%type' => $element['#type_name']));
128 form_set_error($upload_name, t('The file could not be uploaded.'));
129 return 0;
130 }
131
132 if (!$file = field_file_save_upload($upload_name, $element['#upload_validators'], $dest)) {
133 watchdog('imagefield', 'The file upload failed. %upload', array('%upload' => $upload_name));
134 form_set_error($upload_name, t('The Image upload failed.'));
135 return 0;
136 }
137 return $file['fid'];
138}
139
22e736e6
DP
140/**
141 * FileField widget element callbacks.
142 */
d2f124d5 143function filefield_widget_value($element, $edit = FALSE) {
7e784adc 144 if (!$edit) {
d2f124d5
DP
145 $file = field_file_load($element['#default_value']['fid']);
146 $item = $element['#default_value'];
147 }
148 else {
8ffd8e3d
DP
149 // uploads take priority over value of fid text field.
150 if ($fid = filefield_save_upload($element)) {
151 $edit['fid'] = $fid;
7e784adc 152 }
8ffd8e3d
DP
153
154 // load file.
d2f124d5
DP
155 $file = field_file_load($edit['fid']);
156 $item = array(
157 'fid' => $edit['fid'],
c147cceb 158 'list' => empty($edit['list']),
3d3b3ed1 159 'data' => empty($edit['data']) ? array() : $edit['data'],
d2f124d5
DP
160 );
161 }
8ffd8e3d 162 // merge file and item data so it is available to all widgets.
6e7782b4 163 $item = array_merge($item, $file);
1bffec9e 164
6e7782b4
DP
165 // if this widget is another type and leaning on filefield to do the dirty work....
166 // pass it back home.
167 $function = $element['#type'] .'_widget_value';
168 if (function_exists($function)) {
169 $item = array_merge($item, $function($element, $edit));
170 }
171 return $item;
d2f124d5
DP
172}
173
174function filefield_widget_process($element, $edit, &$form_state, $form) {
7e784adc 175
8ffd8e3d
DP
176 $item = $element['#value'];
177 $field_name = $element['#field_name'];
178 $delta = $element['#delta'];
179
ad6c5ff0
DP
180 $field = content_fields($element['#field_name'], $element['#type_name']);
181
8ffd8e3d
DP
182 // check remove buttons...
183 $remove_name = $element['#field_name'] .'_'. $element['#delta'] .'_remove_btn';
ad6c5ff0
DP
184 if (isset($form_state['clicked_button']) && $form_state['clicked_button']['#name'] == $remove_name) {
185 $item = _filefield_default_value($field);
8ffd8e3d 186 }
7e784adc 187
188 // figute out our fid...
8ffd8e3d 189 $element['fid'] = array('#type' => 'hidden', '#value' => $item['fid']);
d2f124d5 190
6e7782b4 191 if ($item['fid'] != 0) {
7e784adc 192 $element['preview'] = array('#type' => 'markup', '#value' => theme($element['#type'] .'_preview', $item));
d2f124d5 193 }
28b1c58e
DP
194
195 // placeholder.. will be serialized into the data column. this is a place for widgets
196 // to put additional data.
197 $element['data'] = array('#tree' => 'true');
198 $element['data']['description'] = array(
7e784adc 199 '#type' => 'textfield',
d2f124d5 200 '#title' => t('Description'),
8ffd8e3d 201 '#value' => isset($item['data']['description']) ? $item['data']['description'] : '',
d2f124d5 202 );
28b1c58e
DP
203
204 if ($field['force_list_default']) {
205 $element['list'] = array(
206 '#type' => 'hidden',
207 '#value' => $field['list_default'],
208 );
209 }
210 else {
211 $element['list'] = array(
212 '#type' => 'checkbox',
213 '#title' => t('List'),
8ffd8e3d 214 '#value' => isset($item['list']) ? $item['list'] : $field['list_default'],
28b1c58e
DP
215 '#attributes' => array('class' => 'filefield-list'),
216 );
217 }
d2f124d5 218
d2f124d5 219
8ffd8e3d
DP
220
221 foreach ($element['#upload_validators'] as $callback => $arguments) {
222 $help_func = $callback .'_help';
223 $desc[] = call_user_func_array($help_func, $arguments);
224 }
225 $element['upload'] = array(
226 '#name' => 'files['. $element['#field_name'] .'_'. $element['#delta'] .']',
227 '#type' => 'file',
228 '#title' => t('New Upload'),
229 '#description' => implode('<br />', $desc),
230 '#attributes' => array(
f976317f 231 'accept' => implode(',', array_filter(explode(' ', $field['widget']['file_extensions']))),
8ffd8e3d
DP
232 )
233 );
234
235
236 if ($item['fid'] != 0) {
237 $element['upload']['#title'] = t('Replace');
238 }
aa3a8ca0
DP
239
240 $element['#prefix'] = '<div id="'. $element['#id'] .'-ahah-wrapper" class="filefield-ahah-wrapper">';
241 $element['#suffix'] = '</div>';
8ffd8e3d 242 $element['upload_btn'] = array(
7e784adc 243 '#type' => 'submit',
8ffd8e3d 244 '#value' => t('Upload'),
aa3a8ca0 245 '#process' => array('form_expand_ahah'),
8ffd8e3d 246 '#submit' => array('node_form_submit_build_node'),
7e784adc 247 '#ahah' => array( // with JavaScript
248 'path' => 'filefield/ahah/'. $element['#type_name'] .'/'. $element['#field_name'] .'/'. $element['#delta'],
249 'wrapper' => $element['#id'] .'-ahah-wrapper',
250 'method' => 'replace',
251 'effect' => 'fade',
8ffd8e3d
DP
252 ),
253 '#field_name' => $element['#field_name'],
254 '#delta' => $element['#delta'],
255 '#type_name' => $element['#type_name'],
256 '#upload_validators' => $element['#upload_validators'],
257 );
6e7782b4 258 if ($item['fid'] != 0) {
d2f124d5 259 $element['remove_btn'] = array(
6e7782b4 260 '#name' => $element['#field_name'] .'_'. $element['#delta'] .'_remove_btn',
7e784adc 261 '#type' => 'submit',
d2f124d5 262 '#value' => t('Remove'),
8ffd8e3d 263 '#process' => array('filefield_widget_process_remove_btn', 'form_expand_ahah'),
ad6c5ff0 264 '#submit' => array('node_form_submit_build_node'),
7e784adc 265 '#ahah' => array( // with JavaScript
266 'path' => 'filefield/ahah/'. $element['#type_name'] .'/'. $element['#field_name'] .'/'. $element['#delta'],
267 'wrapper' => $element['#id'] .'-wrapper',
268 'method' => 'replace',
269 'effect' => 'fade',
6c352642 270 ),
6e7782b4
DP
271 '#field_name' => $element['#field_name'],
272 '#delta' => $element['#delta'],
d2f124d5 273 );
d2f124d5
DP
274 }
275
d2f124d5 276
d2f124d5
DP
277 return $element;
278}
279
ac83a9cf 280function filefield_widget_validate($element, &$form_state) {
1bffec9e 281
ecbb2c26 282}
1bffec9e 283
d2f124d5 284function _filefield_widget_validate($element, &$form_state) {
d2f124d5
DP
285}
286
287
d2f124d5
DP
288/**
289 * FormAPI theme function. Theme the output of an image field.
290 */
bad2b17f 291function theme_filefield_widget($element) {
c6e8be79 292 return theme('form_element', $element, $element['#children']);
d2f124d5
DP
293}
294
22e736e6 295function theme_filefield_widget_preview($item) {
c4c7e990
DP
296 return '<div class="filefield-preview clear-block">'.
297 '<div class="filename">'. theme('filefield_file', $item) .'</div>'.
298 '<div class="filesize">'. format_size($item['filesize']) .'</div>'.
299 '<div class="filemime">'. $item['filemime'] .'</div>'.
300 '</div>';
22e736e6
DP
301}
302
303function theme_filefield_widget_item($element) {
bad2b17f 304 return '<div class="filefield-row clear-block">'.
c4c7e990
DP
305 '<div class="filefield-filename clear-block">'. drupal_render($element['preview']) . '</div>'.
306 '<div class="fielfield-edit clear-block">'.
bad2b17f
DP
307 '<div class="filefield-list">'. drupal_render($element['list']) . '</div>' .
308 '<div class="filefield-description">'. drupal_render($element['description']) . '</div>' .
309 '<div class="filefield-stuff">'. drupal_render($element) .'</div>'.
310 '</div>'.
311 '</div>';
312}
d2f124d5 313
2be7e4b0
DP
314/**
315 * #require validation for filetype fields.
316 */
317
318function filefield_node_form_validate($form, &$form_state) {
2be7e4b0
DP
319 $type = content_types($form['type']['#value']);
320 foreach ($type['fields'] as $field_name => $field) {
c4c7243a 321 if (!(in_array($field['module'], array('imagefield', 'filefield'))) || !$field['required']) continue;
2be7e4b0
DP
322 $empty = $field['module'] .'_content_is_empty';
323 $valid = false;
f92ea317 324 $total_filesize = 0;
2be7e4b0
DP
325 foreach($form_state['values'][$field_name] as $delta => $item) {
326 if ($empty($item, $field)) continue;
3d3b3ed1 327 $valid = true;
f92ea317 328 $total_filesize += (int)$item['filesize'];
2be7e4b0 329 }
9412a7cc 330
f92ea317
DP
331 if (!$valid) {
332 form_set_error($field_name, t('%title field is required.', array('%title' => $field['widget']['label'])));
333 }
334 $max_filesize = parse_size($field['widget']['max_filesize_per_node']);
5af49125 335 if ($max_filesize && $total_filesize > $max_filesize) {
7e784adc 336 form_set_error($field_name, t('Total filesize for %title, %tsize, exceeds field settings of %msize.',
f92ea317 337 array(
7e784adc 338 '%title' => $field['widget']['label'],
339 '%tsize' => format_size($total_filesize),
f92ea317
DP
340 '%msize' => format_size($max_filesize)
341 )
342 ));
343 }
2be7e4b0
DP
344 }
345}
9412a7cc 346
ad6c5ff0
DP
347function filefield_node_form_submit($form, $form_state) {
348 // we ignore all but the save button here.
349 if ($form_state['values']['op'] != t('Save')) {
350 return;
351 }
352 // @todo: try to delete removed files.
353}