image_attach.module

Tracking 6.x-1.x branch
  1. drupal
    1. 5 contributions/image/contrib/image_attach/image_attach.module
    2. 6 contributions/image/contrib/image_attach/image_attach.module

image_attach.module

Functions & methods

NameDescription
image_attach_admin_settings
image_attach_blockImplementation of hook_block().
image_attach_content_extra_fieldsImplementation of hook_content_extra_fields().
image_attach_form_alterImplementation of hook_form_alter().
image_attach_form_node_type_form_alterImplementation of hook_form_FORM_ID_alter().
image_attach_image_add_submitSave attached image nids and rebuild form.
image_attach_menuImplementation of hook_menu()
image_attach_nodeapiImplementation of hook_nodeapi().
image_attach_node_form_submitExtra submit handler for node forms.
image_attach_permImplementation of hook_perm()
image_attach_themeImplementation of hook_theme() registry.
image_attach_validateImage attach validation handler for node edit form.
image_attach_views_apiViews 2 API handler
theme_image_attach_attached_imagesGeneric theme function for any set of attached images.
theme_image_attach_attached_images_blockTheme the attached images block.
theme_image_attach_attached_images_nodeTheme attached images shown in nodes.
theme_image_attach_form_thumbnailsTheme image thumbnails in editing ui to a drag-to-reorder table
_image_attach_get_image_nodesFetch an array of all candidate referenced nodes, for use in presenting the selection form to the user.
_image_attach_node_load_attachedHelper function for hook_nodeapi: view op. Loads all the required attached image nodes.
_image_attach_set_image_weightGet image weights and return an iid array ordered by weight.

Constants

NameDescription
IMAGE_ATTACH_HIDDEN

File

