#1067248 by KeesMK: Fixed function call to new style in media
[project/media_gallery.git] / media_gallery.module
1 <?php
2
3 /**
4 * @file
5 * Lets users create galleries made up of media items.
6 */
7
8 require_once(dirname(__FILE__) . '/media_gallery.fields.inc');
9 require_once(dirname(__FILE__) . '/fields_rsi_prevention.inc');
10
11 /**
12 * The pager element to use for paging through the media items in a gallery.
13 *
14 * We avoid using the default pager for now because there is too much risk of
15 * it colliding with other pagers initialized for the same page (for example,
16 * by the comment module, if the gallery node manages to get comment loading or
17 * display functions called on it).
18 */
19 define('MEDIA_GALLERY_PAGER_ELEMENT', 1);
20
21 /**
22 * Implements hook_menu().
23 */
24 function media_gallery_menu() {
25 $items['admin/config/media/galleries'] = array(
26 'title' => 'Gallery settings',
27 'description' => 'Configure settings for the "All galleries" page.',
28 'access arguments' => array('administer media galleries'),
29 'page callback' => 'media_gallery_admin_settings',
30 'file' => 'media_gallery.admin.inc',
31 );
32 $items['media-gallery/sort/collection/%taxonomy_term/%'] = array(
33 'title' => 'Gallery sort callback',
34 'access callback' => 'media_gallery_edit_access_ajax',
35 'access arguments' => array('collection', 3, 4),
36 'page callback' => 'media_gallery_ajax_sort',
37 'page arguments' => array('collection', 3),
38 'file' => 'media_gallery.pages.inc',
39 );
40 $items['media-gallery/sort/gallery/%node/%'] = array(
41 'title' => 'Gallery sort callback',
42 'access callback' => 'media_gallery_edit_access_ajax',
43 'access arguments' => array('gallery', 3, 4),
44 'page callback' => 'media_gallery_ajax_sort',
45 'page arguments' => array('gallery', 3),
46 'file' => 'media_gallery.pages.inc',
47 );
48 $items['media-gallery/detail/%node/%media'] = array(
49 'page callback' => 'media_gallery_detail_page',
50 'page arguments' => array(2, 3),
51 'access callback' => 'node_access',
52 'access arguments' => array('view', 2),
53 'file' => 'media_gallery.pages.inc',
54 );
55 $items['media-gallery/detail/%node/%media/view'] = array(
56 'title' => 'View',
57 'type' => MENU_DEFAULT_LOCAL_TASK,
58 'weight' => -10,
59 );
60 // An in-gallery-context version of media/%media/edit.
61 $items['media-gallery/detail/%node/%media/edit'] = array(
62 'title' => 'Edit',
63 'page callback' => 'media_gallery_media_page_edit',
64 'page arguments' => array(2, 3),
65 'access callback' => 'media_access',
66 'access arguments' => array('edit'),
67 'weight' => 0,
68 'type' => MENU_LOCAL_TASK,
69 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
70 'file' => 'media_gallery.pages.inc',
71 // Use the same setting as node module
72 'theme callback' => '_node_custom_theme',
73 );
74 $items['media-gallery/detail/%node/%media/remove'] = array(
75 'title' => 'Remove',
76 'page callback' => 'drupal_get_form',
77 'page arguments' => array('media_gallery_remove_item_form', 2, 3),
78 'access callback' => 'media_gallery_remove_item_access',
79 'access arguments' => array(2, 3),
80 'type' => MENU_LOCAL_TASK,
81 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
82 'file' => 'media_gallery.pages.inc',
83 // Use the same setting as node module.
84 'theme callback' => '_node_custom_theme',
85 );
86 $items['media-gallery/lightbox/%node/%media'] = array(
87 'page callback' => 'media_gallery_lightbox_page',
88 'page arguments' => array(2, 3),
89 'access callback' => 'node_access',
90 'access arguments' => array('view', 2),
91 'file' => 'media_gallery.pages.inc',
92 'delivery callback' => 'media_gallery_lightbox_page_deliver',
93 );
94 $items['media-gallery/add-images/%node/%'] = array(
95 'access callback' => 'media_gallery_edit_access_ajax',
96 'access arguments' => array('gallery', 2, 3),
97 'page callback' => 'media_gallery_add_images',
98 'page arguments' => array(2),
99 'file' => 'media_gallery.pages.inc',
100 );
101 // An in-gallery-context version of media/%media_multi/edit.
102 $items['node/%node/multiedit'] = array(
103 'title' => 'Edit media',
104 'page callback' => 'media_gallery_media_page_multiedit',
105 'page arguments' => array(1),
106 'access callback' => 'media_gallery_multiedit_access',
107 'access arguments' => array(1),
108 'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
109 'type' => MENU_LOCAL_TASK,
110 'file' => 'media_gallery.pages.inc',
111 );
112
113 // @todo Move to Media module once it is ready.
114 $items['media/%media/download'] = array(
115 'title' => 'Download',
116 'page callback' => 'media_download',
117 'page arguments' => array(1),
118 'access callback' => 'media_access',
119 'access arguments' => array('view'),
120 'type' => MENU_CALLBACK,
121 'file' => 'media.pages.inc',
122 );
123 return $items;
124 }
125
126 /**
127 * Implements hook_menu_alter().
128 */
129 function media_gallery_menu_alter(&$items) {
130 // Take over taxonomy term list pages by substituting our own callback.
131 // TODO: Use hook_entity_info_alter() to change the entity uri callback for
132 // gallery collections only.
133 $items['taxonomy/term/%taxonomy_term']['page callback'] = 'media_gallery_list_galleries';
134 $items['taxonomy/term/%taxonomy_term']['file'] = 'media_gallery.pages.inc';
135 $items['taxonomy/term/%taxonomy_term']['module'] = 'media_gallery';
136
137 // If you're viewing a media item in context somewhere (which we do inside
138 // media gallery nodes), that means it's being used on your site, which means
139 // you won't be allowed to delete it anyway. Therefore, do not show
140 // contextual links there.
141 // @todo Perhaps this should be changed in the media module itself?
142 $items['media/%media/delete']['context'] = MENU_CONTEXT_PAGE;
143 }
144
145 /**
146 * Implements hook_admin_paths().
147 */
148 function media_gallery_admin_paths() {
149 $paths = array(
150 'media-gallery/detail/*/*/edit' => TRUE,
151 'media-gallery/detail/*/*/remove' => TRUE,
152 'node/*/multiedit' => TRUE,
153 );
154 return $paths;
155 }
156
157 /**
158 * Implements hook_menu_local_tasks_alter().
159 */
160 function media_gallery_menu_local_tasks_alter(&$data, $router_item, $root_path) {
161 // Rename the "Edit" tab on gallery nodes to "Edit gallery".
162 if (($node = menu_get_object()) && isset($node->type) && $node->type == 'media_gallery') {
163 $tabs = &$data['tabs'][0]['output'];
164 foreach ($tabs as &$tab) {
165 if (isset($tab['#link']['path']) && $tab['#link']['path'] == 'node/%/edit') {
166 $tab['#link']['title'] = t('Edit gallery');
167 }
168 }
169 }
170
171 // Rename the "Edit" tab on the "All Galleries" taxonomy term to "Edit all
172 // galleries" and point it to our configuration page.
173 // @todo: Once we have additional gallery-related taxonomy terms and
174 // http://drupal.org/node/678592 is committed to core (so the term edit
175 // pages show the correct admin theme) we'll do something different here,
176 // perhaps not even alter anything at all.
177 if (($term = menu_get_object('taxonomy_term', 2)) && isset($term->vid) && $term->vid == variable_get('media_gallery_collection_vid')) {
178 $tabs = &$data['tabs'][0]['output'];
179 foreach ($tabs as &$tab) {
180 if (isset($tab['#link']['path']) && $tab['#link']['path'] == 'taxonomy/term/%/edit') {
181 $tab['#link']['href'] = 'admin/config/media/galleries';
182 $tab['#link']['title'] = t('Edit all galleries');
183 }
184 }
185 }
186 }
187
188 /**
189 * Implements hook_node_load().
190 */
191 function media_gallery_node_load($nodes, $types) {
192 // Store a copy of the media_gallery_media field before mucking with it in
193 // media_gallery_view(). We use hook_node_load() instead of hook_load(),
194 // because the latter runs before fields are loaded.
195 if (in_array('media_gallery', $types)) {
196 foreach ($nodes as $node) {
197 if ($node->type == 'media_gallery') {
198 $node->media_gallery_media_original = $node->media_gallery_media;
199 }
200 }
201 }
202 }
203
204 /**
205 * Implements hook_view().
206 */
207 function media_gallery_view($node, $view_mode) {
208 // Add display elements and resources for users who can edit the gallery.
209 if (node_access('update', $node)) {
210 // Add the "Add images" link, themed as a local action. Note that this
211 // element is listed in hook_field_extra_fields(), so whether or not it
212 // will *actually* be displayed in the current view mode depends on the
213 // site's configuration for the corresponding pseudo-field.
214 $node->content['add_media_link'] = array(
215 '#theme' => 'menu_local_action',
216 '#link' => array(
217 'title' => t('Add media'),
218 'href' => 'media/browser',
219 'localized_options' => array(
220 'query' => array('render' => 'media-popup'),
221 'attributes' => array(
222 'class' => 'media-gallery-add launcher',
223 ),
224 ),
225 ),
226 // @todo Drupal could really use a theme_menu_local_actions() function...
227 '#prefix' => '<ul class="field action-links">',
228 '#suffix' => '</ul>',
229 // Add front-end resources related to this link, only when it is actually
230 // being rendered.
231 '#pre_render' => array('media_gallery_add_images_link_pre_render'),
232 );
233
234 // These JS settings are used by the "add media" link but are also shared
235 // by the drag-and-drop code below.
236 $gallery_js_settings = array(
237 'mediaGalleryNid' => $node->nid,
238 'mediaGalleryToken' => drupal_get_token('media_gallery'),
239 );
240
241 // When viewing the full node, add front-end resources for drag-and-drop
242 // sorting.
243 if ($view_mode == 'full') {
244 drupal_add_css(drupal_get_path('module', 'media_gallery') . '/media_gallery.dragdrop.css');
245 drupal_add_library('system', 'ui.sortable');
246 drupal_add_js(drupal_get_path('module', 'media_gallery') . '/media_gallery.dragdrop.js');
247 drupal_add_js($gallery_js_settings, array('type' => 'setting'));
248 }
249 else {
250 // Otherwise, attach the setting to the "add media" link, as per above.
251 $node->content['add_media_link']['#attached']['js'][] = array(
252 'type' => 'setting',
253 'data' => $gallery_js_settings,
254 );
255 }
256 }
257
258 // For the teaser, only the first thumbnail needs to be displayed, so remove the
259 // rest from the node's field data, so that the field formatter doesn't waste
260 // time building the render structure for items that won't be shown.
261 if ($view_mode == 'teaser') {
262 if (!empty($node->media_gallery_media[LANGUAGE_NONE])) {
263 $first_item = array_shift($node->media_gallery_media[LANGUAGE_NONE]);
264 $node->media_gallery_media[LANGUAGE_NONE] = array($first_item);
265 }
266 }
267 // For the full display, implement pagination.
268 elseif ($view_mode == 'full' || $view_mode == 'media_gallery_block') {
269 $full = $view_mode == 'full' ? TRUE : FALSE;
270 if (!empty($node->media_gallery_media)) {
271 $media = $full ? $node->media_gallery_media[LANGUAGE_NONE] : $node->media_gallery_media_original[LANGUAGE_NONE];
272 }
273 else {
274 $media = array();
275 }
276
277 // Only display the requested number of media items per page.
278 $columns = $full ? $node->media_gallery_columns[LANGUAGE_NONE][0]['value'] : $node->media_gallery_block_columns[LANGUAGE_NONE][0]['value'];
279 $rows = $full ? $node->media_gallery_rows[LANGUAGE_NONE][0]['value'] : $node->media_gallery_block_rows[LANGUAGE_NONE][0]['value'];
280 $number_per_page = $columns * $rows;
281 $deltas = array_keys($media);
282 $total = count($deltas);
283
284 // Initialize the pager and find out what page we are viewing.
285 $page = $full ? pager_default_initialize($total, $number_per_page, MEDIA_GALLERY_PAGER_ELEMENT) : 0;
286
287 // Deny access to all media items that aren't on this page.
288 $min_on_page = $number_per_page * $page;
289 $max_on_page = $number_per_page * ($page + 1) - 1;
290 $pre_links = array();
291 $post_links = array();
292 foreach ($deltas as $key => $delta) {
293 $item = $media[$delta];
294 $fid = _media_gallery_get_media_fid($item);
295 if ($key < $min_on_page) {
296 $pre_links[$key] = array(
297 'title' => '',
298 'href' => 'media-gallery/detail/' . $node->nid . '/' . $fid,
299 'attributes' => array('class' => array('colorbox-supplemental-link pre')),
300 );
301 unset($media[$delta]);
302 }
303 elseif ($key > $max_on_page) {
304 $post_links[$key] = array(
305 'title' => '',
306 'href' => 'media-gallery/detail/' . $node->nid . '/' . $fid,
307 'attributes' => array('class' => array('colorbox-supplemental-link post')),
308 );
309 unset($media[$delta]);
310 }
311 }
312
313 // Field rendering requires sequential deltas, so re-key.
314 // @todo Open a Drupal core issue about this.
315
316 if ($media) {
317 $node->media_gallery_media[LANGUAGE_NONE] = array_values($media);
318 }
319 else {
320 $node->media_gallery_media[LANGUAGE_NONE] = array();
321 }
322
323 // Create a set of dummy links to media items that don't appear on this
324 // page, so colorbox can link to them in the slideshow.
325 // @todo If the gallery contains 1000 media, then rendering each link takes
326 // extra server-side time, extra network time to transfer the markup, and
327 // extra client-side time to initialize the DOM. Performance can likely be
328 // significantly improved if we only send the fids to Drupal.settings, and
329 // add JavaScript code to make that information usable by Colorbox.
330 $node->content['colorbox_links_pre'] = array(
331 '#theme' => 'links',
332 '#links' => $pre_links,
333 '#weight' => -20,
334 '#attributes' => array('class' => array('colorbox-supplemental-links')),
335 );
336 $node->content['colorbox_links_post'] = array(
337 '#theme' => 'links',
338 '#links' => $post_links,
339 '#weight' => 20,
340 '#attributes' => array('class' => array('colorbox-supplemental-links')),
341 );
342 // Finally, display the pager, with a high weight so it appears at the
343 // bottom.
344 if ($full) {
345 $node->content['media_gallery_pager'] = array(
346 '#theme' => 'pager',
347 '#element' => MEDIA_GALLERY_PAGER_ELEMENT,
348 '#weight' => 2000,
349 );
350 }
351 }
352 return $node;
353 }
354
355 /**
356 * Prerender function to add front-end resources for the "Add media" link.
357 */
358 function media_gallery_add_images_link_pre_render($elements) {
359 drupal_add_library('media', 'media_browser');
360 module_load_include('inc', 'media', 'media.browser');
361 media_attach_browser_js($elements);
362 drupal_add_js(drupal_get_path('module', 'media_gallery') . '/media_gallery.addimage.js');
363 return $elements;
364 }
365
366 /**
367 * Implements hook_field_extra_fields().
368 */
369 function media_gallery_field_extra_fields() {
370 // Allow the "Add media" link to be sorted with respect to the actual media
371 // gallery fields.
372 $extra['node']['media_gallery'] = array(
373 'display' => array(
374 'add_media_link' => array(
375 'label' => t('"Add media" link'),
376 'weight' => 1,
377 ),
378 ),
379 );
380
381 return $extra;
382 }
383
384 /**
385 * Access callback for AJAX-based gallery editing operations.
386 *
387 * @param string $type
388 * The type of item being edited: 'gallery' for an individual gallery or
389 * 'collection' for a gallery collection.
390 * @param mixed $item
391 * For a media gallery, the $node object for that gallery; for gallery
392 * collections, the taxonomy term corresponding to the collection.
393 * @param string $token
394 * A token from drupal_get_token.
395 */
396 function media_gallery_edit_access_ajax($type, $item, $token) {
397 if (!drupal_valid_token($token, 'media_gallery')) {
398 return FALSE;
399 }
400 switch ($type) {
401 case 'gallery':
402 return node_access('update', $item);
403 break;
404 case 'collection':
405 return user_access('administer media galleries');
406 break;
407 default:
408 return FALSE;
409 }
410 }
411
412 /**
413 * Implements hook_theme().
414 */
415 function media_gallery_theme() {
416 return array(
417 'media_gallery_collection' => array(
418 'render element' => 'element',
419 'file' => 'media_gallery.theme.inc',
420 ),
421 'media_gallery_teaser' => array(
422 'render element' => 'element',
423 'file' => 'media_gallery.theme.inc',
424 ),
425 'media_gallery_media_item_thumbnail' => array(
426 'render element' => 'element',
427 'file' => 'media_gallery.theme.inc',
428 'template' => 'media-gallery-media-item-thumbnail',
429 ),
430 'media_gallery_media_item_lightbox' => array(
431 'render element' => 'element',
432 'file' => 'media_gallery.theme.inc',
433 ),
434 'media_gallery_media_item_detail' => array(
435 'render element' => 'element',
436 'file' => 'media_gallery.theme.inc',
437 ),
438 'media_gallery_block_thumbnail' => array(
439 'render element' => 'element',
440 'file' => 'media_gallery.theme.inc',
441 ),
442 'media_gallery_collection_thumbnail' => array(
443 'render element' => 'element',
444 'file' => 'media_gallery.theme.inc',
445 ),
446 'media_gallery_download_link' => array(
447 'variables' => array('file' => NULL, 'text' => NULL, 'options' => array()),
448 'file' => 'media_gallery.theme.inc',
449 ),
450 'media_gallery_meta' => array(
451 'variables' => array('display' => NULL, 'location' => NULL, 'title' => NULL, 'license' => NULL, 'description' => NULL),
452 'file' => 'media_gallery.theme.inc',
453 ),
454 'media_gallery_item' => array(
455 'variables' => array('image' => NULL, 'link_path' => NULL, 'classes' => NULL),
456 'file' => 'media_gallery.theme.inc',
457 ),
458 'media_gallery_license' => array(
459 'variables' => array('element' => NULL, 'color' => 'dark'),
460 'file' => 'media_gallery.theme.inc',
461 ),
462 'media_gallery_file_field_inline' => array(
463 'render element' => 'element',
464 'file' => 'media_gallery.theme.inc',
465 ),
466 );
467 }
468
469 /**
470 * Implements hook_permission().
471 */
472 function media_gallery_permission() {
473 return array(
474 'administer media galleries' => array(
475 'title' => t('Administer media galleries'),
476 ),
477 );
478 }
479
480 /**
481 * Implements hook_node_info().
482 */
483 function media_gallery_node_info() {
484 return array(
485 'media_gallery' => array(
486 'name' => t('Gallery'),
487 'base' => 'media_gallery',
488 'description' => t('A flexible gallery of media.'),
489 'help' => t('Create a gallery of thumbnails including custom display settings. Once your gallery is saved, your media can be added.'),
490 ),
491 );
492 }
493
494 /**
495 * Implements hook_update().
496 */
497 function media_gallery_update($node) {
498 // If the media gallery node is being saved and is configured to not provide
499 // a block, remove all blocks associated with it from the database.
500 if (empty($node->media_gallery_expose_block[LANGUAGE_NONE][0]['value'])) {
501 db_delete('block')
502 ->condition('module', 'media_gallery')
503 ->condition('delta', $node->nid)
504 ->execute();
505 }
506 }
507
508 /**
509 * Implements hook_block_info().
510 */
511 function media_gallery_block_info() {
512 $blocks = array();
513
514 // Define a block for each media gallery node that is configured to expose
515 // one.
516 $query = new EntityFieldQuery();
517 $query->entityCondition('entity_type', 'node');
518 $query->entityCondition('bundle', 'media_gallery');
519 $query->fieldCondition('media_gallery_expose_block', 'value', 1);
520 $result = $query->execute();
521 if (!empty($result['node'])) {
522 // There is no reason to waste going through a full node_load_multiple()
523 // when we only need the titles.
524 $nids = array_keys($result['node']);
525 $node_titles = db_query("SELECT nid, title FROM {node} WHERE nid IN (:nids)", array(':nids' => $nids))->fetchAllKeyed();
526 foreach ($node_titles as $nid => $title) {
527 // The 'info' element is escaped on display, so we pass it through
528 // unfiltered here.
529 $blocks[$nid]['info'] = t('Recent gallery items: !title', array('!title' => $title));
530 $blocks[$nid]['visibility'] = 0;
531 $blocks[$nid]['pages'] = 'node/' . $nid . "\ngalleries";
532 }
533 }
534
535 return $blocks;
536 }
537
538 /**
539 * Implements hook_block_view().
540 */
541 function media_gallery_block_view($delta = '') {
542 $node = node_load($delta);
543 $block['subject'] = check_plain($node->title);
544 if (empty($node->media_gallery_media_original)) {
545 // Bail out now if there won't be any media items to show.
546 $block['content'] = t('No content available.');
547 }
548 else {
549 // Collect an array of file IDs associated with this gallery. For
550 // simplicity we will assume (here and below) that this is not a
551 // multilingual field. Also note that the node may have been loaded and
552 // viewed elsewhere on the page, in which case the 'media_gallery_media'
553 // field was modified and does not contain what we want, so we have to go
554 // back to the original field value set in hook_node_load() instead, and
555 // also clone the node before changing it so our modifications do not
556 // affect other places where it might be being viewed.
557 $node = clone $node;
558 $node->media_gallery_media = $node->media_gallery_media_original;
559 $files = &$node->media_gallery_media[LANGUAGE_NONE];
560 $gallery_fids = array();
561 foreach ($files as $file) {
562 $gallery_fids[] = _media_gallery_get_media_fid($file);
563 }
564 // Construct a list of file IDs that is limited to the specified number of
565 // items and ordered by most recent; these are the files that will be
566 // displayed in the block.
567 $columns = !empty($node->media_gallery_block_columns[LANGUAGE_NONE][0]['value']) ? $node->media_gallery_block_columns[LANGUAGE_NONE][0]['value'] : 1;
568 $rows = !empty($node->media_gallery_block_rows[LANGUAGE_NONE][0]['value']) ? $node->media_gallery_block_rows[LANGUAGE_NONE][0]['value'] : 1;
569 $number_to_show = $columns * $rows;
570 $block_fids = db_select('file_managed', 'f')
571 ->fields('f', array('fid'))
572 ->condition('fid', $gallery_fids, 'IN')
573 ->orderBy('timestamp', 'DESC')
574 ->range(0, $number_to_show)
575 ->execute()
576 ->fetchCol();
577 // Before sorting, remove any items that will not display in the block.
578 $fid_order = array_flip($block_fids);
579 if ($number_to_show < count($files)) {
580 foreach ($files as $key => $file) {
581 if (!isset($fid_order[_media_gallery_get_media_fid($file)])) {
582 unset($files[$key]);
583 }
584 }
585 }
586 // Prepare the sorting function with the list of file ID orders.
587 _media_gallery_sort_by_recent(NULL, NULL, $fid_order);
588 // Perform the sort.
589 usort($files, '_media_gallery_sort_by_recent');
590 // Display the block.
591 $block['content'] = node_view($node, 'media_gallery_block');
592 $block['content']['more_link'] = array(
593 '#theme' => 'more_link',
594 '#url' => 'node/' . $node->nid,
595 '#title' => t('Show the complete gallery'),
596 '#weight' => 1000,
597 );
598 }
599
600 return $block;
601 }
602
603 /**
604 * Implements hook_block_configure().
605 */
606 function media_gallery_block_configure($delta = '') {
607 // Duplicate the form for configuring media gallery node fields, including
608 // our module's custom alterations. We can't use drupal_get_form() here
609 // because that will mess up the form submission, so for now we have to live
610 // without getting any other module's alterations to this part of the node
611 // form.
612 $node = node_load($delta);
613 $form = array();
614 $form_state = array();
615 field_attach_form('node', $node, $form, $form_state, $node->language);
616 media_gallery_form_media_gallery_node_form_alter($form, $form_state);
617
618 // Pull out only the parts of the node form that allow configuration of the
619 // block settings; these are the ones we want to display.
620 $block_settings = array('block' => $form['block']);
621
622 // Store a record of all node fields that we will need to save when
623 // hook_block_save() is called.
624 $block_settings['block']['media_gallery_block_fields'] = array(
625 '#type' => 'value',
626 '#value' => element_children($block_settings['block']),
627 );
628
629 // Don't allow people to destroy the block itself from the block
630 // configuration page.
631 $block_settings['block']['media_gallery_expose_block']['#access'] = FALSE;
632
633 // Customize the fieldset display.
634 $block_settings['block']['#collapsible'] = FALSE;
635 $block_settings['block']['#title'] = t('Block settings');
636 unset($block_settings['block']['#weight']);
637
638 // Add the necessary attached JS and CSS.
639 _media_gallery_attach_form_resources($block_settings['block']);
640
641 return $block_settings;
642 }
643
644 /**
645 * Implements hook_block_save().
646 */
647 function media_gallery_block_save($delta = '', $edit = array()) {
648 // Save the block-related media gallery fields on the node.
649 $node = node_load($delta);
650 foreach ($edit['media_gallery_block_fields'] as $field) {
651 $node->{$field} = $edit[$field];
652 }
653 node_save($node);
654 }
655
656 /**
657 * Implements hook_library().
658 */
659 function media_gallery_library() {
660 $library_path = variable_get('media_gallery_library_path', 'sites/all/libraries');
661 $stylesheet = variable_get('media_gallery_colorbox_stylesheet', 'example1');
662 $libraries['colorbox'] = array(
663 'title' => 'Colorbox',
664 'website' => 'http://colorpowered.com/colorbox/',
665 'version' => '1.3.9',
666 'js' => array(
667 $library_path . '/colorbox/colorbox/jquery.colorbox-min.js' => array(),
668 ),
669 'css' => array(
670 $library_path . '/colorbox/' . $stylesheet . '/colorbox.css' => array(
671 'type' => 'file',
672 'media' => 'screen',
673 ),
674 ),
675 );
676 return $libraries;
677 }
678
679 /**
680 * Helper function to sort media gallery items by an ordered list of file IDs.
681 *
682 * Call once with $set_fid_order set to an array of file orders, keyed by the
683 * file ID, before performing the actual sort.
684 */
685 function _media_gallery_sort_by_recent($a, $b, $set_fid_order = NULL) {
686 $fid_order = &drupal_static(__FUNCTION__, array());
687 // Stored the ordered list if this is a preparatory call.
688 if (isset($set_fid_order)) {
689 $fid_order = $set_fid_order;
690 return;
691 }
692 // Otherwise, perform the sort.
693 $a_order = $fid_order[_media_gallery_get_media_fid($a)];
694 $b_order = $fid_order[_media_gallery_get_media_fid($b)];
695 if ($a_order < $b_order) {
696 return -1;
697 }
698 elseif ($b_order < $a_order) {
699 return 1;
700 }
701 else {
702 return 0;
703 }
704 }
705
706 /**
707 * Returns the number of files of each type attached to a media gallery node.
708 */
709 function media_gallery_get_media_type_count($node, $media_field = 'media_gallery_media') {
710 $fids = media_gallery_get_file_ids($node, $media_field);
711 if (empty($fids)) {
712 return array();
713 }
714 $query = db_select('file_managed', 'f');
715 $type = $query->addField('f', 'type');
716 $query->addExpression('COUNT(*)');
717 $type_count = $query->condition('f.fid', $fids, 'IN')
718 ->groupBy($type)
719 ->execute()
720 ->fetchAllKeyed();
721 return $type_count;
722 }
723
724 /**
725 * Returns all file IDs attached to a media gallery node.
726 */
727 function media_gallery_get_file_ids($node, $media_field = 'media_gallery_media') {
728 $fids = array();
729 $enhanced_node = new FieldsRSIPreventor($node);
730 foreach ($enhanced_node->getAllItems($media_field) as $item) {
731 $fids[] = _media_gallery_get_media_fid($item);
732 }
733 return drupal_map_assoc($fids);
734 }
735
736 /**
737 * Determines the file ID from a media file array or object.
738 *
739 * This is ugly, but necessary since a media field attached to a node may
740 * be represented either as an array or a full object, depending on whether the
741 * node has been processed for viewing yet or not.
742 *
743 * @param $file
744 * Either a media file object or media file array.
745 *
746 * @return
747 * The value of the 'fid' object property or array key.
748 */
749 function _media_gallery_get_media_fid($file) {
750 return is_object($file) ? $file->fid : $file['fid'];
751 }
752
753 /**
754 * Removes a media item from a gallery.
755 *
756 * @param $node
757 * The gallery node object.
758 * @param $media
759 * The media item object to remove from the gallery.
760 *
761 * @return
762 * The updated gallery node object.
763 */
764 function media_gallery_remove_item_from_gallery($node, $media) {
765 $items = &$node->media_gallery_media[LANGUAGE_NONE];
766 foreach ($items as $key => $item) {
767 if ($media->fid == _media_gallery_get_media_fid($item)) {
768 unset($items[$key]);
769 }
770 }
771 node_save($node);
772 return $node;
773 }
774
775 /**
776 * Implements hook_entity_info_alter().
777 */
778 function media_gallery_entity_info_alter(&$info) {
779 // For each media field formatter we add, we also need to add the
780 // corresponding media entity view mode.
781 foreach (media_gallery_field_formatter_info() as $formatter_name => $formatter_info) {
782 if (in_array('media', $formatter_info['field types'])) {
783 $info['media']['view modes'][$formatter_name] = array('label' => $formatter_info['label'], 'custom settings' => FALSE);
784 }
785 }
786 // Add a view mode for displaying a node in a media gallery block.
787 $info['node']['view modes']['media_gallery_block'] = array(
788 'label' => t('Media gallery block'),
789 'custom settings' => FALSE,
790 );
791 }
792
793 /**
794 * Implements hook_form().
795 */
796 function media_gallery_form($node, $form_state) {
797 $form = node_content_form($node, $form_state);
798 return $form;
799 }
800
801 /**
802 * Implements hook_form_alter().
803 */
804 function media_gallery_form_alter(&$form, &$form_state, $form_id) {
805 if (strpos($form_id, 'media_edit') === 0) {
806 // Act on both the regular and multiform versions of the edit form.
807 if ($form_id === 'media_edit' || preg_match('/^media_edit_[0-9]+$/', $form_id)) {
808 // Prepopulate the media_edit form with our best guess at the image title.
809 if (!empty($form['media_title']) && empty($form['media_title'][LANGUAGE_NONE][0]['value']['#default_value'])) {
810 $fid = $form['fid']['#value'];
811 $entity = media_load($fid);
812 if ($entity->type === 'image') {
813 $form['media_title'][LANGUAGE_NONE][0]['value']['#default_value'] = _media_gallery_get_media_title($entity);
814 }
815 }
816 // Prepopulate the license field with the correct default.
817 if ($form['field_license'][LANGUAGE_NONE]['#default_value'] == '_none') {
818 $form['field_license'][LANGUAGE_NONE]['#default_value'] = 'none';
819 }
820 unset($form['field_license'][LANGUAGE_NONE]['#options']['_none']);
821 }
822 }
823 }
824
825 /*
826 * Implements hook_form_FORM_ID_alter().
827 */
828 function media_gallery_form_media_gallery_node_form_alter(&$form, &$form_state) {
829 _media_gallery_attach_form_resources($form);
830
831 // The UI for the multi value media field and the node weight is elsewhere.
832 $form['media_gallery_media']['#access'] = FALSE;
833 $form['media_gallery_weight']['#access'] = FALSE;
834
835 // Hiding this field because we only support a single collection at the moment.
836 $form['media_gallery_collection']['#access'] = FALSE;
837
838 // Wrap a fieldset around the gallery settings.
839 $form['settings_wrapper'] = array(
840 '#type' => 'fieldset',
841 '#title' => t('Gallery settings'),
842 '#weight' => 10,
843 );
844
845 unset($form['media_gallery_lightbox_extras'][LANGUAGE_NONE]['#description']);
846 $form['media_gallery_lightbox_extras'][LANGUAGE_NONE]['#label'] = 'Show title and description';
847
848 // These are the items that need to be added to the fieldset. The array
849 // values represent a subgroup within the fieldset array that the items are
850 // further grouped by.
851 $fieldset = array(
852 'media_gallery_columns' => 'gallery',
853 'media_gallery_rows' => 'gallery',
854 'media_gallery_image_info_where' => 'gallery',
855 'media_gallery_allow_download' => 'presentation',
856 'media_gallery_format' => 'presentation',
857 'media_gallery_lightbox_extras' => 'presentation',
858 );
859
860 // Move the items to the fieldset.
861 foreach($fieldset as $id => $subgroup) {
862 $form['settings_wrapper'][$subgroup][$id] = $form[$id];
863 unset($form[$id]);
864 }
865
866 // Add a vertical tab menu for blocks
867 $form['block'] = array(
868 '#type' => 'fieldset',
869 '#title' => 'Blocks',
870 '#collapsible' => TRUE,
871 '#collapsed' => FALSE,
872 '#group' => 'additional_settings',
873 '#attached' => array(),
874 '#weight' => -100,
875 );
876
877 $fieldset = array(
878 'media_gallery_expose_block' => 'block',
879 'media_gallery_block_columns' => 'block',
880 'media_gallery_block_rows' => 'block',
881 );
882
883 // Move the items to the fieldset.
884 foreach($fieldset as $id => $subgroup) {
885 $form[$subgroup][$id] = $form[$id];
886 unset($form[$id]);
887 }
888
889 // Add a class to the fieldset to target it in the js
890 $form['block']['#attributes']['class'] = array('block-form');
891
892 // Add classes where necessary for JS enhancement.
893 $form['settings_wrapper']['gallery']['media_gallery_image_info_where']['#attributes']['class'][] = 'form-inline label';
894 $form['settings_wrapper']['gallery']['media_gallery_image_info']['#attributes']['class'][] = 'form-inline';
895
896 // Use #prefix and #suffix to group the fields.
897 $form['settings_wrapper']['presentation']['media_gallery_format']['#attributes']['class'][] = 'media-gallery-show no-group-label';
898 $form['settings_wrapper']['gallery']['#prefix'] = '<div class="gallery-settings settings-group hidden clearfix"><div class="setting-icon"></div><div class="no-overflow">';
899 $form['settings_wrapper']['gallery']['#suffix'] = '</div></div>';
900
901 $form['settings_wrapper']['presentation']['#prefix'] = '<div class="presentation-settings settings-group hidden clearfix"><div class="group-label">' . t('Presentation settings') . '</div><div class="setting-icon"></div><div class="no-overflow">';
902 $form['settings_wrapper']['presentation']['#suffix'] = '</div></div>';
903
904 // Enhance the "number of rows" textfields by adding a dropdown element.
905 $form['settings_wrapper']['gallery']['media_gallery_rows']['#process'][] = 'media_gallery_process_dropdown';
906 $form['settings_wrapper']['gallery']['media_gallery_rows']['#media_gallery_dropdown_options'] = array('1', '3', '5', '10', 'other');
907 $form['block']['media_gallery_block_rows']['#process'][] = 'media_gallery_process_dropdown';
908 $form['block']['media_gallery_block_rows']['#media_gallery_dropdown_options'] = array('1', '2', '3', '4', 'other');
909
910 // Adjust the weight of the fields in the presentation wrapper
911 $form['settings_wrapper']['presentation']['media_gallery_allow_download']['#weight'] = 0;
912
913 // @todo At some point, it would be nice to have a functional preview display
914 // of gallery nodes, but until happens, remove the Preview button.
915 $form['actions']['preview']['#access'] = FALSE;
916 }
917
918 /**
919 * Implements hook_form_FORM_ID_alter().
920 */
921 function media_gallery_form_media_edit_alter(&$form, &$form_state) {
922 // Adjust the media edit form when it is show within Gallery context.
923 if (isset($form_state['media_gallery']['gallery'])) {
924 // Remove the Delete button, since media entities can't be deleted when they
925 // are in-use.
926 $form['actions']['delete']['#access'] = FALSE;
927
928 // @todo Should we provide a "Remove" button for removing the media item
929 // from the gallery, or is requiring the user to use the "Remove" tab
930 // preferable?
931
932 // Add a submit handler to alter $form_state['redirect'] to the
933 // in-gallery-context View page. It's annoying to have to add a submit
934 // handler for this, but see http://drupal.org/node/579366#comment-2099836.
935 // Make sure to add this for the form-level submit handlers and also for the
936 // button-level submit handlers of the "Save" button, in case those are
937 // being used.
938 $form['#submit'][] = 'media_gallery_media_edit_submit';
939 if (isset($form['actions']['submit']['#submit'])) {
940 $form['actions']['submit']['#submit'][] = 'media_gallery_media_edit_submit';
941 }
942 }
943 }
944
945 /**
946 * Form submit handler for media entity edit form in gallery context.
947 *
948 * @see media_gallery_form_media_edit_alter()
949 */
950 function media_gallery_media_edit_submit($form, &$form_state) {
951 $form_state['redirect'] = 'media-gallery/detail/' . $form_state['media_gallery']['gallery']->nid . '/' . $form_state['values']['fid'];
952 }
953
954 /**
955 * Implements hook_field_attach_form().
956 */
957 function media_gallery_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
958 // Remove the ability for a user to select a license for externally hosted
959 // media.
960 if ($entity_type == 'media') {
961 $scheme = file_uri_scheme($entity->uri);
962 // @todo Implement a more generic determination for when it makes sense for
963 // a user to select a license and when it doesn't.
964 if ($scheme == 'youtube') {
965 $form['field_license']['#access'] = FALSE;
966 }
967 }
968 }
969
970 /**
971 * Helper function to attach JS/CSS for media galleries to a form element.
972 */
973 function _media_gallery_attach_form_resources(&$element) {
974 $element['#attached']['js'][] = drupal_get_path('module', 'media_gallery') . '/media_gallery.form.js';
975 _media_gallery_attach_css_resources($element);
976 }
977
978 /**
979 * Helper function to attach CSS for media galleries to a render element.
980 */
981 function _media_gallery_attach_css_resources(&$element) {
982 $path = drupal_get_path('module', 'media_gallery');
983 $element['#attached']['css'][] = $path . '/media_gallery.css';
984 $element['#attached']['css'][] = array(
985 'data' => $path . '/media_gallery.ie7.css',
986 'browsers' => array('IE' => 'lt IE 8', '!IE' => FALSE),
987 );
988 }
989
990 /**
991 * Implements hook_node_view_alter().
992 */
993 function media_gallery_node_view_alter(&$build) {
994 // This is for the Galleries plural page
995 if ($build['#bundle'] == 'media_gallery' && $build['#view_mode'] == 'teaser') {
996 // Hide node links.
997 $build['links']['#access'] = FALSE;
998 unset($build['#contextual_links']);
999 _media_gallery_attach_css_resources($build);
1000 }
1001 // This is for when a gallery is being shown in a block
1002 elseif ($build['#view_mode'] == 'media_gallery_block') {
1003 // Hide node links.
1004 $build['links']['#access'] = FALSE;
1005 _media_gallery_attach_css_resources($build);
1006 }
1007 // This is for when a gallery is being shown on its own, single gallery page.
1008 elseif ($build['#bundle'] == 'media_gallery' && $build['#view_mode'] == 'full') {
1009 if (!empty($build['media_gallery_media'])) {
1010 foreach (element_children($build['media_gallery_media']) as $delta) {
1011 // For each media item, add contextual links to the in-gallery-context
1012 // tasks that can be performed on a media item.
1013 $fid = $build['media_gallery_media'][$delta]['#media_gallery_media_entity']->fid;
1014 $build['media_gallery_media'][$delta]['#contextual_links']['media_gallery'] = array('media-gallery/detail', array($build['#node']->nid, $fid));
1015 }
1016 }
1017 _media_gallery_attach_css_resources($build);
1018 }
1019 }
1020
1021 /**
1022 * Implements MODULE_preprocess_node().
1023 */
1024 function media_gallery_preprocess_node(&$variables) {
1025 // Do not show the title when a node is being displayed in a media gallery
1026 // block.
1027 if ($variables['view_mode'] == 'media_gallery_block') {
1028 $variables['title'] = '';
1029 }
1030
1031 // Gallery teasers (for example, the ones that appear on the Galleries page)
1032 // require special theming of their content. We set that up here instead of as
1033 // part of hook_node_view_alter() or similar, because we want the node itself
1034 // to have #theme='node' as normal, and only want to add special theming for
1035 // the node content, but the content element isn't created until
1036 // template_preprocess_node().
1037 if ($variables['node']->type == 'media_gallery' && $variables['view_mode'] == 'teaser') {
1038 $variables['content']['#theme'] = 'media_gallery_teaser';
1039 $variables['content']['#node'] = $variables['node'];
1040 }
1041 }
1042
1043 /**
1044 * Implements MODULE_preprocess_menu_local_task().
1045 */
1046 function media_gallery_preprocess_menu_local_task(&$variables) {
1047 // Persist the "page" URL query parameter from the "view" tab to the
1048 // "multiedit" tab for gallery nodes. In the future, we may want to expand
1049 // this to cover more than just the "multiedit" tab. Since this code runs for
1050 // every local task of every page, we try to determine no-op conditions as
1051 // quickly as possible.
1052 if (isset($_GET['page']) && !isset($variables['element']['#link']['localized_options']['query']['page']) && strpos($variables['element']['#link']['href'], 'node/') == 0) {
1053 $nid = arg(1, $variables['element']['#link']['href']);
1054 if (is_numeric($nid) && arg(2, $variables['element']['#link']['href']) == 'multiedit') {
1055 $node = node_load($nid);
1056 if ($node->type == 'media_gallery') {
1057 $page = pager_find_page(MEDIA_GALLERY_PAGER_ELEMENT);
1058 if (is_int($page)) {
1059 $variables['element']['#link']['localized_options']['query']['page'] = "$page";
1060 }
1061 }
1062 }
1063 }
1064 }
1065
1066 /**
1067 * Implements hook_contextual_links_view_alter().
1068 */
1069 function media_gallery_contextual_links_view_alter(&$element, $items) {
1070 // Modify the contextual links on gallery blocks; we only want to allow
1071 // editing the gallery and configuring the block, and we want a more
1072 // descriptive title for the edit link.
1073 if (isset($element['#element']['#block']->module) && $element['#element']['#block']->module == 'media_gallery' && !empty($element['#links'])) {
1074 $links = &$element['#links'];
1075 foreach ($links as $key => &$link) {
1076 if ($key != 'node-edit' && $key != 'block-configure') {
1077 unset($links[$key]);
1078 }
1079 elseif ($key == 'node-edit') {
1080 $link['title'] = t('Edit gallery');
1081 }
1082 }
1083 }
1084 }
1085
1086 /**
1087 * Preprocess function for theme_field().
1088 */
1089 function media_gallery_preprocess_field(&$variables, $hook) {
1090 if ($variables['element']['#field_name'] === 'media_gallery_media') {
1091 $columns = 1;
1092 switch($variables['element']['#view_mode']) {
1093 case 'media_gallery_block':
1094 $columns = $variables['element']['#object']->media_gallery_block_columns['und'][0]['value'];
1095 break;
1096 case 'full':
1097 $columns = $variables['element']['#object']->media_gallery_columns['und'][0]['value'];
1098 break;
1099 }
1100 // Don't add the columning classes if the field is being displayed in a teaser
1101 $variables['classes_array'][] = ($variables['element']['#view_mode'] != 'teaser') ? 'clearfix media-gallery-media mg-col mg-col-' . $columns : 'clearfix media-gallery-media';
1102 foreach ($variables['items'] as $delta => $item) {
1103 $variables['item_attributes_array'][$delta] = array('id' => 'media-gallery-media-' . $delta);
1104
1105 }
1106 }
1107 }
1108
1109 /**
1110 * Media gallery equivalent to taxonomy_select_nodes().
1111 */
1112 function media_gallery_select_galleries($tid, $pager = TRUE, $limit = FALSE) {
1113 if (!variable_get('taxonomy_maintain_index_table', TRUE)) {
1114 return array();
1115 }
1116 $query = db_select('taxonomy_index', 't');
1117 $query->leftJoin('media_gallery_weight', 'mgw', 'mgw.nid = t.nid AND mgw.tid = :tid', array(':tid' => $tid));
1118 $query->addTag('node_access');
1119 $query->condition('t.tid', $tid);
1120 if ($pager) {
1121 $count_query = clone $query;
1122 $count_query->addExpression('COUNT(t.nid)');
1123
1124 $query = $query->extend('PagerDefault');
1125 if ($limit !== FALSE) {
1126 $query = $query->limit($limit);
1127 }
1128 $query->setCountQuery($count_query);
1129 }
1130 else {
1131 if ($limit !== FALSE) {
1132 $query->range(0, $limit);
1133 }
1134 }
1135 $query->addField('t', 'nid');
1136 $query->addField('t', 'tid');
1137 $query->addField('mgw', 'weight');
1138 $query->orderBy('mgw.weight', 'ASC');
1139 $query->orderBy('t.nid', 'ASC');
1140 $result = $query->execute();
1141 return $result->fetchCol();
1142 }
1143
1144 /**
1145 * Implements hook_form_FORM_ID_alter().
1146 *
1147 * Used to modify the taxonomy term edit screen for gallery collection settings.
1148 */
1149 function media_gallery_form_taxonomy_form_term_alter(&$form, &$form_state) {
1150 // This form is used for deleting taxonomy terms also (in which case
1151 // $form['#term'] has a totally different structure) so make sure to check
1152 // those conditions first before continuing. We only want to alter this form
1153 // if a media gallery taxonomy term is being edited.
1154 if (isset($form_state['confirm_delete']) || !is_array($form['#term']) || $form['#term']['vid'] != variable_get('media_gallery_collection_vid')) {
1155 return;
1156 }
1157
1158 $form['introduction'] = array(
1159 '#weight' => -10,
1160 '#markup' => check_plain(t('The following settings affect the "All galleries" page, which shows a thumbnail of every gallery created.')),
1161 );
1162 $form['#attributes']['class'][] = 'form-media-gallery-collection';
1163 $form['name']['#title'] = t('Title');
1164 $form['path']['alias']['#title'] = check_plain(t('"All galleries" URL'));
1165 $form['path']['alias']['#weight'] = -1;
1166 $form['path']['alias']['#field_prefix'] = url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=');
1167 unset($form['path']['alias']['#description']);
1168 _media_gallery_attach_form_resources($form);
1169
1170 // These are the items that need to be added to the fieldset. The array
1171 // values represent a subgroup within the fieldset array that the items are
1172 // further grouped by.
1173 $fieldset = array(
1174 'media_gallery_columns' => 'gallery',
1175 'media_gallery_rows' => 'gallery',
1176 'media_gallery_image_info_where' => 'gallery',
1177 );
1178
1179 // Move the items to the fieldset.
1180 foreach($fieldset as $id => $subgroup) {
1181 $form['settings_wrapper'][$subgroup][$id] = $form[$id];
1182 unset($form[$id]);
1183 }
1184
1185 $form['settings_wrapper']['gallery']['media_gallery_image_info_where']['#attributes']['class'][] = 'form-inline label';
1186 // Use #prefix and #suffix to group the fields.
1187 $form['settings_wrapper']['gallery']['#prefix'] = '<div class="galleries-settings settings-group hidden"><div class="group-label">' . check_plain(t('"All galleries" layout settings')) . '</div><div class="setting-icon"></div><div class="no-overflow">';
1188 $form['settings_wrapper']['gallery']['#suffix'] = '</div></div>';
1189
1190 // Enhance the "number of rows" textfield by adding a dropdown element.
1191 $form['settings_wrapper']['gallery']['media_gallery_rows']['#process'][] = 'media_gallery_process_dropdown';
1192 $form['settings_wrapper']['gallery']['media_gallery_rows']['#media_gallery_dropdown_options'] = array('1', '3', '5', '10', 'other');
1193
1194 $form['relations']['#access'] = FALSE;
1195 $form['actions']['delete']['#access'] = FALSE;
1196 $form['field_license']['#access'] = FALSE;
1197
1198 // Add a submit handler to change the "Updated term" message on submit.
1199 $form['#submit'][] = 'media_gallery_taxonomy_form_term_submit';
1200 }
1201
1202 /**
1203 * Submit handler for the taxonomy_form_term form.
1204 */
1205 function media_gallery_taxonomy_form_term_submit($form, &$form_state) {
1206 // Change the "Updated term Galleries" message into something that makes
1207 // sense in this context.
1208 $term_name = $form_state['values']['name'];
1209 $messages = $_SESSION['messages']['status'];
1210 $updated_message = t('Updated term %term.', array('%term' => $term_name));
1211 foreach ($messages as $key => $message) {
1212 if ($message === $updated_message) {
1213 $_SESSION['messages']['status'][$key] = t('The gallery settings have been saved.');
1214 }
1215 }
1216 }
1217
1218 /**
1219 * Implements hook_form_FORM_ID_alter().
1220 *
1221 * Used to hide the gallery_collections taxonomy admin screens.
1222 */
1223 function media_gallery_form_taxonomy_overview_vocabularies_alter(&$form, &$form_state) {
1224 $gallery_collection_vid = variable_get('media_gallery_collection_vid');
1225 unset($form[$gallery_collection_vid]);
1226 }
1227
1228 /**
1229 * Implements hook_module_implements_alter().
1230 */
1231 function media_gallery_module_implements_alter(&$implementations, $hook) {
1232 switch ($hook) {
1233 // TODO: All we really need to control here is
1234 // form_taxonomy_form_term_alter; if D7 gets fixed to allow that level of
1235 // control, this can be changed.
1236 //case 'form_taxonomy_form_term_alter':
1237 case 'form_alter':
1238 if (!isset($implementations['media_gallery'])){
1239 break;
1240 }
1241 $group = $implementations['media_gallery'];
1242 unset($implementations['media_gallery']);
1243 $implementations['media_gallery'] = $group;
1244 break;
1245 // We need to ensure that these hooks run before the corresponding Pathauto
1246 // implementations. Given what they do, it's harmless to put them at the
1247 // very front of the list, so we do that because it's easiest.
1248 case 'taxonomy_term_insert':
1249 case 'taxonomy_term_update':
1250 if (isset($implementations['media_gallery'])) {
1251 $implementations = array('media_gallery' => $implementations['media_gallery']) + $implementations;
1252 }
1253 break;
1254 }
1255 }
1256
1257 /**
1258 * Gets the first term in the media_gallery_collection vocabulary
1259 */
1260 function media_gallery_get_default_gallery_collection() {
1261 $gallery_collection_vid = variable_get('media_gallery_collection_vid');
1262 $tid = db_select('taxonomy_term_data', 'ttd')
1263 ->fields('ttd', array('tid'))
1264 ->condition('vid', $gallery_collection_vid)
1265 ->range(0,1)
1266 ->execute()
1267 ->fetchField();
1268
1269 return taxonomy_term_load($tid);
1270 }
1271
1272 /**
1273 * Access callback for editing parts of a node that are only relevant for media
1274 * galleries.
1275 */
1276 function media_gallery_edit_access($node) {
1277 if (!node_access('update', $node)) {
1278 return FALSE;
1279 }
1280 if ($node->type == 'media_gallery') {
1281 return TRUE;
1282 }
1283 }
1284
1285 /**
1286 * Access callback for editing parts of a node that are only relevant for media
1287 * galleries.
1288 */
1289 function media_gallery_multiedit_access($node) {
1290 if (media_gallery_edit_access($node)) {
1291 $node = new FieldsRSIPreventor($node);
1292 if (count($node->getAllItems('media_gallery_media')) > 0 ) {
1293 return TRUE;
1294 }
1295 }
1296 }
1297
1298 /**
1299 * Access callback for removing a media item from a gallery.
1300 *
1301 * @param $node
1302 * The gallery node object.
1303 * @param $media
1304 * The media item object to remove from the gallery.
1305 *
1306 * @return
1307 * TRUE if access is granted; FALSE otherwise.
1308 */
1309 function media_gallery_remove_item_access($node, $media) {
1310 // Only grant access if the user can edit the gallery and the provided media
1311 // item is attached to the gallery.
1312 return media_gallery_edit_access($node) && in_array($media->fid, media_gallery_get_file_ids($node));
1313 }
1314
1315 /**
1316 * Implement hook_image_default_styles().
1317 */
1318 function media_gallery_image_default_styles() {
1319 $styles = array();
1320 $styles['media_gallery_thumbnail'] = array(
1321 'effects' => array(
1322 array(
1323 // @todo We want to not upscale if the user uploads a smaller image, but
1324 // image_scale_and_crop doesn't support that option. Try to get
1325 // http://drupal.org/node/872206 into core, or solve it in contrib.
1326 'name' => 'image_scale_and_crop',
1327 'data' => array('width' => 450, 'height' => 450, 'upscale' => FALSE),
1328 'weight' => 0,
1329 ),
1330 )
1331 );
1332 $styles['media_gallery_large'] = array(
1333 'effects' => array(
1334 array(
1335 'name' => 'image_scale',
1336 'data' => array('width' => 900, 'height' => 900, 'upscale' => FALSE),
1337 'weight' => 0,
1338 ),
1339 )
1340 );
1341 return $styles;
1342 }
1343
1344 /**
1345 * Implements hook_styles_presets().
1346 */
1347 function media_gallery_styles_presets() {
1348 $presets = array(
1349 'file' => array(
1350 'media_gallery_thumbnail' => array(
1351 'media_youtube' => array(
1352 'youtube_thumbnail_media_gallery_thumbnail',
1353 ),
1354 ),
1355 'media_gallery_large' => array(
1356 'media_youtube' => array(
1357 'youtube_full',
1358 ),
1359 ),
1360 ),
1361 );
1362 return $presets;
1363 }
1364
1365 /**
1366 * Implements hook_media_wysiwyg_allowed_view_modes_alter().
1367 *
1368 * We don't want media's WYSIWYG form to show the view modes for galleries.
1369 * So we remove any of the view modes we create.
1370 */
1371 function media_gallery_media_wysiwyg_allowed_view_modes_alter($bundle, &$view_modes) {
1372 require_once dirname(__FILE__) . '/media_gallery.fields.inc';
1373 // While these technically aren't view modes, we know they are all media
1374 // view_modes as well as media formatters.
1375 $media_gallery_view_modes = media_gallery_field_formatter_info();
1376 $view_modes = array_diff_key($view_modes, $media_gallery_view_modes);
1377 }
1378
1379 /**
1380 * Form #process function for attaching dropdown-related classes and settings.
1381 */
1382 function media_gallery_process_dropdown($element, &$form_state) {
1383 $element['#attributes']['class'][] = 'media-gallery-dropdown';
1384 $element['#attached']['js'][] = array(
1385 'type' => 'setting',
1386 'data' => array(
1387 'media_gallery_dropdown_options' => array(
1388 $element['#id'] => $element['#media_gallery_dropdown_options'],
1389 ),
1390 ),
1391 );
1392
1393 return $element;
1394 }
1395
1396 /**
1397 * Implements hook_taxonomy_term_insert().
1398 */
1399 function media_gallery_taxonomy_term_insert($term) {
1400 // Note that in hook_module_implements_alter() we guarantee that this code
1401 // will always run before Pathauto's implementation.
1402 _media_gallery_prevent_unwanted_pathauto_aliases($term);
1403 }
1404
1405 /**
1406 * Implements hook_taxonomy_term_update().
1407 */
1408 function media_gallery_taxonomy_term_update($term) {
1409 // Note that in hook_module_implements_alter() we guarantee that this code
1410 // will always run before Pathauto's implementation.
1411 _media_gallery_prevent_unwanted_pathauto_aliases($term);
1412 }
1413
1414 /**
1415 * Implements hook_entity_insert().
1416 */
1417 function media_gallery_entity_insert($entity, $type) {
1418 // This hook is used because it always runs after Pathauto's
1419 // hook_taxonomy_term_insert() implementation.
1420 if ($type == 'taxonomy_term') {
1421 _media_gallery_allow_all_pathauto_aliases();
1422 }
1423 }
1424
1425 /**
1426 * Implements hook_entity_update().
1427 */
1428 function media_gallery_entity_update($entity, $type) {
1429 // This hook is used because it always runs after Pathauto's
1430 // hook_taxonomy_term_update() implementation.
1431 if ($type == 'taxonomy_term') {
1432 _media_gallery_allow_all_pathauto_aliases();
1433 }
1434 }
1435
1436 /**
1437 * Hack to prevent Pathauto from generating unwanted taxonomy aliases.
1438 *
1439 * This function can be called before allowing the Pathauto module to act on a
1440 * saved term for the taxonomy vocabulary used for media galleries. It prevents
1441 * Pathauto from generating an alias for the term based on the generic Pathauto
1442 * taxonomy alias settings (i.e., an alias will only be generated if the site
1443 * is specifically configured to have aliases generated for the vocabulary, not
1444 * for taxonomy terms in general).
1445 *
1446 * The reason we want to do this is so that the URL alias people save on the
1447 * media gallery settings page will actually work.
1448 *
1449 * If a $term object is not provided, then this function will always act; if
1450 * one is provided, then it will only act if the term corresponds to the media
1451 * gallery default collection.
1452 *
1453 * Call _media_gallery_allow_all_pathauto_aliases() after the term is saved to
1454 * resume normal Pathauto behavior for the rest of the page request.
1455 */
1456 function _media_gallery_prevent_unwanted_pathauto_aliases($term = NULL) {
1457 if (!isset($term) || $term->tid == variable_get('media_gallery_default_collection_tid')) {
1458 if (isset($GLOBALS['conf']['pathauto_taxonomy_pattern'])) {
1459 $GLOBALS['conf']['media_gallery_original_pathauto_taxonomy_pattern'] = $GLOBALS['conf']['pathauto_taxonomy_pattern'];
1460 }
1461 $GLOBALS['conf']['pathauto_taxonomy_pattern'] = '';
1462 }
1463 }
1464
1465 /**
1466 * Restores Pathauto behavior after we are done hacking with it.
1467 *
1468 * @see _media_gallery_prevent_unwanted_pathauto_aliases()
1469 */
1470 function _media_gallery_allow_all_pathauto_aliases() {
1471 if (isset($GLOBALS['conf']['media_gallery_original_pathauto_taxonomy_pattern'])) {
1472 $GLOBALS['conf']['pathauto_taxonomy_pattern'] = $GLOBALS['conf']['media_gallery_original_pathauto_taxonomy_pattern'];
1473 }
1474 }