/[drupal]/contributions/modules/inline/inline_upload.module
ViewVC logotype

Contents of /contributions/modules/inline/inline_upload.module

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


Revision 1.13 - (show annotations) (download) (as text)
Wed Aug 12 06:21:13 2009 UTC (3 months, 2 weeks ago) by sun
Branch: MAIN
CVS Tags: HEAD
Changes since 1.12: +16 -8 lines
File MIME type: text/x-php
#172613 by sun: Added new context property to $macro objects.
1 <?php
2 // $Id: inline_upload.module,v 1.12 2009/08/12 05:54:36 sun Exp $
3
4 /**
5 * @file
6 * Inline API implementation to render uploaded attachments inline.
7 */
8
9 /**
10 * Implementation of hook_inline_info().
11 *
12 * @see hook_inline_info()
13 */
14 function inline_upload_inline_info() {
15 $info['upload'] = array(
16 'callback' => 'inline_upload_inline',
17 );
18 return $info;
19 }
20
21 /**
22 * Implementation of hook_inline().
23 *
24 * @param $op
25 * The current operation performed.
26 * @param $macro
27 * An inline macro object containing user supplied values, passed by reference.
28 */
29 function inline_upload_inline($op, &$macro) {
30 switch ($op) {
31 case 'args':
32 // Return an array of available/required tag arguments.
33 $args = array(
34 // @todo Use vid instead here?
35 'nid' => array(
36 '#title' => t('Node id'),
37 '#description' => t('A node id containing a file to render.'),
38 '#type' => 'int',
39 '#default_value' => 0,
40 ),
41 'file' => array(
42 '#title' => t('File'),
43 '#description' => t('The number or name of a file to render.'),
44 '#required' => TRUE,
45 ),
46 'title' => array(
47 '#title' => t('Title'),
48 '#description' => t('A optional title to use for the link text.'),
49 '#type' => 'string',
50 ),
51 );
52 return $args;
53
54 case 'presave':
55 // Context may be passed via inline_nodeapi().
56 if (!isset($macro->params['nid']) && !empty($macro->context['node'])) {
57 $macro->params['nid'] = $macro->context['node']->nid;
58 }
59 // Mark this tag as permanent, if we already have a node id.
60 // @todo Reverse the temporary/permanent logic; this is only used by a
61 // minority of inline macros.
62 if (!empty($macro->params['nid'])) {
63 $macro->status = 0;
64 }
65
66 // @todo The processing of the current form state is required to
67 // properly update a file's description (tooltip) during previews
68 // as well as during final saving of a node.
69 // However, this operation is only invoked when the macro is saved to
70 // the database, but not for rendering. Not sure what the common
71 // denominator of 'presave' and 'prepare' is, but it seems we need a
72 // new operation... 'prepare' => 'prerender' at least!
73 // Afterwards, use 'prepare' to perform alterations on the macro
74 // before it is processed for editing.
75
76 // Convert a (human) numeric file reference to a named one.
77 if (isset($macro->params['file']) && is_int($macro->params['file'])) {
78 // Account for new uploaded files in node preview.
79 // @see upload_js()
80 // @todo This basically works how it should. However, altered weights are
81 // applied when doing a subsequent preview only. So we may have to
82 // additionally derive the attachment weights from the form in $_POST.
83 $cached_form_state = array();
84 if (isset($_POST['form_build_id']) && ($cached_form = form_get_cache($_POST['form_build_id'], $cached_form_state)) && isset($cached_form['#node']) && isset($cached_form['attachments']['wrapper']['files'])) {
85 $files = array();
86 foreach (element_children($cached_form['attachments']['wrapper']['files']) as $fid) {
87 $element = $cached_form['attachments']['wrapper']['files'][$fid];
88 if (empty($element['remove']['#default_value'])) {
89 $file = new stdClass;
90 foreach ($element as $key => $item) {
91 $file->{$key} = (isset($item['#value']) ? $item['#value'] : $item['#default_value']);
92 }
93 $files[$fid] = $file;
94 }
95 }
96 }
97 if (isset($files)) {
98 // Humans start to count from 1.
99 $filekeys = array_keys($files);
100 if (isset($filekeys[$macro->params['file'] - 1])) {
101 $macro->params['file'] = $files[$filekeys[$macro->params['file'] - 1]]->filename;
102 }
103 }
104 }
105 return;
106
107 case 'validate':
108 // Custom validation of user supplied values.
109 return TRUE;
110
111 case 'prepare':
112 // Prepare user supplied values for rendering.
113 if ($macro->params['nid'] == 0) {
114 // Insert some tricky code to insert current node id here. 02/02/2008 sun
115 if (arg(0) == 'node' && is_numeric(arg(1))) {
116 $macro->params['nid'] = (int)arg(1);
117 }
118 }
119 // Load a node object if valid nid is given.
120 if ($macro->params['nid'] > 0) {
121 $node = node_load($macro->params['nid']);
122 if (node_access('view', $node)) {
123 $macro->upload['node'] = $node;
124 }
125 }
126 return;
127
128 case 'render':
129 // Return a rendered representation to replace a tag.
130 if (!isset($macro->upload['node'])) {
131 return;
132 }
133 // Find the referenced file.
134 foreach ($macro->upload['node']->files as $node_file) {
135 if ($node_file->filename == $macro->params['file']) {
136 $file = $node_file;
137 break;
138 }
139 }
140 if (isset($file)) {
141 // Alter the file object on node previews.
142 inline_upload_prepare_file_object($file);
143
144 if (!empty($macro->params['title'])) {
145 $file->title = $macro->params['title'];
146 }
147 // Decide whether to show a link or an image tag.
148 if (_inline_upload_decide_img_tag($file)) {
149 // @todo Provide different rendering options for images, i.e.
150 // imagecache presets. Seems like we can't support different presets
151 // for teaser and page view anymore. :-(
152 // Only hook_nodeapi($op = view|alter) provides $node->build_mode.
153 $output = theme('inline_upload_img', $file, '');
154 }
155 else {
156 $output = theme('inline_upload_as_link', $file);
157 }
158 }
159 else {
160 $output = '<span style="color: red; font-weight: bold;">NOT FOUND: '. $macro->params['file'] .'</span>';
161 }
162 return $output;
163 }
164 }
165
166 /**
167 * Implementation of hook_theme().
168 */
169 function inline_upload_theme() {
170 return array(
171 'inline_upload_as_link' => array(
172 'arguments' => array('file' => NULL),
173 ),
174 'inline_upload_img' => array(
175 'arguments' => array('file' => NULL, 'field' => NULL),
176 ),
177 'inline_upload_prepend_to_field' => array(
178 'arguments' => array('node' => NULL, 'file' => NULL, 'field' => NULL),
179 ),
180 );
181 }
182
183 /**
184 * Implementation of hook_menu().
185 */
186 function inline_upload_menu() {
187 $items['admin/settings/inline/inline_upload'] = array(
188 'title' => 'Inline Upload',
189 'description' => 'Manage automatic and manual inclusion of attachments in the content of your posts.',
190 'page callback' => 'drupal_get_form',
191 'page arguments' => array('inline_upload_settings'),
192 'access arguments' => array('administer inline settings'),
193 );
194 return $items;
195 }
196
197 /**
198 * Inline settings form builder function.
199 */
200 function inline_upload_settings() {
201 $form = array();
202
203 // Check if Inline filter is enabled
204 $inline_upload_activated = FALSE;
205 foreach (filter_formats() as $format) {
206 foreach (filter_list_format($format->format) as $filter) {
207 if ($filter->module == 'inline') {
208 $inline_upload_activated = TRUE;
209 break 2;
210 }
211 }
212 }
213 if ($inline_upload_activated == FALSE) {
214 drupal_set_message(t('Inline filter is not yet enabled for at least one <a href="!formats">input format</a>.', array('!formats' => url('admin/settings/filters'))), 'error');
215 }
216
217 $form['inline']['upload']['image_link'] = array(
218 '#type' => 'fieldset',
219 '#title' => t('Image output'),
220 '#collapsible' => TRUE,
221 '#description' => t('<strong>Note:</strong> Images are only processed if a tag is referencing them. However, there is a auto-inline feature to inline all uploaded images automatically. Auto-inline can be enabled for certain <a href="!content-types">content types</a>.', array('!content-types' => url('admin/content/types'))),
222 );
223 $form['inline']['upload']['image_link']['inline_upload_link_img'] = array(
224 '#type' => 'radios',
225 '#title' => t('Link to images'),
226 '#default_value' => variable_get('inline_upload_link_img', 1),
227 '#options' => array(
228 '0' => t('Display image only'),
229 '1' => t('Display image with a link to the image file')
230 ),
231 );
232
233 $imagecache_path = '';
234 $presets = array();
235 if (module_exists('imagecache')) {
236 // ImageCache v2 API.
237 if (function_exists('imagecache_presets')) {
238 $imagecache_path = url('admin/build/imagecache');
239 $rules = imagecache_presets();
240 foreach ($rules as $preset_id => $preset_info) {
241 $presets[$preset_id] = $preset_info['presetname'];
242 }
243 }
244 // ImageCache v1 API (deprecated).
245 else {
246 $imagecache_path = url('admin/settings/imagecache');
247 $presets = _imagecache_get_presets();
248 }
249 }
250 $form['inline']['upload']['image_scaling'] = array(
251 '#type' => 'fieldset',
252 '#title' => t('Image dimensions and scaling'),
253 '#collapsible' => TRUE,
254 '#description' => (module_exists('imagecache') ? t('Select the <a href="!presets">Imagecache presets</a> to use for inlined images.', array('!presets' => $imagecache_path)) : t('<strong>Note:</strong> If <a href="!imagecache">Imagecache</a> module is installed, Inline provides support for image scaling.', array('!imagecache' => url('http://drupal.org/project/imagecache')))),
255 );
256
257 // If Imagecache module exists and is enabled, we assume that we want to use
258 // the improved image handling instead of our own.
259 if ($presets) {
260 $options = array();
261 $options[''] = 'No Imagecache processing';
262 foreach ($presets as $id => $name) {
263 $options[$name] = $name;
264 }
265 $form['inline']['upload']['image_scaling']['inline_upload_teaser_preset'] = array(
266 '#title' => t('Teaser preset'),
267 '#description' => t('Select the Imagecache preset to use for inlined images in teaser view.'),
268 '#type' => 'select',
269 '#options' => $options,
270 '#default_value' => variable_get('inline_upload_teaser_preset', ''),
271 );
272 $form['inline']['upload']['image_scaling']['inline_upload_full_preset'] = array(
273 '#title' => t('Full preset'),
274 '#description' => t('Select the Imagecache preset to use for inlined images in full view.'),
275 '#type' => 'select',
276 '#options' => $options,
277 '#default_value' => variable_get('inline_upload_full_preset', ''),
278 );
279 }
280 else {
281 $form['inline']['upload']['image_scaling']['inline_upload_img_dim'] = array(
282 '#type' => 'textfield',
283 '#title' => t('Maximum width and height for inline images (format: XXX,YYY)'),
284 '#size' => 10,
285 '#maxlength' => 10,
286 '#required' => TRUE,
287 '#default_value' => variable_get('inline_upload_img_dim', '150,150'),
288 '#description' => t('This setting limits the dimensions of displayed images in pixels. They will not be resized. Images exceeding these dimensions are automatically not displayed.', array('!content-types' => url('admin/content/types'))),
289 );
290 }
291
292 return system_settings_form($form);
293 }
294
295 /**
296 * Change file path of new files for previews.
297 *
298 * New files are stored in a temporary upload directory until the content
299 * is saved. We alter the file object accordingly, so such files may be
300 * displayed if the temporary directory is inside the root directory of
301 * this Drupal site (publicly accessible).
302 */
303 function inline_upload_prepare_file_object($file) {
304 $file = (object)$file;
305 // @todo Remove.
306 if (!is_numeric($file->fid)) {
307 $file->in_preview = TRUE;
308 $file->real_path = $file->filepath;
309 $file->filepath = $file->_filename;
310 }
311 return $file;
312 }
313
314 /**
315 * Decide if an image tag (&lt;IMG&gt;) or a link to a file should be rendered.
316 *
317 * @param $file
318 * A file object.
319 *
320 * @return
321 * TRUE in case an image tag should be generated.
322 */
323 function _inline_upload_decide_img_tag($file) {
324 $inlined = array('jpg', 'jpeg', 'pjpeg', 'gif', 'png');
325 $mime = array_pop(explode('/', $file->filemime));
326 if (in_array($mime, $inlined)) {
327 if (module_exists('imagecache')) {
328 return TRUE;
329 }
330 else {
331 // Read maximum dimension settings.
332 list($maxwidth, $maxheight) = explode(',', variable_get('inline_upload_img_dim', '150,150'));
333
334 if (!empty($file->in_preview)) {
335 list($width, $height) = @getimagesize($file->real_path);
336 }
337 else {
338 list($width, $height) = @getimagesize($file->filepath);
339 }
340 if (($width && $height) && ($width <= $maxwidth && $height <= $maxheight)) {
341 return TRUE;
342 }
343 }
344 }
345 return FALSE;
346 }
347
348 /**
349 * Return HTML for a link to a file.
350 *
351 * @param $file
352 * A file object.
353 */
354 function theme_inline_upload_as_link($file) {
355 // Prepare link text with title or filename.
356 $linktext = (!empty($file->title) ? $file->title : $file->filename);
357 $targs = array(
358 '@name' => $file->filename,
359 '@size' => format_size($file->filesize),
360 );
361
362 return l($linktext, file_create_url($file->filepath), array(
363 'attributes' => array(
364 'title' => t('Download: @name (@size)', $targs),
365 'class' => 'inline-link inline-file-mime-' . strtr($file->filemime, '/.', '-'),
366 ),
367 ));
368 }
369
370 /**
371 * Return HTML for an image.
372 */
373 function theme_inline_upload_img($file, $field) {
374 // Prepare link text with inline title, file description or filename.
375 $title = (!empty($file->title) ? $file->title : (!empty($file->description) ? $file->description : $file->filename));
376 $inline_upload_preset = ($field == 'teaser' ? 'inline_upload_teaser_preset' : 'inline_upload_full_preset');
377 $url = file_create_url($file->filepath);
378
379 if (module_exists('imagecache') && variable_get($inline_upload_preset, '') != '') {
380 // ImageCache implements its own private files handling.
381 $output = theme('imagecache',
382 variable_get($inline_upload_preset, ''),
383 $file->filepath,
384 $title,
385 $title,
386 array('class' => 'inline')
387 );
388 }
389 else {
390 // Private files support: theme_image() requires us to set $getsize to FALSE
391 // and prepare image attributes on our own.
392 $info = image_get_info($file->filepath);
393 $output = theme('image',
394 $url,
395 $title,
396 $title,
397 array('class' => 'inline', 'width' => $info['width'], 'height' => $info['height']),
398 FALSE
399 );
400 }
401
402 if (variable_get('inline_upload_link_img', '1')) {
403 $attributes = array(
404 'class' => 'inline-image-link',
405 'title' => t('View: @file', array('@file' => $title)),
406 );
407 $output = l($output, $url, array('attributes' => $attributes, 'html' => TRUE));
408 }
409
410 return $output;
411 }
412
413 /**
414 * @defgroup inline_upload_auto Auto inline support
415 * @{
416 */
417
418 /**
419 * Implementation of hook_form_alter().
420 *
421 * Allows to enable/disable auto-inline support for each content type.
422 */
423 function inline_upload_form_alter(&$form, &$form_state, $form_id) {
424 if ($form_id == 'node_type_form' && isset($form['identity']['type'])) {
425 $form['workflow']['upload_inline_upload'] = array(
426 '#type' => 'radios',
427 '#title' => t('Display attachments inline automatically'),
428 '#default_value' => variable_get('upload_inline_upload_'. $form['#node_type']->type, 0),
429 '#options' => array(
430 0 => t('Disabled'),
431 1 => t('Only in teaser view'),
432 2 => t('Only in body view'),
433 3 => t('In teaser and body view')),
434 '#description' => t('Choose whether uploaded images should be shown inline automatically. Make sure you set the dimensions at !settings_url', array('!settings_url' => l(t('Inline Upload settings'), 'admin/settings/inline/inline_upload'))),
435 );
436 }
437 }
438
439 /**
440 * Implementation of hook_nodeapi().
441 *
442 * @todo Break processing at all if Inline filter is not enabled.
443 */
444 function inline_upload_nodeapi(&$node, $op, $arg) {
445 if (!(isset($node->files) && is_array($node->files))) {
446 return;
447 }
448 switch ($op) {
449 case 'alter':
450 case 'print':
451 case 'rss item':
452 if (variable_get('upload_inline_upload_'. $node->type, 0)) {
453 $node = _inline_upload_auto_add($node);
454 }
455 return;
456 }
457 }
458
459 /**
460 * Automatically add all images to configured node views.
461 *
462 * This feature can be configured per content-type.
463 */
464 function _inline_upload_auto_add($node) {
465 switch (variable_get('upload_inline_upload_'. $node->type, 0)) {
466 case 1:
467 // Display only in teaser.
468 foreach ($node->files as $fid => $file) {
469 $file = inline_upload_prepare_file_object($file);
470 if (_inline_upload_decide_img_tag($file)) {
471 $node->files[$fid]->inline = TRUE;
472 $node->teaser = theme('inline_upload_prepend_to_field', $node, $file, 'teaser');
473 }
474 else {
475 $node->files[$fid]->inline = FALSE;
476 }
477 }
478 break;
479
480 case 2:
481 // Display only in body.
482 foreach ($node->files as $fid => $file) {
483 $file = inline_upload_prepare_file_object($file);
484 if (_inline_upload_decide_img_tag($file)) {
485 $node->files[$fid]->inline = TRUE;
486 $node->body = theme('inline_upload_prepend_to_field', $node, $file, 'body');
487 }
488 else {
489 $node->files[$fid]->inline = FALSE;
490 }
491 }
492 break;
493
494 case 3:
495 // Display in teaser and body.
496 foreach ($node->files as $fid => $file) {
497 $file = inline_upload_prepare_file_object($file);
498 if (_inline_upload_decide_img_tag($file)) {
499 $node->files[$fid]->inline = TRUE;
500 $node->teaser = theme('inline_upload_prepend_to_field', $node, $file, 'teaser');
501 $node->body = theme('inline_upload_prepend_to_field', $node, $file, 'body');
502 }
503 else {
504 $node->files[$fid]->inline = FALSE;
505 }
506 }
507 break;
508 }
509 return $node;
510 }
511
512 /**
513 * Insert an image in front of node field.
514 *
515 * @param $node
516 * The node object to process.
517 * @param $file
518 * A file object of an image to insert.
519 * @param $field
520 * The field name to prepend with the image.
521 */
522 function theme_inline_upload_prepend_to_field($node, $file, $field) {
523 return theme('inline_upload_img', $file, $field) . $node->$field;
524 }
525
526 /**
527 * @} End of "defgroup inline_upload_auto".
528 */
529

  ViewVC Help
Powered by ViewVC 1.1.2