| 1 |
<?php
|
| 2 |
// $Id: node_images.module,v 1.10 2007/10/07 17:12:24 stefano73 Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* This module will add an "Images" tab to nodes, allowing users to upload images and associate them with the current node.
|
| 7 |
*/
|
| 8 |
|
| 9 |
/**
|
| 10 |
* Implementation of hook_perm().
|
| 11 |
*/
|
| 12 |
function node_images_perm() {
|
| 13 |
$perms = array('administer node images', 'edit own node images', 'edit any node image', 'delete own node images', 'delete any node image');
|
| 14 |
|
| 15 |
foreach (node_get_types() as $type) {
|
| 16 |
if ($type->module == 'node') {
|
| 17 |
$name = check_plain($type->type);
|
| 18 |
$perms[] = 'add node images to own '. $name .' content';
|
| 19 |
$perms[] = 'add node images to any '. $name .' content';
|
| 20 |
}
|
| 21 |
}
|
| 22 |
|
| 23 |
return $perms;
|
| 24 |
}
|
| 25 |
|
| 26 |
/**
|
| 27 |
* Implementation of hook_menu().
|
| 28 |
*/
|
| 29 |
function node_images_menu() {
|
| 30 |
$items = array();
|
| 31 |
|
| 32 |
$items['node_images/js'] = array(
|
| 33 |
'page callback' => '_node_images_js',
|
| 34 |
'file' => 'node_images.pages.inc',
|
| 35 |
'access arguments' => array(),
|
| 36 |
'type' => MENU_CALLBACK,
|
| 37 |
);
|
| 38 |
$items['admin/settings/node_images'] = array(
|
| 39 |
'title' => 'Node images',
|
| 40 |
'description' => 'Control how to upload node images.',
|
| 41 |
'page callback' => 'drupal_get_form',
|
| 42 |
'page arguments' => array('node_images_admin_settings'),
|
| 43 |
'access arguments' => array('administer site configuration'),
|
| 44 |
'file' => 'node_images.admin.inc',
|
| 45 |
);
|
| 46 |
$items['node/%node/images'] = array(
|
| 47 |
'title' => 'Images',
|
| 48 |
'page callback' => 'drupal_get_form',
|
| 49 |
'page arguments' => array('_node_images_edit_form', 1),
|
| 50 |
'access callback' => '_node_images_access',
|
| 51 |
'access arguments' => array('create', 1),
|
| 52 |
'weight' => 2,
|
| 53 |
'file' => 'node_images.pages.inc',
|
| 54 |
'type' => MENU_LOCAL_TASK,
|
| 55 |
);
|
| 56 |
$items['node/%node/image_gallery'] = array(
|
| 57 |
'title' => 'Gallery',
|
| 58 |
'page callback' => '_node_images_gallery',
|
| 59 |
'page arguments' => array(1),
|
| 60 |
'access callback' => 'node_access',
|
| 61 |
'access arguments' => array('view', 1),
|
| 62 |
'file' => 'node_images.pages.inc',
|
| 63 |
'type' => MENU_CALLBACK,
|
| 64 |
);
|
| 65 |
|
| 66 |
return $items;
|
| 67 |
}
|
| 68 |
|
| 69 |
/**
|
| 70 |
* implementation of hook_form_alter()
|
| 71 |
*/
|
| 72 |
function node_images_form_alter(&$form, $form_state, $form_id) {
|
| 73 |
$type = $form['#node_type']->type;
|
| 74 |
if ($form_id == 'node_type_form' && isset($form['identity']['type'])) {
|
| 75 |
// radio button in the node's content type configuration page
|
| 76 |
_node_images_check_settings();
|
| 77 |
$form['node_images'] = array(
|
| 78 |
'#type' => 'fieldset',
|
| 79 |
'#title' => t('Node images'),
|
| 80 |
'#collapsible' => TRUE,
|
| 81 |
'#collapsed' => TRUE,
|
| 82 |
);
|
| 83 |
$form['node_images']['node_images_position'] = array(
|
| 84 |
'#type' => 'radios',
|
| 85 |
'#title' => t('Position'),
|
| 86 |
'#default_value' => variable_get('node_images_position_'.$type, 'hide'),
|
| 87 |
'#options' => array('hide' => t('Do not show'), 'above' => t('Show above node body'), 'below' => t('Show below node body'),
|
| 88 |
'node_template' => t('Manually set in node template by variable $node->node_images')),
|
| 89 |
'#description' => t('The position of images in the node view.'),
|
| 90 |
);
|
| 91 |
$form['node_images']['node_images_gallery_link'] = array(
|
| 92 |
'#type' => 'radios',
|
| 93 |
'#title' => t('Link to image gallery'),
|
| 94 |
'#default_value' => variable_get('node_images_gallery_link_'.$type, TRUE),
|
| 95 |
'#options' => array(t('Do not show'), t('Show')),
|
| 96 |
'#description' => t('Choose whether to show or not the link to the image gallery.'),
|
| 97 |
);
|
| 98 |
$form['node_images']['node_images_teaser_images'] = array(
|
| 99 |
'#type' => 'textfield',
|
| 100 |
'#title' => t('Number of images in node teaser'),
|
| 101 |
'#default_value' => variable_get('node_images_teaser_images_'.$type, 2),
|
| 102 |
'#size' => 5,
|
| 103 |
'#maxlength' => 2,
|
| 104 |
'#description' => t('The maximum number of images to show in the node teaser. 0 will not show images. Leave blank to show all images.'),
|
| 105 |
);
|
| 106 |
$form['node_images']['node_images_body_images'] = array(
|
| 107 |
'#type' => 'textfield',
|
| 108 |
'#title' => t('Number of images in node body'),
|
| 109 |
'#size' => 5,
|
| 110 |
'#maxlength' => 2,
|
| 111 |
'#default_value' => variable_get('node_images_body_images_'.$type, NULL),
|
| 112 |
'#description' => t('The maximum number of images to show in the node body. 0 will not show images. Leave blank to show all images.'),
|
| 113 |
);
|
| 114 |
$form['node_images']['node_images_teaser_format'] = array(
|
| 115 |
'#type' => 'radios',
|
| 116 |
'#title' => t('Image format in node teaser'),
|
| 117 |
'#default_value' => variable_get('node_images_teaser_format_'.$type, 'thumbs'),
|
| 118 |
'#options' => array('thumbs' => t('Thumbnails'), 'fullsize' => t('Full size images')),
|
| 119 |
'#description' => t('Image format in node teaser.'),
|
| 120 |
);
|
| 121 |
$form['node_images']['node_images_body_format'] = array(
|
| 122 |
'#type' => 'radios',
|
| 123 |
'#title' => t('Image format in node body'),
|
| 124 |
'#default_value' => variable_get('node_images_body_format_'.$type, 'thumbs'),
|
| 125 |
'#options' => array('thumbs' => t('Thumbnails'), 'fullsize' => t('Full size images')),
|
| 126 |
'#description' => t('Image format in node body.'),
|
| 127 |
);
|
| 128 |
|
| 129 |
// Role-based settings for image insertion
|
| 130 |
$result = db_query('SELECT rid, name FROM {role} ORDER BY name');
|
| 131 |
$role_options = array();
|
| 132 |
while ($role = db_fetch_object($result)) {
|
| 133 |
$role_options[$role->rid] = $role->name;
|
| 134 |
}
|
| 135 |
$form['node_images']['node_images_roles_add'] = array(
|
| 136 |
'#type' => 'checkboxes',
|
| 137 |
'#title' => t('Allow specific roles to add images to any node'),
|
| 138 |
'#default_value' => variable_get('node_images_roles_add_'.$type, array()),
|
| 139 |
'#options' => $role_options,
|
| 140 |
'#description' => t('Users having the selected role(s) will be able to add images to any existing node, even if they\'re not the node owner. If you select no roles, only node owner will be able to add images.'),
|
| 141 |
);
|
| 142 |
}
|
| 143 |
|
| 144 |
if (isset($form['type']) && isset($form['#node'])) {
|
| 145 |
$node = $form['#node'];
|
| 146 |
if (!$node->nid && $form['type']['#value'] .'_node_form' == $form_id && _node_images_access('create', $node)) {
|
| 147 |
// Attachments fieldset
|
| 148 |
$form['node_images'] = array(
|
| 149 |
'#type' => 'fieldset',
|
| 150 |
'#title' => t('Node images'),
|
| 151 |
'#collapsible' => TRUE,
|
| 152 |
'#collapsed' => empty($node->node_images),
|
| 153 |
'#description' => t('Changes made to the node images are not permanent until you save this post.'),
|
| 154 |
'#weight' => 30,
|
| 155 |
);
|
| 156 |
|
| 157 |
// Wrapper for fieldset contents (used by ahah.js).
|
| 158 |
$form['node_images']['wrapper'] = array(
|
| 159 |
'#prefix' => '<div id="node_images-attach-wrapper">',
|
| 160 |
'#suffix' => '</div>',
|
| 161 |
);
|
| 162 |
|
| 163 |
if (!_node_images_check_directory(NULL, $user, $node)) {
|
| 164 |
$form['node_images']['wrapper']['#description'] = t('Node images are disabled. The file directories have not been properly configured.');
|
| 165 |
if (user_access('administer site configuration')) {
|
| 166 |
$form['node_images']['wrapper']['#description'] .= ' '. t('Please visit the <a href="@admin-node-images">node_images configuration page</a>.', array('@admin-node-images' => url('admin/settings/node_images')));
|
| 167 |
}
|
| 168 |
else {
|
| 169 |
$form['node_images']['wrapper']['#description'] .= ' '. t('Please contact the site administrator.');
|
| 170 |
}
|
| 171 |
}
|
| 172 |
else {
|
| 173 |
require_once(drupal_get_path('module', 'node_images').'/node_images.pages.inc');
|
| 174 |
$form['node_images']['wrapper'] += _node_images_attach_form($form_state, $node);
|
| 175 |
$form['#attributes']['enctype'] = 'multipart/form-data';
|
| 176 |
}
|
| 177 |
}
|
| 178 |
$form['#submit'][] = 'node_images_node_form_submit';
|
| 179 |
}
|
| 180 |
}
|
| 181 |
|
| 182 |
/**
|
| 183 |
* Implementation of hook_nodeapi().
|
| 184 |
*/
|
| 185 |
function node_images_nodeapi(&$node, $op, $teaser, $page) {
|
| 186 |
// test if images are allowed for this node
|
| 187 |
if ($op == 'load' || $op == 'view') {
|
| 188 |
if (variable_get('node_images_position_'.$node->type, 'hide') == 'hide') return;
|
| 189 |
// fire an additional hook for the specific node type
|
| 190 |
// i.e. node images might be a pro feature, so only subscribed users can view them
|
| 191 |
// if the hook is not present in the node type module, images are loaded by default
|
| 192 |
$show = module_invoke($node->type, 'node_images', $op, $node);
|
| 193 |
if ($show === FALSE) return;
|
| 194 |
}
|
| 195 |
|
| 196 |
switch ($op) {
|
| 197 |
case 'load':
|
| 198 |
// load node images for the current node
|
| 199 |
$where = 'WHERE nid=%d';
|
| 200 |
if (arg(0) != 'node' || arg(2) != 'images') $where .= ' AND status=1 AND list=1';
|
| 201 |
$sql = db_query('SELECT * FROM {node_images} ' .$where. ' ORDER BY weight', $node->nid);
|
| 202 |
while ($r = db_fetch_object($sql)) {
|
| 203 |
$node->node_images[$r->id] = $r;
|
| 204 |
}
|
| 205 |
break;
|
| 206 |
|
| 207 |
case 'insert':
|
| 208 |
if (_node_images_access('create', $node)) {
|
| 209 |
_node_images_save_attachments($node);
|
| 210 |
if (variable_get('node_images_position_'.$node->type, 'hide') != 'hide') {
|
| 211 |
drupal_set_message(t('Click the <strong>!images</strong> tab to edit node images.',
|
| 212 |
array('!images' => l(t('Images'), 'node/'.$node->nid.'/images'))));
|
| 213 |
}
|
| 214 |
}
|
| 215 |
break;
|
| 216 |
|
| 217 |
case 'delete':
|
| 218 |
// Delete image and thumbnail files
|
| 219 |
$sql = db_query('SELECT filepath, thumbpath FROM {node_images} WHERE nid=%d', $node->nid);
|
| 220 |
while ($r = db_fetch_object($sql)) {
|
| 221 |
file_delete($r->filepath);
|
| 222 |
file_delete($r->thumbpath);
|
| 223 |
}
|
| 224 |
// Delete all images associated with the node
|
| 225 |
db_query('DELETE FROM {node_images} WHERE nid=%d', $node->nid);
|
| 226 |
break;
|
| 227 |
|
| 228 |
case 'prepare':
|
| 229 |
// Initialize $_SESSION['node_images'] if no post occurred.
|
| 230 |
// This clears the variable from old forms and makes sure it
|
| 231 |
// is an array to prevent notices and errors in other parts
|
| 232 |
// of node_images.module.
|
| 233 |
if (!$_POST) {
|
| 234 |
$_SESSION['node_images'] = array();
|
| 235 |
}
|
| 236 |
break;
|
| 237 |
|
| 238 |
case 'view':
|
| 239 |
if (empty($node->node_images)) return;
|
| 240 |
|
| 241 |
// search for a themed view for the current node type
|
| 242 |
$nodetype_function = 'theme_'.$node->type.'_node_images_view';
|
| 243 |
if (function_exists($nodetype_function)) {
|
| 244 |
$output = $nodetype_function($node, $teaser, $page);
|
| 245 |
}
|
| 246 |
else {
|
| 247 |
// use the default theme function
|
| 248 |
$output = theme('node_images_view', $node, $teaser, $page);
|
| 249 |
}
|
| 250 |
$node->node_images = $output;
|
| 251 |
|
| 252 |
$output = '<div class="node_images">'.$output.'</div>';
|
| 253 |
$position = variable_get('node_images_position_'.$node->type, 'hide');
|
| 254 |
switch ($position) {
|
| 255 |
case 'node_template':
|
| 256 |
case 'hide':
|
| 257 |
break;
|
| 258 |
|
| 259 |
case 'above':
|
| 260 |
$node->content['node_images'] = array('#value' => $output, '#weight' => -1);
|
| 261 |
break;
|
| 262 |
|
| 263 |
default:
|
| 264 |
$node->content['node_images'] = array('#value' => $output, '#weight' => 1);
|
| 265 |
break;
|
| 266 |
}
|
| 267 |
return $node;
|
| 268 |
}
|
| 269 |
}
|
| 270 |
|
| 271 |
/**
|
| 272 |
* Implementation of hook_theme()
|
| 273 |
*/
|
| 274 |
function node_images_theme() {
|
| 275 |
return array(
|
| 276 |
'node_images_form_list' => array(
|
| 277 |
'arguments' => array('form' => NULL),
|
| 278 |
),
|
| 279 |
'node_images_form_upload' => array(
|
| 280 |
'arguments' => array('form' => NULL),
|
| 281 |
),
|
| 282 |
'node_images_attach_list' => array(
|
| 283 |
'arguments' => array('form' => NULL),
|
| 284 |
),
|
| 285 |
'node_images_view' => array(
|
| 286 |
'arguments' => array('node' => NULL, 'teaser' => NULL, 'page' => NULL),
|
| 287 |
),
|
| 288 |
'node_images_gallery' => array(
|
| 289 |
'arguments' => array('element' => NULL),
|
| 290 |
),
|
| 291 |
'node_images_gallery_thumbs' => array(
|
| 292 |
'arguments' => array('thumbs' => NULL, 'cols' => 2),
|
| 293 |
),
|
| 294 |
);
|
| 295 |
}
|
| 296 |
|
| 297 |
/**
|
| 298 |
* Implementation of hook_link().
|
| 299 |
*/
|
| 300 |
function node_images_link($type, $node = null, $teaser = false) {
|
| 301 |
$links = array();
|
| 302 |
|
| 303 |
if ($type == 'node' && $node->nid && variable_get('node_images_position_'.$node->type, 'hide') != 'hide') {
|
| 304 |
if (node_access('update', $node) && user_access('create node images')) {
|
| 305 |
$links['node_images_edit'] = array(
|
| 306 |
'title' => t('Edit node images'),
|
| 307 |
'href' => "node/$node->nid/images",
|
| 308 |
);
|
| 309 |
}
|
| 310 |
if (count($node->node_images) && variable_get('node_images_gallery_link_'.$node->type, TRUE)) {
|
| 311 |
$links['node_images_gallery'] = array(
|
| 312 |
'title' => t('Open the image gallery'),
|
| 313 |
'href' => "node/$node->nid/image_gallery",
|
| 314 |
);
|
| 315 |
}
|
| 316 |
}
|
| 317 |
|
| 318 |
return $links;
|
| 319 |
}
|
| 320 |
|
| 321 |
/**
|
| 322 |
* Implementation of hook_user().
|
| 323 |
*/
|
| 324 |
function node_images_user($type, &$edit, &$user, $category = NULL) {
|
| 325 |
switch ($type) {
|
| 326 |
case 'delete':
|
| 327 |
// Set uid=0 for images uploaded by the deleted user
|
| 328 |
db_query('UPDATE {node_images} SET uid=0 WHERE uid=%d', $user->uid);
|
| 329 |
}
|
| 330 |
}
|
| 331 |
|
| 332 |
/**
|
| 333 |
* Implementation of hook_file_download().
|
| 334 |
* Find out if an image is accessible when download method is set to private
|
| 335 |
*/
|
| 336 |
function node_images_file_download($file) {
|
| 337 |
$path = file_create_path($file);
|
| 338 |
$result = db_query("SELECT * FROM {node_images} WHERE filepath='%s' OR thumbpath='%s'", $path, $path);
|
| 339 |
if ($file = db_fetch_object($result)) {
|
| 340 |
$node = node_load($file->nid);
|
| 341 |
if (node_access('view', $node)) {
|
| 342 |
if ($path == $file->thumbpath) {
|
| 343 |
// update header info if thumb is requested
|
| 344 |
$name = mime_header_encode(basename($file->thumbpath));
|
| 345 |
$size = $file->thumbsize;
|
| 346 |
}
|
| 347 |
else {
|
| 348 |
$name = mime_header_encode($file->filename);
|
| 349 |
$size = $file->filesize;
|
| 350 |
}
|
| 351 |
$type = mime_header_encode($file->filemime);
|
| 352 |
return array(
|
| 353 |
'Content-Type: '. $type .'; name='. $name,
|
| 354 |
'Content-Length: '. $size,
|
| 355 |
'Cache-Control: private'
|
| 356 |
);
|
| 357 |
}
|
| 358 |
else {
|
| 359 |
return -1;
|
| 360 |
}
|
| 361 |
}
|
| 362 |
}
|
| 363 |
|
| 364 |
|
| 365 |
/************************************************************
|
| 366 |
* Upload functions
|
| 367 |
************************************************************/
|
| 368 |
|
| 369 |
function _node_images_attach_form($form_state, $node) {
|
| 370 |
$form = array(
|
| 371 |
'#cache' => TRUE,
|
| 372 |
);
|
| 373 |
$form['node_images'] = _node_images_attach_list($node);
|
| 374 |
|
| 375 |
if (_node_images_access('create', $node)) {
|
| 376 |
$limits = _node_images_file_limits($user);
|
| 377 |
$form['node_images_file'] = array(
|
| 378 |
'#type' => 'file',
|
| 379 |
'#title' => t('Attach new image'),
|
| 380 |
'#size' => 40,
|
| 381 |
'#description' => ($limits['resolution'] ? t('Images 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']))),
|
| 382 |
'#weight' => 30,
|
| 383 |
);
|
| 384 |
$form['node_images_attach'] = array(
|
| 385 |
'#type' => 'submit',
|
| 386 |
'#value' => t('Attach'),
|
| 387 |
'#name' => 'attach',
|
| 388 |
'#ahah' => array(
|
| 389 |
'path' => 'node_images/js',
|
| 390 |
'wrapper' => 'node_images-attach-wrapper',
|
| 391 |
'progress' => array('type' => 'bar', 'message' => t('Please wait...')),
|
| 392 |
),
|
| 393 |
'#submit' => array('node_form_submit_build_node'),
|
| 394 |
'#weight' => 31,
|
| 395 |
);
|
| 396 |
}
|
| 397 |
|
| 398 |
return $form;
|
| 399 |
}
|
| 400 |
|
| 401 |
function _node_images_attach_list($node) {
|
| 402 |
$form = array(
|
| 403 |
'#theme' => 'node_images_attach_list',
|
| 404 |
'#tree' => TRUE,
|
| 405 |
);
|
| 406 |
if (is_array($node->node_images) && !empty($node->node_images)) {
|
| 407 |
$delta = max(count($node->node_images), 10);
|
| 408 |
foreach ($node->node_images as $key => $file) {
|
| 409 |
$file = (object)$file;
|
| 410 |
$thumb = file_create_url($file->filepath);
|
| 411 |
$row = array();
|
| 412 |
$row['fid'] = array('#type' => 'value', '#value' => $file->fid);
|
| 413 |
$row['filepath'] = array('#type' => 'value', '#value' => $file->filepath);
|
| 414 |
$row['delete'] = array('#type' => 'checkbox');
|
| 415 |
$row['list'] = array('#type' => 'checkbox', '#default_value' => $file->list);
|
| 416 |
$row['thumbnail'] = array('#value' => '<img src="'.$thumb.'" width="75" alt="" />');
|
| 417 |
$row['description'] = array('#type' => 'textfield', '#default_value' => $file->description, '#maxlength' => 255, '#size' => 40);
|
| 418 |
$row['filename'] = array('#type' => 'value', '#value' => $file->filename);
|
| 419 |
$row['filemime'] = array('#type' => 'value', '#value' => $file->filemime);
|
| 420 |
$row['filesize'] = array('#value' => format_size($file->filesize));
|
| 421 |
$row['weight'] = array('#type' => 'weight', '#delta' => $delta, '#default_value' => $file->weight);
|
| 422 |
$form[$key] = $row;
|
| 423 |
}
|
| 424 |
}
|
| 425 |
return $form;
|
| 426 |
}
|
| 427 |
|
| 428 |
/**
|
| 429 |
* Save the current uploaded file.
|
| 430 |
*
|
| 431 |
* @return
|
| 432 |
* An object containing the file information, or FALSE in the event of an error.
|
| 433 |
*/
|
| 434 |
function _node_images_file_upload($form, &$form_state, $node = NULL) {
|
| 435 |
global $user;
|
| 436 |
|
| 437 |
$limits = _node_images_file_limits($user);
|
| 438 |
$validators = array(
|
| 439 |
'file_validate_is_image' => array(),
|
| 440 |
'file_validate_image_resolution' => array($limits['resolution']),
|
| 441 |
'file_validate_size' => array($limits['file_size']),
|
| 442 |
'_node_images_file_validate_name' => array(),
|
| 443 |
);
|
| 444 |
|
| 445 |
// Save new file upload.
|
| 446 |
$dest = ($node ? _node_images_get_directory('', $user, $node) : file_directory_path());
|
| 447 |
if ($file = file_save_upload('node_images_file', $validators, $dest)) {
|
| 448 |
return $file;
|
| 449 |
}
|
| 450 |
|
| 451 |
return FALSE;
|
| 452 |
}
|
| 453 |
|
| 454 |
/**
|
| 455 |
* Save new uploads and store them in the session to be associated to the node
|
| 456 |
* on _node_images_save_attachments.
|
| 457 |
*
|
| 458 |
* @param $node
|
| 459 |
* A node object to associate with uploaded images.
|
| 460 |
*/
|
| 461 |
function node_images_node_form_submit($form, &$form_state, $node = NULL) {
|
| 462 |
global $user;
|
| 463 |
|
| 464 |
// Save new file upload.
|
| 465 |
$file = _node_images_file_upload($form, $form_state);
|
| 466 |
if (!$file) return;
|
| 467 |
|
| 468 |
$file->list = 1;
|
| 469 |
$file->description = $file->filename;
|
| 470 |
$file->weight = 0;
|
| 471 |
$_SESSION['node_images'][$file->fid] = $file;
|
| 472 |
|
| 473 |
// Attach session files to node.
|
| 474 |
if (!empty($_SESSION['node_images'])) {
|
| 475 |
foreach ($_SESSION['node_images'] as $fid => $file) {
|
| 476 |
if (!isset($form_state['values']['node_images'][$fid]['filepath'])) {
|
| 477 |
$form_state['values']['node_images'][$fid] = (array)$file;
|
| 478 |
}
|
| 479 |
}
|
| 480 |
}
|
| 481 |
|
| 482 |
// Order the form according to the set file weight values.
|
| 483 |
if (!empty($form_state['values']['node_images'])) {
|
| 484 |
$microweight = 0.001;
|
| 485 |
foreach ($form_state['values']['node_images'] as $fid => $file) {
|
| 486 |
if (is_numeric($fid)) {
|
| 487 |
$form_state['values']['node_images'][$fid]['#weight'] = $file['weight'] + $microweight;
|
| 488 |
$microweight += 0.001;
|
| 489 |
}
|
| 490 |
}
|
| 491 |
uasort($form_state['values']['node_images'], 'element_sort');
|
| 492 |
}
|
| 493 |
}
|
| 494 |
|
| 495 |
function _node_images_save_attachments(&$node) {
|
| 496 |
global $user;
|
| 497 |
|
| 498 |
if (empty($node->node_images) || !is_array($node->node_images)) {
|
| 499 |
return;
|
| 500 |
}
|
| 501 |
|
| 502 |
$result = _node_images_check_directory(NULL, $user, $node);
|
| 503 |
if (!$result) return FALSE;
|
| 504 |
$dest = _node_images_get_directory('', $user, $node);
|
| 505 |
|
| 506 |
foreach ($node->node_images as $fid => $file) {
|
| 507 |
// Convert file to object for compatibility
|
| 508 |
$file = (object)$file;
|
| 509 |
if (!$file->delete) {
|
| 510 |
$result = file_move($file->filepath, $dest);
|
| 511 |
if (!$result) {
|
| 512 |
drupal_set_message(t('Unable to copy image "%image".',
|
| 513 |
array('%image' => $file->filename)), 'error');
|
| 514 |
}
|
| 515 |
|
| 516 |
// If we made it this far it's safe to record this file in the database.
|
| 517 |
$file->filepath = $dest .'/'. basename($file->filepath);
|
| 518 |
$thumb = _node_images_create_thumbnail($file->filepath);
|
| 519 |
$file->uid = $user->uid;
|
| 520 |
$file->nid = $node->nid;
|
| 521 |
$file->timestamp = time();
|
| 522 |
$file->filesize = filesize($file->filepath);
|
| 523 |
$file->thumbpath = $thumb->filepath;
|
| 524 |
$file->thumbsize = $thumb->filesize;
|
| 525 |
$file->status = 1;
|
| 526 |
drupal_write_record('node_images', $file);
|
| 527 |
}
|
| 528 |
else {
|
| 529 |
file_delete($file->filepath);
|
| 530 |
db_query('DELETE FROM {files} WHERE fid = %d', $fid);
|
| 531 |
|
| 532 |
// Remove it from the session in the case of new uploads,
|
| 533 |
// that you want to disassociate before node submission.
|
| 534 |
unset($_SESSION['node_images'][$fid]);
|
| 535 |
}
|
| 536 |
}
|
| 537 |
|
| 538 |
// Empty the session storage after save. We use this variable to track files
|
| 539 |
// that haven't been related to the node yet.
|
| 540 |
unset($_SESSION['node_images']);
|
| 541 |
}
|
| 542 |
|
| 543 |
/**
|
| 544 |
* Menu-callback for JavaScript-based uploads.
|
| 545 |
*/
|
| 546 |
function _node_images_js() {
|
| 547 |
global $user;
|
| 548 |
|
| 549 |
$output = '';
|
| 550 |
//$nid = $_POST['nid'];
|
| 551 |
|
| 552 |
if ($_POST['form_id'] == 'page_node_form') {
|
| 553 |
// upload from node creation page
|
| 554 |
|
| 555 |
// Load the form from the Form API cache.
|
| 556 |
$cache = cache_get('form_'. $_POST['form_build_id'], 'cache_form');
|
| 557 |
|
| 558 |
// Handle new uploads, and merge tmp files into node_images.
|
| 559 |
$node = (object)$_POST;
|
| 560 |
node_images_node_form_submit($form, $form_state);
|
| 561 |
if (!empty($form_state['values']['node_images'])) {
|
| 562 |
foreach ($form_state['values']['node_images'] as $fid => $file) {
|
| 563 |
if (is_numeric($fid)) {
|
| 564 |
$node->node_images[$fid] = $file;
|
| 565 |
if (0 && !isset($file['filepath'])) {
|
| 566 |
$node->node_images[$fid] = $node_files[$fid];
|
| 567 |
}
|
| 568 |
}
|
| 569 |
}
|
| 570 |
}
|
| 571 |
|
| 572 |
$form = _node_images_attach_form($form_state, $node);
|
| 573 |
|
| 574 |
// Update the default values changed in the $_POST array.
|
| 575 |
$files = isset($_POST['node_images']) ? $_POST['node_images'] : array();
|
| 576 |
foreach ($files as $fid => $file) {
|
| 577 |
if (is_numeric($fid)) {
|
| 578 |
$form['node_images'][$fid]['description']['#default_value'] = $file['description'];
|
| 579 |
$form['node_images'][$fid]['list']['#default_value'] = isset($file['list']) ? 1 : 0;
|
| 580 |
$form['node_images'][$fid]['remove']['#default_value'] = isset($file['remove']) ? 1 : 0;
|
| 581 |
$form['node_images'][$fid]['weight']['#default_value'] = $file['weight'];
|
| 582 |
$form['node_images'][$fid]['filemime']['#value'] = $file['filemime'];
|
| 583 |
}
|
| 584 |
}
|
| 585 |
|
| 586 |
// Add the new element to the stored form state and resave.
|
| 587 |
$cache->data['node_images']['wrapper'] = array_merge($cache->data['node_images']['wrapper'], $form);
|
| 588 |
cache_set('form_'. $_POST['form_build_id'], $cache->data, 'cache_form', $cache->expire);
|
| 589 |
|
| 590 |
// Render the form for output.
|
| 591 |
$form += array(
|
| 592 |
'#post' => $_POST,
|
| 593 |
'#programmed' => FALSE,
|
| 594 |
'#tree' => FALSE,
|
| 595 |
'#parents' => array(),
|
| 596 |
);
|
| 597 |
drupal_alter('form', $form, array(), 'node_images_js');
|
| 598 |
}
|
| 599 |
elseif ($nid = $_POST['nid']) {
|
| 600 |
// upload from node images page
|
| 601 |
if ($node = node_load($nid)) {
|
| 602 |
$form = array();
|
| 603 |
$form_state = array('values' => $_POST);
|
| 604 |
|
| 605 |
if ($file = _node_images_upload_submit($form, $form_state, $node)) {
|
| 606 |
// upload successful, reload node
|
| 607 |
$node = node_load(array('nid' => $nid));
|
| 608 |
}
|
| 609 |
|
| 610 |
$form = _node_images_edit_form($form_state, $node);
|
| 611 |
}
|
| 612 |
}
|
| 613 |
|
| 614 |
$form_state = array('submitted' => FALSE, 'values' => $_POST);
|
| 615 |
$form = form_builder('_node_images_js', $form, $form_state);
|
| 616 |
$form['#sorted'] = TRUE;
|
| 617 |
|
| 618 |
$output .= theme('status_messages') . drupal_render($form);
|
| 619 |
|
| 620 |
// We send the updated node images form.
|
| 621 |
print drupal_to_js(array('status' => TRUE, 'data' => $output));
|
| 622 |
exit();
|
| 623 |
}
|
| 624 |
|
| 625 |
/**
|
| 626 |
* Upload a new image and associate it to the current node.
|
| 627 |
*
|
| 628 |
* @param $form
|
| 629 |
* The form structure.
|
| 630 |
* @param $form_state
|
| 631 |
* An associative array containing the current state of the form.
|
| 632 |
* @param $node
|
| 633 |
* A node object to associate with uploaded image.
|
| 634 |
* @return
|
| 635 |
* the uploaded image file, or FALSE if upload fails
|
| 636 |
*/
|
| 637 |
function _node_images_upload_submit($form, &$form_state, $node = NULL) {
|
| 638 |
global $user;
|
| 639 |
|
| 640 |
if (!$node && is_numeric(arg(1))) {
|
| 641 |
$node = node_load(arg(1));
|
| 642 |
}
|
| 643 |
else {
|
| 644 |
}
|
| 645 |
if (!$node || !isset($node->nid)) {
|
| 646 |
drupal_set_message(t('Node not valid.'), 'error');
|
| 647 |
}
|
| 648 |
|
| 649 |
if (!_node_images_access('create', $node)) {
|
| 650 |
drupal_set_message(t('You are not allowed to upload node images.'), 'error');
|
| 651 |
return FALSE;
|
| 652 |
}
|
| 653 |
|
| 654 |
if ($file = _node_images_file_upload($form, $form_state, $node)) {
|
| 655 |
$description = $form_state['values']['description'];
|
| 656 |
if (trim($description) == '') {
|
| 657 |
$description = basename($file->filename);
|
| 658 |
}
|
| 659 |
$thumb = _node_images_create_thumbnail($file->filepath);
|
| 660 |
|
| 661 |
// If we made it this far it's safe to record this file in the database.
|
| 662 |
$file->uid = $user->uid;
|
| 663 |
$file->nid = $node->nid;
|
| 664 |
$file->timestamp = time();
|
| 665 |
$file->thumbpath = $thumb->filepath;
|
| 666 |
$file->thumbsize = $thumb->filesize;
|
| 667 |
$file->description = $description;
|
| 668 |
$file->status = 1;
|
| 669 |
$file->weight = $form_state['values']['weight'];
|
| 670 |
$file->list = (isset($form_state['values']['list']) ? $form_state['values']['list'] : 1);
|
| 671 |
|
| 672 |
$result = drupal_write_record('node_images', $file);
|
| 673 |
if ($result == SAVED_NEW) {
|
| 674 |
drupal_set_message(t('The image has been successfully uploaded.'));
|
| 675 |
}
|
| 676 |
return $file;
|
| 677 |
}
|
| 678 |
|
| 679 |
return FALSE;
|
| 680 |
}
|
| 681 |
|
| 682 |
|
| 683 |
/************************************************************
|
| 684 |
* Theme functions
|
| 685 |
************************************************************/
|
| 686 |
|
| 687 |
/**
|
| 688 |
* Theme the list of attached images.
|
| 689 |
*
|
| 690 |
* @ingroup themeable
|
| 691 |
*/
|
| 692 |
function theme_node_images_attach_list(&$form) {
|
| 693 |
$header = array('', t('Delete'), t('List'), t('Thumbnail'), t('Description'), t('Weight'), t('Size'));
|
| 694 |
drupal_add_tabledrag('node_images_attach_list', 'order', 'sibling', 'node_images-weight');
|
| 695 |
|
| 696 |
foreach (element_children($form) as $key) {
|
| 697 |
if (!$form[$key]['thumbnail']) continue;
|
| 698 |
|
| 699 |
// Add class to group weight fields for drag and drop.
|
| 700 |
$form[$key]['weight']['#attributes']['class'] = 'node_images-weight';
|
| 701 |
|
| 702 |
$row = array('');
|
| 703 |
$row[] = drupal_render($form[$key]['delete']);
|
| 704 |
$row[] = drupal_render($form[$key]['list']);
|
| 705 |
$row[] = drupal_render($form[$key]['thumbnail']);
|
| 706 |
$row[] = array('data' => drupal_render($form[$key]['description']), 'width' => '100%');
|
| 707 |
$row[] = drupal_render($form[$key]['weight']);
|
| 708 |
$row[] = array('data' => drupal_render($form[$key]['filesize']), 'class' => 'nowrap');
|
| 709 |
$rows[] = array('data' => $row, 'class' => 'draggable');
|
| 710 |
}
|
| 711 |
|
| 712 |
$output = '';
|
| 713 |
if (!empty($rows)) $output .= theme('table', $header, $rows, array('id' => 'node_images_attach_list'));
|
| 714 |
$output .= drupal_render($form);
|
| 715 |
return $output;
|
| 716 |
}
|
| 717 |
|
| 718 |
/**
|
| 719 |
* Show node images in the node view.
|
| 720 |
*/
|
| 721 |
function theme_node_images_view($node, $teaser, $page, $block = FALSE, $count = NULL, $format = NULL) {
|
| 722 |
if (arg(2) == 'image_gallery' || empty($node->node_images)) return;
|
| 723 |
|
| 724 |
$output = '';
|
| 725 |
$i = 0;
|
| 726 |
|
| 727 |
// set maximum number of images for teaser/body
|
| 728 |
$view = ($teaser ? 'teaser' : 'body');
|
| 729 |
if (!$count) {
|
| 730 |
$count = variable_get('node_images_'.$view.'_images_'.$node->type, 2);
|
| 731 |
}
|
| 732 |
if (isset($count) && $count == '0') return;
|
| 733 |
|
| 734 |
// set image format
|
| 735 |
if (!$format) {
|
| 736 |
$format = variable_get('node_images_'.$view.'_format_'.$node->type, 'thumbs');
|
| 737 |
}
|
| 738 |
|
| 739 |
foreach((array)$node->node_images as $id => $image) {
|
| 740 |
$description = check_plain($image->description);
|
| 741 |
$pattern = '<img src="%path" alt="%description" />';
|
| 742 |
$thumb = strtr($pattern, array('%path'=>file_create_url($image->thumbpath), '%description'=>$description));
|
| 743 |
$fullsize = strtr($pattern, array('%path'=>file_create_url($image->filepath), '%description'=>$description));
|
| 744 |
|
| 745 |
if ($info = @getimagesize($image->filepath)) {
|
| 746 |
$width = $info[0] + 36;
|
| 747 |
$height = $info[1] + 36;
|
| 748 |
}
|
| 749 |
else {
|
| 750 |
$width = 420;
|
| 751 |
$height = 315;
|
| 752 |
}
|
| 753 |
|
| 754 |
if ($format == 'thumbs') {
|
| 755 |
$output .= '<a href="javascript:void(0);" title="'.$description.'" onclick="window.open(\''.
|
| 756 |
file_create_url($image->filepath).'\', \'\', \'height='.$height.',width='.$width.'\');">'.$thumb.'</a> ';
|
| 757 |
}
|
| 758 |
else {
|
| 759 |
$output .= $fullsize.' ';
|
| 760 |
}
|
| 761 |
if ($count>0 && ++$i >= $count) break;
|
| 762 |
}
|
| 763 |
|
| 764 |
if ($block && $count < count($node->node_images)) {
|
| 765 |
$output .= '<div class="node_images_block_link">'.l(t('View all images'), 'node/'.$node->nid.'/image_gallery').'</div>';
|
| 766 |
}
|
| 767 |
|
| 768 |
return $output;
|
| 769 |
}
|
| 770 |
|
| 771 |
|
| 772 |
/************************************************************
|
| 773 |
* Helper functions - other
|
| 774 |
************************************************************/
|
| 775 |
|
| 776 |
/**
|
| 777 |
* Check access to add, edit or delete node images.
|
| 778 |
*/
|
| 779 |
function _node_images_access($op, $node) {
|
| 780 |
global $user;
|
| 781 |
|
| 782 |
//if (node_access($op, $node)) return TRUE;
|
| 783 |
|
| 784 |
$type = node_get_types('name', $node);
|
| 785 |
if ($op == 'create') {
|
| 786 |
return (user_access('add node images to any '. $type .' content') || (user_access('add node images to own '. $type .' content') && ($user->uid == $node->uid)));
|
| 787 |
}
|
| 788 |
if ($op == 'update') {
|
| 789 |
return (user_access('edit any node_image') || (user_access('edit own node images') && ($user->uid == $node->uid)));
|
| 790 |
}
|
| 791 |
if ($op == 'delete') {
|
| 792 |
return (user_access('delete any node_image') || (user_access('delete own node images') && ($user->uid == $node->uid)));
|
| 793 |
}
|
| 794 |
|
| 795 |
return FALSE;
|
| 796 |
}
|
| 797 |
|
| 798 |
/**
|
| 799 |
* Checks if the upload.module is enabled, and the existence of an image toolkit.
|
| 800 |
*
|
| 801 |
* @param $form_element
|
| 802 |
* The form element containing the name of the directory to check.
|
| 803 |
*/
|
| 804 |
function _node_images_check_settings() {
|
| 805 |
// Make sure we've got a working toolkit
|
| 806 |
if (!image_get_toolkit()) {
|
| 807 |
drupal_set_message(t('Make sure you have a working image toolkit installed and enabled, for more information see: %settings', array('%settings' => l(t('the settings page'), 'admin/settings/image-toolkit'))), 'error');
|
| 808 |
}
|
| 809 |
}
|
| 810 |
|
| 811 |
/**
|
| 812 |
* Checks the existence of the destination directory.
|
| 813 |
* The directory can be specified either in $form_element (when called from the admin settings)
|
| 814 |
* or in $path (when called from the node images edit page).
|
| 815 |
*
|
| 816 |
* @param $form_element
|
| 817 |
* The form element containing the name of the directory to check.
|
| 818 |
*/
|
| 819 |
function _node_images_check_directory($form_element = NULL, $u = NULL, $node = NULL) {
|
| 820 |
$dir = (isset($form_element['#value']) ? $form_element['#value'] : '');
|
| 821 |
$path = _node_images_get_directory($dir, $u, $node);
|
| 822 |
$form_item = isset($form_element['#parents'][0]) ? $form_element['#parents'][0] : NULL;
|
| 823 |
$result = _node_images_mkdir_recursive($path, FILE_CREATE_DIRECTORY, $form_element['#parents'][0]);
|
| 824 |
if ($form_element) return $form_element;
|
| 825 |
return $result;
|
| 826 |
}
|
| 827 |
|
| 828 |
function _node_images_mkdir_recursive($path, $mode, $form_item) {
|
| 829 |
if (file_check_directory($path, $mode, $form_item)) return TRUE;
|
| 830 |
|
| 831 |
$folders = explode('/', $path);
|
| 832 |
$dirs = array();
|
| 833 |
foreach ($folders as $folder) {
|
| 834 |
$dirs[] = $folder;
|
| 835 |
$dir = implode('/', $dirs);
|
| 836 |
if (!file_check_directory($dir, $mode, $form_item)) {
|
| 837 |
return FALSE;
|
| 838 |
}
|
| 839 |
}
|
| 840 |
return TRUE;
|
| 841 |
}
|
| 842 |
|
| 843 |
/**
|
| 844 |
* Return the destination directory.
|
| 845 |
*/
|
| 846 |
function _node_images_get_directory($dir = '', $u = NULL, $node = NULL) {
|
| 847 |
global $user;
|
| 848 |
|
| 849 |
if (!$u) $u = $user;
|
| 850 |
$variables = array('%uid' => $u->uid, '%username' => $u->name);
|
| 851 |
$variables['%nid'] = ($node ? $node->nid : 0);
|
| 852 |
$variables['%type'] = ($node ? $node->type: 'node');
|
| 853 |
$path = file_directory_path().'/';
|
| 854 |
$path .= ($dir ? trim($dir, '/') : variable_get('node_images_path', 'node_images'));
|
| 855 |
return strtr($path, $variables);
|
| 856 |
}
|
| 857 |
|
| 858 |
/**
|
| 859 |
* Validate, apply md5 and normalize filename.
|
| 860 |
*
|
| 861 |
* @param $file
|
| 862 |
* A Drupal file object.
|
| 863 |
* @return
|
| 864 |
* An array. If the file name is not valid, it will contain an error message.
|
| 865 |
*/
|
| 866 |
function _node_images_file_validate_name(&$file) {
|
| 867 |
$errors = array();
|
| 868 |
|
| 869 |
if (variable_get('node_images_md5name', FALSE)) {
|
| 870 |
// set md5 file name
|
| 871 |
preg_match('/\.(.*?)$/i', $file->filename, $m);
|
| 872 |
$extension = $m[1];
|
| 873 |
$file->filename = substr(md5($dest.'/'.$file->filename), 0, 16);
|
| 874 |
if ($extension) $file->filename .= '.'.strtolower($extension);
|
| 875 |
}
|
| 876 |
$file->filename = preg_replace(array('/[ \']+/', '/["]+/'), array('_', ''), $file->filename);
|
| 877 |
|
| 878 |
if (strlen($file->filename) > 255) {
|
| 879 |
$errors[] = t('Its name exceeds the 255 characters limit. Please rename the file and try again.');
|
| 880 |
}
|
| 881 |
return $errors;
|
| 882 |
}
|
| 883 |
|
| 884 |
/**
|
| 885 |
* Create the thumbnail for the uploaded image.
|
| 886 |
*/
|
| 887 |
function _node_images_create_thumbnail($source, $suffix = '_tn') {
|
| 888 |
$size = variable_get('node_images_thumb_resolution', '100x100');
|
| 889 |
list($width, $height) = explode('x', $size);
|
| 890 |
$dest = preg_replace('!(\.[^/.]+?)?$!', "$suffix\\1", $source, 1);
|
| 891 |
|
| 892 |
if ($size = @getimagesize($source)) {
|
| 893 |
if (!image_scale($source, $dest, $width, $height)) {
|
| 894 |
file_copy($source, $dest, FILE_EXISTS_REPLACE);
|
| 895 |
}
|
| 896 |
$info = image_get_info($dest);
|
| 897 |
$thumb = new stdClass();
|
| 898 |
$thumb->filename = basename($dest);
|
| 899 |
$thumb->filepath = $dest;
|
| 900 |
$thumb->filesize = $info['file_size'];
|
| 901 |
$thumb->filemime = $info['mime_type'];
|
| 902 |
return $thumb;
|
| 903 |
}
|
| 904 |
return NULL;
|
| 905 |
}
|
| 906 |
|
| 907 |
/**
|
| 908 |
* Determine the limitations on files that a given user may upload. The user
|
| 909 |
* may be in multiple roles so we select the most permissive limitations from
|
| 910 |
* all of their roles.
|
| 911 |
*
|
| 912 |
* @param $user
|
| 913 |
* A Drupal user object.
|
| 914 |
* @return
|
| 915 |
* An associative array with the following keys:
|
| 916 |
* 'extensions'
|
| 917 |
* A white space separated string containing the allowed extensions.
|
| 918 |
* 'file_size'
|
| 919 |
* The maximum size of a file upload in bytes.
|
| 920 |
* 'resolution'
|
| 921 |
* A string specifying the maximum resolution of images.
|
| 922 |
*/
|
| 923 |
function _node_images_file_limits($user) {
|
| 924 |
return array(
|
| 925 |
'extensions' => variable_get('node_images_extensions', 'jpg jpeg gif png'),
|
| 926 |
'file_size' => variable_get('node_images_file_limit', 1) * 1024 * 1024,
|
| 927 |
'resolution' => variable_get('node_images_large_resolution', 0),
|
| 928 |
);
|
| 929 |
}
|