/[drupal]/contributions/modules/comment_upload/comment_upload.module
ViewVC logotype

Contents of /contributions/modules/comment_upload/comment_upload.module

Parent Directory Parent Directory | Revision Log Revision Log | View Revision Graph Revision Graph


Revision 1.7 - (show annotations) (download) (as text)
Thu Aug 7 07:41:30 2008 UTC (15 months, 3 weeks ago) by heine
Branch: MAIN
CVS Tags: HEAD
Branch point for: DRUPAL-6--1
Changes since 1.6: +501 -227 lines
File MIME type: text/x-php
#197015 - Initial rewrite of comment_upload for Drupal 6.x.
1 <?php
2 // $Id$
3
4 /**
5 * @file
6 * Provides file attachment functionality for comments.
7 *
8 * Written by Heine Deelstra. Copyright (c) 2008 by Ustima (http://ustima.com). All rights reserved.
9 *
10 * This module is licensed under GPL v2. See LICENSE.txt for more information.
11 */
12
13 /**
14 * @todo private file system support.
15 * @todo Single file attachments.
16 * @todo Inline images.
17 * @todo React to content type changes
18 */
19
20
21 /**
22 * Implementation of hook_menu().
23 */
24 function comment_upload_menu() {
25 $items = array();
26
27 $items['comment-upload/js'] = array(
28 'type' => MENU_CALLBACK,
29 'page callback' => 'comment_upload_js',
30 'access arguments' => array('upload files to comments'),
31 );
32
33 return $items;
34 }
35
36 /**
37 * Implementation of hook_perm().
38 */
39 function comment_upload_perm() {
40 return array('upload files to comments');
41 }
42
43 function comment_upload_theme() {
44 return array(
45 'comment_upload_attachments' => array(
46 'arguments' => array('files' => NULL),
47 ),
48 'comment_upload_form_current' => array(
49 'arguments' => array('form' => NULL),
50 ),
51 'comment_upload_form_new' => array(
52 'arguments' => array('form' => NULL),
53 ),
54 );
55 }
56
57
58 /**
59 * Add an Attachments for comments setting to the content type settings forms.
60 *
61 * Implementation of hook_form_alter().
62 */
63 function comment_upload_form_alter(&$form, $form_state, $form_id) {
64 if ($form_id == 'node_type_form' && isset($form['identity']['type'])) {
65 $form['comment']['comment_upload'] = array(
66 '#type' => 'radios',
67 '#title' => t('Attachments on comments'),
68 '#default_value' => variable_get('comment_upload_'. $form['#node_type']->type, 1),
69 '#options' => array(t('Disabled'), t('Enabled')), '#weight' => 20,
70 );
71 }
72 }
73
74
75 /**
76 * Hook into the comment_form to support file uploads.
77 *
78 * Implementation of hook_form_form-id_alter().
79 */
80 function comment_upload_form_comment_form_alter(&$form, &$form_state) {
81
82 if (!user_access('upload files to comments')) {
83 return;
84 }
85
86 // Check whether attachments are enabled for comments on this content type.
87 $node = node_load($form['nid']['#value']);
88 if (!variable_get('comment_upload_'. $node->type, 0)) {
89 return;
90 }
91
92 $files = array();
93 $cid = $form['cid']['#value'];
94
95 // Rebuild indicates whether we have a pristine form (FALSE) or one that has been trough validation -> submission once.
96 if (empty($form_state['rebuild'])) {
97 if ($cid) {
98 // Attempt to load files for an existing comment.
99 $files = comment_upload_load_files($cid);
100 }
101 $form_state['storage']['comment_upload_files'] = $files;
102 }
103 else {
104 // Using the Attach button without JS does not generate a preview.
105
106 // Rape the comment form.
107 // Comment_form was not build to rebuild a form an fetch values from $form_state.
108 // To preserve changes made by the user, we build the part of the form we just received,
109 // mapping $_POST values to #default_values.
110 // Because rebuild is TRUE, $_POST has been validated. Nevertheless this is insane.
111 $form['#post'] = $_POST;
112 unset($form['#post']['op']);
113 $build_form = form_builder('comment_form', $form, $state);
114 comment_upload_value_to_default($build_form, $form);
115
116 if (isset($form_state['values']['files'])) {
117 $files = $form_state['values']['files'];
118 }
119 }
120
121 $form['attachments'] = array(
122 '#type' => 'fieldset',
123 '#access' => user_access('upload files'), // TODO: Change perm.
124 '#title' => t('File attachments'),
125 '#collapsible' => TRUE,
126 '#collapsed' => count($files) == 0,
127 '#description' => t('Changes made to the attachments are not permanent until you save this post. The first "listed" file will be included in RSS feeds.'),
128 '#prefix' => '<div class="attachments">',
129 '#suffix' => '</div>',
130 );
131
132 // Wrapper for fieldset contents (used by ahah.js).
133 $form['attachments']['wrapper'] = array(
134 '#prefix' => '<div id="attach-wrapper">',
135 '#suffix' => '</div>',
136 );
137
138 $form['attachments']['wrapper'] += comment_upload_upload_form($files);
139 $form['#attributes']['enctype'] = 'multipart/form-data';
140
141 $form['store_file_information'] = array(
142 '#type' => 'value',
143 '#value' => $files,
144 );
145
146 // Comment_form dynamically adds buttons such as preview / save in the
147 // formbuilder. As the attachment fieldset contains an AHAH element, the
148 // #cache property of the form will be set to TRUE and the formbuilder will
149 // no longer be called. Therefore, comment_upload needs to implement preview
150 // functionality as well.
151
152 $form['preview'] = array(
153 '#type' => 'submit',
154 '#value' => t('Preview'),
155 '#submit' => array('comment_upload_comment_form_intermittent_submit'),
156 '#weight' => 20,
157 );
158
159 $form['#submit'] = array('comment_upload_comment_form_submit', 'comment_form_submit');
160
161 }
162
163 /*
164 * Listen to node deletion and delete files from comments on that node.
165 *
166 * (comment_nodeapi does not call comment APIs when deleting).
167 *
168 * Implementation of hook_nodeapi().
169 */
170 function comment_upload_nodeapi(&$node, $op, $arg = 0) {
171 if ($op == 'delete') {
172 $result = db_query("SELECT fid, nid, filepath FROM {comment_upload} cu INNER JOIN {files} f ON cu.fid = f.fid WHERE cu.nid = %d", $node->nid);
173 while ($row = db_fetch_array($result)) {
174 // comment_upload_delete_file just needs a filepath and a fid.
175 comment_upload_delete_file($row);
176 }
177 }
178 }
179
180 /**
181 * Traverse a build form and #value to corresponding #default_values in an unbuild form.
182 *
183 * @param array $build_form
184 * @param array $form
185 */
186 function comment_upload_value_to_default($build_form, &$form) {
187 if (!is_array($build_form)) {
188 return;
189 }
190 foreach (element_children($build_form) as $key) {
191 if (isset($form[$key]) && isset($build_form[$key]['#value'])) {
192 $form[$key]['#default_value'] = $build_form[$key]['#value'];
193 }
194 comment_upload_value_to_default($build_form[$key], $form[$key]);
195 }
196 }
197
198 /**
199 * Build the section of the upload_form that holds the attachments table and upload element.
200 *
201 * @param array $files
202 * @return array
203 */
204 function comment_upload_upload_form($files = array()) {
205
206 $form = array('#theme' => 'comment_upload_form_new');
207
208 if (!empty($files) && is_array($files)) {
209 $count = count($files);
210 $form['files']['#theme'] = 'comment_upload_form_current';
211 $form['files']['#tree'] = TRUE;
212
213 foreach ($files as $key => $file) {
214 $file = (object) $file;
215 $form['files'][$key] = comment_upload_create_file_element($file, $count);
216 }
217 }
218
219 $limits = _upload_file_limits($GLOBALS['user']);
220 $form['new']['upload'] = array(
221 '#type' => 'file',
222 '#title' => t('Attach new file'),
223 '#size' => 40,
224 '#description' => ($limits['resolution'] ? t('Images are larger than %resolution will be resized. ', array('%resolution' => $limits['resolution'])) : '') . t('The maximum upload size is %filesize. Only files with the following extensions may be uploaded: %extensions. ', array('%extensions' => $limits['extensions'], '%filesize' => format_size($limits['file_size']))),
225 );
226 $form['new']['attach'] = array(
227 '#type' => 'submit',
228 '#value' => t('Attach'),
229 '#name' => 'attach',
230 '#ahah' => array(
231 'path' => 'comment-upload/js',
232 'wrapper' => 'attach-wrapper',
233 'progress' => array('type' => 'bar', 'message' => t('Please wait...')),
234 ),
235 '#submit' => array('comment_upload_comment_form_attach_submit'),
236 );
237 return $form;
238 }
239
240 /**
241 * Create the form elements for one file in the attachments table.
242 *
243 * @param object $file
244 * @param integer $count
245 * @return array
246 */
247 function comment_upload_create_file_element($file, $count) {
248 $element = array();
249
250 $description = "<small>". check_plain(file_create_url($file->filepath)) ."</small>";
251
252 $element['description'] = array('#type' => 'textfield', '#default_value' => !empty($file->description) ? $file->description : $file->filename, '#maxlength' => 256, '#description' => $description );
253 $element['size'] = array('#value' => format_size($file->filesize));
254 $element['remove'] = array('#type' => 'checkbox', '#default_value' => !empty($file->remove));
255 $element['list'] = array('#type' => 'checkbox', '#default_value' => $file->list);
256 $element['weight'] = array('#type' => 'weight', '#delta' => $count, '#default_value' => $file->weight);
257 $element['filename'] = array('#type' => 'value', '#value' => $file->filename);
258 $element['filepath'] = array('#type' => 'value', '#value' => $file->filepath);
259 $element['filemime'] = array('#type' => 'value', '#value' => $file->filemime);
260 $element['filesize'] = array('#type' => 'value', '#value' => $file->filesize);
261 $element['fid'] = array('#type' => 'value', '#value' => $file->fid);
262 $element['new'] = array('#type' => 'value', '#value' => FALSE);
263 return $element;
264 }
265
266 /**
267 * Implementation of hook_comment().
268 */
269 function comment_upload_comment(&$a1, $op) {
270
271 switch ($op) {
272 case 'insert':
273 case 'update':
274 comment_upload_save($a1);
275 break;
276 case 'delete':
277 comment_upload_comment_delete($a1);
278 break;
279 case 'view':
280 comment_upload_comment_view($a1);
281 break;
282 }
283 }
284
285 /**
286 * Remove files when the comment is deleted.
287 *
288 * @param object $comment
289 */
290 function comment_upload_comment_delete($comment) {
291 $files = comment_upload_load_files($comment->cid);
292 if (!empty($files)) {
293 foreach ($files as $fid => $file) {
294 comment_upload_delete_file($file);
295 }
296 }
297 }
298
299 /**
300 * Add attachments to the comment on view or preview.
301 *
302 * @param object $comment
303 */
304 function comment_upload_comment_view(&$comment) {
305
306 if (isset($comment->files)) {
307 $files = $comment->files;
308 }
309 else {
310 $files = comment_upload_load_files($comment->cid);
311 }
312
313 if (isset($files) && count($files)) {
314 $comment->comment .= theme('comment_upload_attachments', $files);
315 }
316 }
317
318 /**
319 * Save the changes made to attachments.
320 *
321 * @param array $comment
322 */
323 function comment_upload_save($comment) {
324 if (!user_access('upload files to comments')) {
325 return;
326 }
327
328 if (!isset($comment['files']) || !is_array($comment['files'])) {
329 return;
330 }
331
332 foreach ($comment['files'] as $fid => $file) {
333 if (!empty($file['remove'])) {
334 comment_upload_delete_file($file);
335 }
336
337 // Later: make this nicer: add a 'new' flag for new files.
338 if (!empty($file['new'])) {
339
340 db_query("INSERT INTO {comment_upload} (fid, cid, nid, list, description, weight) VALUES (%d, %d, %d, %d, '%s', %d)", $fid, $comment['cid'], $comment['nid'], $file['list'], $file['description'], $file['weight']);
341
342 $file = (object)$file;
343 file_set_status($file, FILE_STATUS_PERMANENT);
344 }
345 else {
346 db_query("UPDATE {comment_upload} SET list = %d, description = '%s', weight = %d WHERE fid = %d", $file['list'], $file['description'], $file['weight'], $fid);
347 }
348 }
349 }
350
351 /**
352 * React to the Attach button; update file information on AHAH request.
353 *
354 */
355 function comment_upload_js() {
356 $cached_form_state = array();
357
358 if (!$stored_form = form_get_cache($_POST['form_build_id'], $cached_form_state)) {
359 exit();
360 }
361
362 $form_state = array('values' => $_POST, 'storage' => $cached_form_state['storage']);
363
364 comment_upload_process_files($stored_form, $form_state);
365
366 foreach ($form_state['values']['files'] as $fid => $file) {
367 $files[$fid] = $form_state['storage']['comment_upload_files'][$fid];
368 }
369
370 $upload_form = comment_upload_upload_form($files);
371
372 $stored_form['attachments']['wrapper'] = array_merge($stored_form['attachments']['wrapper'], $upload_form);
373 $cached_form_state['storage']['comment_upload_files'] = $form_state['storage']['comment_upload_files'];
374
375 form_set_cache($_POST['form_build_id'], $stored_form, $cached_form_state);
376
377 foreach ($files as $fid => $file) {
378 if (is_numeric($fid)) {
379 $upload_form['files'][$fid]['description']['#default_value'] = $form_state['values']['files'][$fid]['description'];
380 $upload_form['files'][$fid]['list']['#default_value'] = isset($form_state['values']['files'][$fid]['list']) ? 1 : 0;
381 $upload_form['files'][$fid]['remove']['#default_value'] = isset($form_state['values']['files'][$fid]['remove']) ? 1 : 0;
382 $upload_form['files'][$fid]['weight']['#default_value'] = $form_state['values']['files'][$fid]['weight'];
383 }
384 }
385
386 // Render the form for output.
387 $upload_form += array(
388 '#post' => $_POST,
389 '#programmed' => FALSE,
390 '#tree' => FALSE,
391 '#parents' => array(),
392 );
393
394 drupal_alter('form', $upload_form, array(), 'comment_upload_js');
395
396 $form_state = array('submitted' => FALSE);
397
398 $build_form = form_builder('comment_upload_js', $upload_form, $form_state);
399 $output = theme('status_messages') . drupal_render($build_form);
400
401 // We send the updated file attachments form.
402 // Don't call drupal_json(). ahah.js uses an iframe and
403 // the header output by drupal_json() causes problems in some browsers.
404 print drupal_to_js(array('status' => TRUE, 'data' => $output));
405 exit();
406 }
407
408 /**
409 * Process file uploads.
410 *
411 * @param array $form
412 * @param array $form_state
413 */
414 function comment_upload_process_files($form, &$form_state) {
415
416 $limits = _upload_file_limits($GLOBALS['user']);
417 $validators = array(
418 'file_validate_extensions' => array($limits['extensions']),
419 'file_validate_image_resolution' => array($limits['resolution']),
420 'file_validate_size' => array($limits['file_size'], $limits['user_size']),
421 );
422
423 // Save new file uploads.
424 if (user_access('upload files to comments') && ($file = file_save_upload('upload', $validators, file_directory_path()))) {
425 $file->list = variable_get('upload_list_default', 1);
426 $file->description = $file->filename;
427 $file->weight = 0;
428 if (!isset($form_state['values']['files'][$file->fid]['filepath'])) {
429 $form_state['values']['files'][$file->fid] = (array)$file;
430 $file->new = TRUE;
431 $form_state['storage']['comment_upload_files'][$file->fid] = (array) $file;
432 }
433 }
434 else {
435 // If no file has been entered, we have an upload element in files.
436 unset($form_state['values']['files']['upload']);
437 }
438
439 if (isset($form_state['values']['files'])) {
440 foreach ($form_state['values']['files'] as $fid => $file) {
441 $form_state['values']['files'][$fid]['new'] = !empty($form_state['storage']['comment_upload_files'][$fid]['new']) ? TRUE : FALSE;
442 }
443 }
444
445 // Order the form according to the set file weight values.
446 if (!empty($form_state['values']['files'])) {
447 $microweight = 0.001;
448 foreach ($form_state['values']['files'] as $fid => $file) {
449 if (is_numeric($fid)) {
450 $form_state['values']['files'][$fid]['#weight'] = $file['weight'] + $microweight;
451 $microweight += 0.001;
452 }
453 }
454 uasort($form_state['values']['files'], 'element_sort');
455 }
456
457 }
458
459 /**
460 * Additional submit handler for the comment form.
461 *
462 * @param array $form
463 * @param array $form_state
464 */
465 function comment_upload_comment_form_submit($form, &$form_state) {
466 comment_upload_process_files($form, $form_state);
467 unset($form_state['storage']);
468 }
469
470 /**
471 * Submit handler for the preview and attach button.
472 *
473 * @param array $form
474 * @param array $form_state
475 */
476 function comment_upload_comment_form_intermittent_submit($form, &$form_state) {
477 comment_upload_process_files($form, $form_state);
478 $form_state['rebuild'] = TRUE;
479 return;
480 }
481
482
483 /**
484 * Theme the attachments list.
485 *
486 * Taken from upload.module.
487 *
488 * @ingroup themeable
489 */
490 function theme_comment_upload_form_current(&$form) {
491 $header = array('', t('Delete'), t('List'), t('Description'), t('Weight'), t('Size'));
492 drupal_add_tabledrag('comment-upload-attachments', 'order', 'sibling', 'comment-upload-weight');
493
494 foreach (element_children($form) as $key) {
495 // Add class to group weight fields for drag and drop.
496 $form[$key]['weight']['#attributes']['class'] = 'comment-upload-weight';
497
498 $row = array('');
499 $row[] = drupal_render($form[$key]['remove']);
500 $row[] = drupal_render($form[$key]['list']);
501 $row[] = drupal_render($form[$key]['description']);
502 $row[] = drupal_render($form[$key]['weight']);
503 $row[] = drupal_render($form[$key]['size']);
504 $rows[] = array('data' => $row, 'class' => 'draggable');
505 }
506 $output = theme('table', $header, $rows, array('id' => 'comment-upload-attachments'));
507 $output .= drupal_render($form);
508 return $output;
509 }
510
511 function theme_comment_upload_form_new($form) {
512 drupal_add_tabledrag('comment=upload-attachments', 'order', 'sibling', 'comment-upload-weight');
513 $output = drupal_render($form);
514 return $output;
515 }
516
517 function theme_comment_upload_attachments($files) {
518 $header = array(t('Attachment'), t('Size'));
519 $rows = array();
520
521 foreach ($files as $file) {
522 $file = (object)$file;
523 if ($file->list && empty($file->remove)) {
524 $href = file_create_url($file->filepath);
525 $text = $file->description ? $file->description : $file->filename;
526 $rows[] = array(l($text, $href), format_size($file->filesize));
527 }
528 }
529 if (count($rows)) {
530 return theme('table', $header, $rows, array('id' => 'attachments'));
531 }
532 }
533
534 /**
535 * Load attachments that belong to the comment.
536 *
537 * @param integer $cid
538 * @return array
539 */
540 function comment_upload_load_files($cid) {
541 $files = array();
542
543 $result = db_query('SELECT * FROM {files} f INNER JOIN {comment_upload} cu ON f.fid = cu.fid WHERE cu.cid = %d ORDER BY cu.weight, f.fid', $cid);
544 while ($file = db_fetch_array($result)) {
545 $files[$file['fid']] = $file;
546 }
547 return $files;
548 }
549
550 /**
551 * Delete a file and its associated records.
552 *
553 * @param array $file
554 */
555 function comment_upload_delete_file($file) {
556 file_delete($file['filepath']);
557 db_query('DELETE FROM {files} WHERE fid = %d', $file['fid']);
558 db_query("DELETE FROM {comment_upload} WHERE fid = %d", $file['fid']);
559 }

  ViewVC Help
Powered by ViewVC 1.1.2