View source
  1. <?php
  2. /**
  3. * @file image_attach.module
  4. */
  5. define('IMAGE_ATTACH_HIDDEN', 'hidden');
  6. /**
  7. * Implementation of hook_menu()
  8. */
  9. function image_attach_menu() {
  10. $items['image_attach'] = array(
  11. 'title' => 'Image attachment view',
  12. 'page callback' => 'image_attach_view_image',
  13. 'access arguments' => array('access content'),
  14. 'type' => MENU_CALLBACK,
  15. );
  16. $items['admin/settings/image/image_attach'] = array(
  17. 'title' => 'Image attach',
  18. 'description' => 'Enable image attach for content.',
  19. 'page callback' => 'drupal_get_form',
  20. 'page arguments' => array('image_attach_admin_settings'),
  21. 'access arguments' => array('administer site configuration'),
  22. 'type' => MENU_LOCAL_TASK,
  23. );
  24. return $items;
  25. }
  26. /**
  27. * Implementation of hook_perm()
  28. */
  29. function image_attach_perm() {
  30. return array('attach images');
  31. }
  32. function image_attach_admin_settings() {
  33. $form['image_attach_existing'] = array(
  34. '#type' => 'radios',
  35. '#title' => t('Attach existing images'),
  36. '#default_value' => variable_get('image_attach_existing', 1),
  37. '#options' => array(
  38. 0 => t('Disabled'),
  39. 1 => t('Enabled'),
  40. ),
  41. '#description' => t('When enabled, will allow existing image nodes to be attached instead of uploading new images.'),
  42. );
  43. return system_settings_form($form);
  44. }
  45. /**
  46. * Implementation of hook_block().
  47. */
  48. function image_attach_block($op = 'list', $delta = 0, $edit = array()) {
  49. switch ($op) {
  50. case 'list':
  51. $blocks[0] = array(
  52. 'info' => t('Attached images'),
  53. 'weight' => 0,
  54. 'visibility' => 1,
  55. 'pages' => 'node/*',
  56. );
  57. return $blocks;
  58. case 'view':
  59. if ($delta == 0) {
  60. if (arg(0) == 'node' && is_numeric(arg(1))) {
  61. $node = node_load(arg(1));
  62. if (isset($node->iids)) {
  63. $output['subject'] = t('Attached images');
  64. foreach ($node->iids as $iid) {
  65. $image = node_load($iid);
  66. if (node_access('view', $image)) {
  67. $image_nodes[] = $image;
  68. }
  69. }
  70. $output['content'] = theme('image_attach_attached_images_block', $node->nid, $image_nodes);
  71. return $output;
  72. }
  73. }
  74. }
  75. break;
  76. case 'configure':
  77. if ($delta == 0) {
  78. $image_sizes = array();
  79. foreach (image_get_sizes() as $key => $size) {
  80. $image_sizes[$key] = $size['label'];
  81. }
  82. $form['image_attach_block_0_size'] = array(
  83. '#type' => 'select',
  84. '#title' => t('Image size'),
  85. '#default_value' => variable_get('image_attach_block_0_size', IMAGE_THUMBNAIL),
  86. '#options' => $image_sizes,
  87. '#description' => t('This determines the size of the image that appears in the block.'),
  88. );
  89. return $form;
  90. }
  91. break;
  92. case 'save':
  93. if ($delta == 0) {
  94. variable_set('image_attach_block_0_size', $edit['image_attach_block_0_size']);
  95. }
  96. break;
  97. }
  98. }
  99. /**
  100. * Implementation of hook_form_FORM_ID_alter().
  101. *
  102. * Add settings to the content type settings form.
  103. */
  104. function image_attach_form_node_type_form_alter(&$form, $form_state) {
  105. if ($form['#node_type']->type != 'image') {
  106. _image_check_settings();
  107. $image_sizes = array(IMAGE_ATTACH_HIDDEN => t('<Hidden>'));
  108. foreach (image_get_sizes() as $key => $size) {
  109. $image_sizes[$key] = $size['label'];
  110. }
  111. $form['image_attach'] = array(
  112. '#type' => 'fieldset',
  113. '#title' => t('Image Attach settings'),
  114. '#collapsible' => TRUE,
  115. '#collapsed' => TRUE,
  116. );
  117. $form['image_attach']['image_attach'] = array(
  118. '#type' => 'radios',
  119. '#title' => t('Attach images'),
  120. '#default_value' => variable_get('image_attach_' . $form['#node_type']->type, 0),
  121. '#options' => array(0 => t('Disabled'), 1 => t('Enabled')),
  122. '#description' => t('Should this node allows users to upload an image?'),
  123. );
  124. $form['image_attach']['image_attach_maximum'] = array(
  125. '#type' => 'select',
  126. '#title' => t('Maximum number of images'),
  127. '#default_value' => variable_get('image_attach_maximum_' . $form['#node_type']->type, 0),
  128. '#options' => array(0 => t('Unlimited')) + drupal_map_assoc(range(1, 10)),
  129. '#description' => t('The maximum number of images that may be attached to nodes of this type.'),
  130. );
  131. $form['image_attach']['image_attach_size_teaser'] = array(
  132. '#type' => 'select',
  133. '#title' => t('Teaser image size'),
  134. '#default_value' => variable_get('image_attach_size_teaser_' . $form['#node_type']->type, IMAGE_THUMBNAIL),
  135. '#options' => $image_sizes,
  136. '#description' => t("This determines the size of the image that appears when the node is displayed as a teaser. 'Hidden' will not show the image."),
  137. );
  138. // Hide the weight if CCK is doing the weight for us.
  139. if (!module_exists('content')) {
  140. $form['image_attach']['image_attach_weight_teaser'] = array(
  141. '#type' => 'weight',
  142. '#title' => t('Teaser image weight'),
  143. '#default_value' => variable_get('image_attach_weight_teaser_' . $form['#node_type']->type, 0),
  144. '#description' => t('This value determines the order of the image when displayed in the teaser.'),
  145. );
  146. }
  147. $form['image_attach']['image_attach_size_body'] = array(
  148. '#type' => 'select',
  149. '#title' => t('Full node image size'),
  150. '#default_value' => variable_get('image_attach_size_body_' . $form['#node_type']->type, IMAGE_THUMBNAIL),
  151. '#options' => $image_sizes,
  152. '#description' => t("This determines the size of the image that appears when the full node is displayed. 'Hidden' will not show the image."),
  153. );
  154. if (!module_exists('content')) {
  155. $form['image_attach']['image_attach_weight_body'] = array(
  156. '#type' => 'weight',
  157. '#title' => t('Full node image weight'),
  158. '#default_value' => variable_get('image_attach_weight_body_' . $form['#node_type']->type, 0),
  159. '#description' => t('This value determines the order of the image when displayed in the body.'),
  160. );
  161. }
  162. if (module_exists('content')) {
  163. $link = l(t('Manage fields'), $_GET['q'] . '/fields');
  164. $form['image_attach']['#description'] = t('Since you installed CCK module, you can change the image weight in the !link page.', array('!link' => $link));
  165. }
  166. }
  167. }
  168. /**
  169. * Implementation of hook_form_alter().
  170. */
  171. function image_attach_form_alter(&$form, $form_state, $form_id) {
  172. // Node edit form.
  173. if (isset($form['type']['#value']) && $form['type']['#value'] != 'image') {
  174. $type = $form['type']['#value'];
  175. // If enabled adjust the form.
  176. if ($form_id == $type . '_node_form' && variable_get('image_attach_' . $type, 0)) {
  177. $node = $form['#node'];
  178. _image_check_settings();
  179. $value = !empty($node->new_image) ? '#value' : '#default_value';
  180. $form['#attributes'] = array("enctype" => "multipart/form-data");
  181. // Add a custom submit handler so we can handle image creation on-the-fly
  182. $form['#validate'][] = 'image_attach_validate';
  183. // Add a custom submit handler so we can clean up the selection box items.
  184. $form['#submit'][] = 'image_attach_node_form_submit';
  185. // Check permissions and settings
  186. $may_attach = user_access('attach images');
  187. $may_attach_existing = variable_get('image_attach_existing', 1);
  188. $may_upload = user_access('create images');
  189. $has_existing_images = !empty($node->iids);
  190. $maximum_images = variable_get('image_attach_maximum_' . $type, 0);
  191. // Display the image attach form only if user can attach images, AND
  192. // it is allowed to attach existing images or the user is allowed to create new images
  193. if ($may_attach && ($may_attach_existing || $may_upload)) {
  194. $form['image_attach'] = array(
  195. '#type' => 'fieldset',
  196. '#title' => t('Attached images'),
  197. '#collapsible' => TRUE,
  198. '#collapsed' => empty($node->iids),
  199. );
  200. if ($maximum_images) {
  201. $form['image_attach']['#description'] = format_plural(
  202. $maximum_images,
  203. 'You may attach 1 image.',
  204. 'You may attach up to @count images.'
  205. );
  206. }
  207. if ($has_existing_images) {
  208. $form['image_attach']['image_thumbnail']['#theme'] = 'image_attach_form_thumbnails';
  209. $form['image_attach']['image_thumbnail']['#tree'] = TRUE;
  210. $weight = 0;
  211. foreach ($node->iids as $iid) {
  212. $image = node_load($iid);
  213. $form['image_attach']['image_thumbnail'][$iid] = array(
  214. 'id' => array(
  215. '#type' => 'hidden',
  216. '#value' => $iid,
  217. ),
  218. 'image' => array(
  219. '#type' => 'markup',
  220. '#value' => image_display($image, 'thumbnail'),
  221. ),
  222. 'delete' => array(
  223. '#type' => 'checkbox',
  224. ),
  225. 'title' => array(
  226. '#type' => 'markup',
  227. '#value' => check_plain($image->title),
  228. ),
  229. 'weight' => array(
  230. '#type' => 'weight',
  231. '#title' => t('Weight'),
  232. '#delta' => count($node->iids),
  233. '#default_value' => isset($form_state['values']['image_thumbnail'][$iid]) ? $form_state['values']['image_thumbnail'][$iid]['weight'] : $weight++,
  234. ),
  235. );
  236. }
  237. }
  238. // Only show selection box of image nodes if the user may attach some,
  239. // or if there are existings ones that may be removed.
  240. if ($may_attach_existing || $has_existing_images) {
  241. $form['image_attach']['iids'] = array(
  242. '#type' => 'select',
  243. $value => empty($node->iids) ? NULL : $node->iids,
  244. '#multiple' => TRUE,
  245. '#size' => 6,
  246. // Title, options and description are set just below.
  247. );
  248. // User may attach already existing images: show a selection box containing all images.
  249. if ($may_attach_existing) {
  250. $form['image_attach']['iids']['#title'] = t('Existing images');
  251. $form['image_attach']['iids']['#options'] = _image_attach_get_image_nodes();
  252. if ($may_upload) {
  253. $form['image_attach']['iids']['#description'] = t('Choose existing images if you do not upload a new one.');
  254. }
  255. else {
  256. $form['image_attach']['iids']['#description'] = t('Choose existing images to attach.');
  257. }
  258. }
  259. // User may only upload new images: show a selection box containing only attached images.
  260. else {
  261. $form['image_attach']['iids']['#title'] = t('Attached images');
  262. $form['image_attach']['iids']['#options'] = _image_attach_get_image_nodes($node->iids);
  263. $form['image_attach']['iids']['#description'] = t('You can remove a previously attached image by unselecting it.');
  264. }
  265. }
  266. // User may create images, add upload form elements.
  267. if ($may_upload) {
  268. $form['image_attach']['image'] = array(
  269. '#type' => 'file',
  270. '#size' => 40,
  271. '#title' => t('Upload image'),
  272. );
  273. $form['image_attach']['image_title'] = array(
  274. '#type' => 'textfield',
  275. '#title' => t('Image title'),
  276. $value => '',
  277. '#description' => t('The title the image will be shown with. Leave blank to use the filename.'),
  278. );
  279. // Provide an additional submit button, which adds an image and redirects
  280. // the user to the node edit form.
  281. $form['image_attach']['image_attach_multiple'] = array(
  282. '#type' => 'submit',
  283. '#value' => t('Upload'),
  284. '#validate' => array('image_attach_validate'),
  285. '#submit' => array('image_attach_image_add_submit'),
  286. );
  287. }
  288. }
  289. }
  290. }
  291. }
  292. /**
  293. * Get image weights and return an iid array ordered by weight.
  294. *
  295. * This private function is called by submit handlers to discover how the user
  296. * has ordered their images.
  297. * It returns an array with identical keys and values (just like the ordinary
  298. * iid array).
  299. *
  300. * @param $raw_weight_data
  301. * An array of iids and weights from the drag-to-reorder table, derived from
  302. * either the $form_state object or the $node object.
  303. * @param $select_box_array
  304. * The array of existing images that the user wants to include. This may be
  305. * different to the iids passed in $raw_weight_data.
  306. *
  307. * @return
  308. * A weight-sorted (from lightest to heaviest) array of iids, with identical
  309. * keys and (integer) values.
  310. */
  311. function _image_attach_set_image_weight($raw_weight_data, $select_box_array) {
  312. // Build up an array of iids => weights.
  313. $weights = array();
  314. foreach ($select_box_array as $iid) {
  315. // Check the delete box has not been ticked.
  316. if ($raw_weight_data[$iid]['delete'] !== 1) {
  317. // If the image exists in the drag-to-reorder array, get its weight, otherwise, assign it the heaviest weight possible.
  318. $weights[$iid] = isset($raw_weight_data[$iid]['weight']) ? $raw_weight_data[$iid]['weight'] : count($select_box_array);
  319. }
  320. }
  321. // Sort the iids array by weight.
  322. asort($weights);
  323. // Take the keys to make the return array.
  324. $items = drupal_map_assoc(array_keys($weights));
  325. return $items;
  326. }
  327. /**
  328. * Save attached image nids and rebuild form.
  329. *
  330. * This submit function adds the new images and returns to the
  331. * node edit form directly afterwards, without creating the new node yet.
  332. */
  333. function image_attach_image_add_submit(&$form, &$form_state) {
  334. // Rebuild the attached image data.
  335. if (isset($form_state['values']['iids'])) {
  336. db_query("DELETE FROM {image_attach} WHERE nid = %d", $form['nid']['#value']);
  337. // Sort the $form_state['values']['iids'] array by weight.
  338. if (count($form_state['values']['image_thumbnail'])) {
  339. $form_state['values']['iids'] = _image_attach_set_image_weight($form_state['values']['image_thumbnail'], $form_state['values']['iids']);
  340. }
  341. if (count($form_state['values']['iids'])) {
  342. $weight = 0;
  343. foreach ($form_state['values']['iids'] as $iid) {
  344. db_query("INSERT INTO {image_attach} (nid, iid, weight) VALUES (%d, %d, %d)", $form['nid']['#value'], $iid, $weight++);
  345. }
  346. }
  347. }
  348. // Convert taxonomy format from Preview to Object.
  349. if (module_exists('taxonomy') && !empty($form_state['values']['taxonomy'])) {
  350. $temp_node = new stdClass();
  351. $temp_node->taxonomy = $form_state['values']['taxonomy'];
  352. $form_state['values']['taxonomy'] = taxonomy_preview_terms($temp_node);
  353. unset($temp_node);
  354. }
  355. // Rebuild the node edit form.
  356. node_form_submit_build_node($form, $form_state);
  357. }
  358. /**
  359. * Image attach validation handler for node edit form.
  360. *
  361. * Check that the number of images has not exceeded the maximum.
  362. * Capture node form submission and immediately create an image if one has been
  363. * uploaded.
  364. * Note that the new image nodes are created even on preview. Taking several
  365. * attempts may create trash.
  366. */
  367. function image_attach_validate(&$form, &$form_state) {
  368. // Test for whether a file is being uploaded cribbed from file_save_upload().
  369. $uploading_new_image = isset($_FILES['files']) && $_FILES['files']['name']['image'] && is_uploaded_file($_FILES['files']['tmp_name']['image']);
  370. // Validate the number of attached images. Filter out the 'None' with array_filter.
  371. if ($maximum_images = variable_get('image_attach_maximum_' . $form['#node']->type, 0)) {
  372. if (is_array($form_state['values']['iids'])) {
  373. $num_images = count(array_filter($form_state['values']['iids']));
  374. }
  375. else {
  376. $num_images = 0;
  377. }
  378. $node_type_label = node_get_types('name', $form['#node']->type);
  379. if ($num_images >= $maximum_images && $uploading_new_image) {
  380. // This error will be set when attempting to upload a new image.
  381. // The number already selected may be equal to the maximum, in which case
  382. // the error is just to alert the user that their upload has not been performed, and allow
  383. // them to unselect an image and proceed to upload the new one.
  384. form_set_error('iids', t('There are @count_images images already attached. A new image cannot be uploaded until one or more attached images are unselected.', array(
  385. '@count_images' => format_plural($num_images, '1 image', '@count images'),
  386. '@maximum' => $maximum_images,
  387. '%type' => $node_type_label,
  388. )));
  389. }
  390. elseif ($num_images > $maximum_images) {
  391. form_set_error('iids', t('You have selected @count_images but the maximum for a %type is @maximum.', array(
  392. '@count_images' => format_plural($num_images, '1 image', '@count images'),
  393. '@maximum' => $maximum_images,
  394. '%type' => $node_type_label,
  395. )));
  396. }
  397. }
  398. // Validate and save the uploaded image, providing that there are no errors set.
  399. if (!count(form_get_errors())) {
  400. $validators = array(
  401. 'file_validate_is_image' => array(),
  402. );
  403. if ($file = file_save_upload('image', $validators)) {
  404. $image_title = $_POST['image_title'] ? $_POST['image_title'] : basename($file->filepath);
  405. // Initialize an image properly.
  406. $image = image_create_node_from($file->filepath, $image_title, '');
  407. if ($image && !form_get_errors()) {
  408. drupal_set_message(t("Created new image to attach to this node. !image_link", array('!image_link' => l($image_title, 'node/' . $image->nid))));
  409. // Append image nid to array of images.
  410. $form_state['values']['iids'][$image->nid] = $image->nid;
  411. }
  412. }
  413. else {
  414. // Only raise error if user clicked specific Upload button.
  415. if ($uploading_new_image) {
  416. form_set_error('image_attach', t('Invalid or missing image file for upload and attach.'));
  417. }
  418. }
  419. }
  420. }
  421. /**
  422. * Extra submit handler for node forms.
  423. */
  424. function image_attach_node_form_submit(&$form, &$form_state) {
  425. // Clear the 0 key in the iids array that arises from selecting the 'None'
  426. // option. We do this here so image_attach_nodeapi() gets clean data.
  427. unset($form_state['values']['iids'][0]);
  428. }
  429. /**
  430. * Implementation of hook_nodeapi().
  431. */
  432. function image_attach_nodeapi(&$node, $op, $teaser, $page) {
  433. // Make sure that if an image is deleted it is detached from any nodes.
  434. if ($node->type == 'image') {
  435. switch ($op) {
  436. case 'delete':
  437. db_query("DELETE FROM {image_attach} WHERE iid = %d", $node->nid);
  438. }
  439. return;
  440. }
  441. else if (variable_get('image_attach_' . $node->type, 0) == 0) {
  442. return;
  443. }
  444. switch ($op) {
  445. case 'insert':
  446. case 'update':
  447. db_query("DELETE FROM {image_attach} WHERE nid = %d", $node->nid);
  448. if (!empty($node->iids)) {
  449. if (!empty($node->image_thumbnail)) {
  450. // Form submitted, order iids according to drag-to-reorder table.
  451. $node->iids = _image_attach_set_image_weight($node->image_thumbnail, $node->iids);
  452. }
  453. $weight = 0;
  454. foreach ($node->iids as $iid) {
  455. db_query("INSERT INTO {image_attach} (nid, iid, weight) VALUES (%d, %d, %d)", $node->nid, $iid, $weight++);
  456. }
  457. }
  458. break;
  459. case 'delete':
  460. db_query("DELETE FROM {image_attach} WHERE nid = %d", $node->nid);
  461. break;
  462. case 'load':
  463. $res = db_query("SELECT iid FROM {image_attach} WHERE nid = %d ORDER BY weight", $node->nid);
  464. $iids = array();
  465. while ($iid = db_fetch_array($res)) {
  466. $iids[] = $iid['iid'];
  467. }
  468. return array('iids' => $iids);
  469. // Pass the body and teaser objects to the theme again to add the images.
  470. case 'view':
  471. if (!empty($node->iids)) {
  472. $node->image_attach = _image_attach_node_load_attached($node->iids, $teaser);
  473. $teaser_or_body = $teaser ? 'teaser' : 'body';
  474. $img_size = variable_get('image_attach_size_' . $teaser_or_body . '_' . $node->type, IMAGE_THUMBNAIL);
  475. // Don't show anything if the attached images are set to hidden.
  476. if ($img_size == IMAGE_ATTACH_HIDDEN) {
  477. return;
  478. }
  479. // Set weight, either from CCK or our own settings. Cribbed from signup!
  480. if (module_exists('content')) {
  481. // Due to a bug in CCK (http://drupal.org/node/363456), we need
  482. // to call this function twice to ensure we get the real value.
  483. // The bug is present when you first enable the setting to
  484. // display in the node instead of a separate tab, or when you
  485. // first upgrade to the version that contains this code.
  486. content_extra_field_weight($node->type, 'image_attach');
  487. $weight = content_extra_field_weight($node->type, 'image_attach');
  488. }
  489. else {
  490. $weight = variable_get("image_attach_weight_{$teaser_or_body}_{$node->type}", 0);
  491. }
  492. $node->content['image_attach'] = array(
  493. '#weight' => $weight,
  494. '#value' => theme('image_attach_attached_images_node', $node->nid, $node->image_attach, $img_size, $teaser),
  495. );
  496. }
  497. break;
  498. case 'rss item':
  499. $ret = array();
  500. if (!empty($node->iids) && $image = node_load($node->iids[0])) {
  501. $info = image_get_info(file_create_path($image->images[IMAGE_PREVIEW]));
  502. $ret[] = array(
  503. 'key' => 'enclosure',
  504. 'attributes' => array(
  505. 'url' => url("image/view/{$node->iids[0]}/" . IMAGE_PREVIEW, array('absolute' => TRUE)),
  506. 'length' => $info['file_size'],
  507. 'type' => $info['mime_type'],
  508. ),
  509. );
  510. }
  511. return $ret;
  512. }
  513. }
  514. /**
  515. * Helper function for hook_nodeapi: view op.
  516. * Loads all the required attached image nodes.
  517. *
  518. * @param $attached_nids
  519. * An array of node ids.
  520. * @param $teaser
  521. * If true, only load the first of the node ids.
  522. *
  523. * @return
  524. * An numerical array of node objects.
  525. */
  526. function _image_attach_node_load_attached($attached_nids, $teaser = FALSE) {
  527. if ($teaser) {
  528. // For the teaser we only want the first image from $attached_nids.
  529. // During normal node viewing the array is zero-keyed but during edit
  530. // preview it is keyed by iid. Therefore using array_shift() will return the
  531. // first image for either of these situations.
  532. $attached_nids = array(array_shift($attached_nids));
  533. }
  534. foreach ($attached_nids as $nid) {
  535. $nodes[] = node_load($nid);
  536. }
  537. return $nodes;
  538. }
  539. /**
  540. * Fetch an array of all candidate referenced nodes, for use in presenting the
  541. * selection form to the user.
  542. *
  543. * @param $nids
  544. * A list of nids to filter on. If not passed, all image nids are returned.
  545. */
  546. function _image_attach_get_image_nodes($nids = array()) {
  547. $placeholder = '';
  548. // If $nids was passed, build placeholders to put in the query
  549. if (count($nids)) {
  550. $placeholder = 'AND n.nid IN (' . implode(', ', array_fill(0, sizeof($nids), '%d')) . ') ';
  551. }
  552. $rows = array(0 => t('- None -'));
  553. $result = db_query(db_rewrite_sql("SELECT n.nid, n.title, n.sticky FROM {node} n WHERE n.status = 1 AND n.type = 'image' " . $placeholder . "ORDER BY n.sticky DESC, n.title ASC"), $nids);
  554. while ($node = db_fetch_object($result)) {
  555. $rows[$node->nid] = $node->title;
  556. }
  557. return $rows;
  558. }
  559. /**
  560. * Views 2 API handler
  561. */
  562. function image_attach_views_api() {
  563. return array(
  564. 'api' => 2,
  565. 'path' => drupal_get_path('module', 'image_attach'),
  566. );
  567. }
  568. /**
  569. * Implementation of hook_theme() registry.
  570. */
  571. function image_attach_theme() {
  572. return array(
  573. 'image_attach_attached_images' => array(
  574. 'arguments' => array(
  575. 'nid' => 0,
  576. 'image_nodes' => array(),
  577. 'options' => array(),
  578. ),
  579. ),
  580. 'image_attach_attached_images_node' => array(
  581. 'arguments' => array(
  582. 'node' => new stdClass(),
  583. 'image_nodes' => array(),
  584. 'img_size' => IMAGE_THUMBNAIL,
  585. 'teaser' => FALSE,
  586. ),
  587. ),
  588. 'image_attach_attached_images_block' => array(
  589. 'arguments' => array(
  590. 'nid' => 0,
  591. 'image_nodes' => array(),
  592. ),
  593. ),
  594. 'image_attach_form_thumbnails' => array(
  595. 'arguments' => array('form' => NULL),
  596. ),
  597. );
  598. }
  599. /**
  600. * Theme image thumbnails in editing ui to a drag-to-reorder table
  601. *
  602. * @param $form
  603. * The $form object
  604. */
  605. function theme_image_attach_form_thumbnails($form) {
  606. drupal_add_tabledrag('image-attach-thumbnails-draggable-table', 'order', 'sibling', 'weight');
  607. $header = array(t('Attached images'), t('Remove'), t('Title'), t('Weight'));
  608. foreach (element_children($form) as $key) {
  609. $element = &$form[$key];
  610. $element['weight']['#attributes']['class'] = 'weight';
  611. $row = array();
  612. $row[] = drupal_render($element['image']);
  613. $row[] = drupal_render($element['delete']);
  614. $row[] = drupal_render($element['title']);
  615. $row[] = drupal_render($element['weight']) . drupal_render($element['id']);
  616. $rows[] = array('data' => $row, 'class' => 'draggable');
  617. }
  618. $output = theme('table', $header, $rows, array('id' => 'image-attach-thumbnails-draggable-table'));
  619. $output .= drupal_render($form);
  620. return $output;
  621. }
  622. /**
  623. * Theme attached images shown in nodes.
  624. *
  625. * @param $nid
  626. * The attaching node's id.
  627. * @param $image_nodes
  628. * The node objects of the images to theme.
  629. * @param $img_size
  630. * The size at which to show images.
  631. * @param $teaser
  632. * Whether the $node is being shown as a teaser or not.
  633. *
  634. * Override this in template.php to include a case statement if you want
  635. * different node types to appear differently.
  636. * If you have additional image sizes you defined in image.module, you can
  637. * use them by theming this function as well.
  638. */
  639. function theme_image_attach_attached_images_node($nid, $image_nodes, $img_size, $teaser = FALSE) {
  640. drupal_add_css(drupal_get_path('module', 'image_attach') . '/image_attach.css');
  641. $options = array(
  642. 'size' => $img_size,
  643. 'link' => $teaser ? 'node' : 'image',
  644. 'attributes' => array(
  645. 'class' => 'image-attach-' . ($teaser ? 'teaser' : 'body'),
  646. ),
  647. );
  648. // We take the images in reverse order because they are floated to the right,
  649. // and we want the apparent left to right order to be correct.
  650. $output = theme('image_attach_attached_images', $nid, array_reverse($image_nodes), $options);
  651. // Wrap output of potentially multiple images in a DIV.
  652. if ($output && !$teaser) {
  653. $output = '<div class="all-attached-images">' . $output . '</div>';
  654. }
  655. return $output;
  656. }
  657. /**
  658. * Theme the attached images block.
  659. *
  660. * @param $nid
  661. * The attaching node's id.
  662. * @param $image_nodes
  663. * The attached image nodes.
  664. */
  665. function theme_image_attach_attached_images_block($nid, $image_nodes = array()) {
  666. // Only return block content if there are images.
  667. if (is_array($image_nodes) && count($image_nodes)) {
  668. $options = array(
  669. 'size' => variable_get('image_attach_block_0_size', IMAGE_THUMBNAIL),
  670. 'link' => 'image',
  671. );
  672. $output = theme('image_attach_attached_images', $nid, $image_nodes, $options);
  673. $output = '<div class="all-attached-images">' . $output . '</div>';
  674. return $output;
  675. }
  676. }
  677. /**
  678. * Generic theme function for any set of attached images.
  679. *
  680. * @param $nid
  681. * The id of the attaching node.
  682. * @param $image_nodes
  683. * The fully loaded image nodes to theme. These do not need to be checked for
  684. * access: that happens in this function.
  685. * @param $options
  686. * An associative array of options, with the following keys:
  687. * - 'size' (default IMAGE_THUMBNAIL)
  688. * The name of the image derivative size at which to show the images,
  689. * eg 'thumbnail'.
  690. * - 'link' (default 'image')
  691. * Whether and where the images should be linked. This should be one of:
  692. * - 'image': link to the image node. Default.
  693. * - 'node': link to the attaching node.
  694. * - 'none': no link.
  695. * - 'attributes'
  696. * Extra attributes for the div around each image.
  697. */
  698. function theme_image_attach_attached_images($nid, $image_nodes = array(), $options = array()) {
  699. // Merge in defaults.
  700. $options += array(
  701. 'size' => IMAGE_THUMBNAIL,
  702. 'link' => 'image',
  703. 'attributes' => array(),
  704. );
  705. $img_size = $options['size'];
  706. $link_destination = $options['link'];
  707. // Link images to the attaching node.
  708. if ($link_destination == 'node') {
  709. $link_path = "node/$nid";
  710. }
  711. $output = '';
  712. foreach ($image_nodes as $image) {
  713. if (!node_access('view', $image)) {
  714. // If the image is restricted, don't show it as an attachment.
  715. continue;
  716. }
  717. // Link images to the image node.
  718. if ($link_destination == 'image') {
  719. $link_path = "node/$image->nid";
  720. }
  721. // Get a fresh copy of the attributes for each image node.
  722. $div_attributes = $options['attributes'];
  723. // Create CSS classes, beginning with those passed in to the function.
  724. $classes = array();
  725. if (isset($div_attributes['class'])) {
  726. $classes[] = $div_attributes['class'];
  727. }
  728. // replace with base class in DIV
  729. //$classes[] = 'image-attach-' . $teaser_or_body;
  730. $classes[] = 'image-attach-node-' . $image->nid;
  731. if (!$image->status) {
  732. $classes[] = 'image-unpublished';
  733. }
  734. $div_attributes['class'] = implode(' ', $classes);
  735. // Add the width as inline CSS.
  736. $info = image_get_info(file_create_path($image->images[$img_size]));
  737. if (!isset($div_attributes['style'])) {
  738. $div_attributes['style'] = '';
  739. }
  740. $div_attributes['style'] .= 'width: ' . $info['width'] . 'px;';
  741. $output .= '<div' . drupal_attributes($div_attributes) . '>';
  742. $image_img = image_display($image, $img_size);
  743. if (isset($link_path)) {
  744. $output .= l($image_img, $link_path, array('html' => TRUE));
  745. }
  746. else {
  747. $output .= $image_img;
  748. }
  749. $output .= "</div>\n";
  750. }
  751. return $output;
  752. }
  753. /**
  754. * Implementation of hook_content_extra_fields().
  755. */
  756. function image_attach_content_extra_fields($type_name) {
  757. if (variable_get('image_attach_' . $type_name, 0)) {
  758. $extra['image_attach'] = array(
  759. 'label' => t('Attached images'),
  760. 'description' => t('Image Attach module form.'),
  761. 'weight' => 0,
  762. );
  763. return $extra;
  764. }
  765. }