File: /home/nexper/public_html/sites/all/modules/media_gallery/media_gallery.module
<?php
/**
* @file
* Lets users create galleries made up of media items.
*/
require_once(dirname(__FILE__) . '/media_gallery.fields.inc');
require_once(dirname(__FILE__) . '/fields_rsi_prevention.inc');
/**
* The pager element to use for paging through the media items in a gallery.
*
* We avoid using the default pager for now because there is too much risk of
* it colliding with other pagers initialized for the same page (for example,
* by the comment module, if the gallery node manages to get comment loading or
* display functions called on it).
*/
define('MEDIA_GALLERY_PAGER_ELEMENT', 1);
/**
* Helper function to return the view modes used by this module for displaying files in gallery context.
*/
function media_gallery_file_view_modes() {
return array(
'media_gallery_thumbnail' => t('Gallery thumbnail'),
'media_gallery_lightbox' => t('Gallery lightbox'),
'media_gallery_detail' => t('Gallery detail'),
'media_gallery_block_thumbnail' => t('Gallery block thumbnail'),
'media_gallery_collection_thumbnail' => t('Gallery collection thumbnail'),
);
}
/**
* Implements hook_menu().
*/
function media_gallery_menu() {
$items['admin/config/media/galleries'] = array(
'title' => 'Gallery settings',
'description' => 'Configure settings for the "All galleries" page.',
'access arguments' => array('administer media galleries'),
'page callback' => 'media_gallery_admin_settings',
'file' => 'media_gallery.admin.inc',
);
$items['media-gallery/sort/collection/%taxonomy_term/%'] = array(
'title' => 'Gallery sort callback',
'access callback' => 'media_gallery_edit_access_ajax',
'access arguments' => array('collection', 3, 4),
'page callback' => 'media_gallery_ajax_sort',
'page arguments' => array('collection', 3),
'file' => 'media_gallery.pages.inc',
);
$items['media-gallery/sort/gallery/%node/%'] = array(
'title' => 'Gallery sort callback',
'access callback' => 'media_gallery_edit_access_ajax',
'access arguments' => array('gallery', 3, 4),
'page callback' => 'media_gallery_ajax_sort',
'page arguments' => array('gallery', 3),
'file' => 'media_gallery.pages.inc',
);
$items['media-gallery/detail/%node/%file'] = array(
'page callback' => 'media_gallery_detail_page',
'page arguments' => array(2, 3),
'access callback' => 'media_gallery_view_item_access',
'access arguments' => array(2, 3),
'file' => 'media_gallery.pages.inc',
);
$items['media-gallery/detail/%node/%file/view'] = array(
'title' => 'View',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -10,
);
// An in-gallery-context version of media/%file/edit.
$items['media-gallery/detail/%node/%file/edit'] = array(
'title' => 'Edit',
'page callback' => 'media_gallery_media_page_edit',
'page arguments' => array(2, 3),
'access callback' => 'media_gallery_edit_item_access',
'access arguments' => array(2, 3),
'weight' => 0,
'type' => MENU_LOCAL_TASK,
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'file' => 'media_gallery.pages.inc',
);
$items['media-gallery/detail/%node/%file/remove'] = array(
'title' => 'Remove',
'page callback' => 'drupal_get_form',
'page arguments' => array('media_gallery_remove_item_form', 2, 3),
'access callback' => 'media_gallery_remove_item_access',
'access arguments' => array(2, 3),
'type' => MENU_LOCAL_TASK,
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'file' => 'media_gallery.pages.inc',
);
$items['media-gallery/lightbox/%node/%file'] = array(
'page callback' => 'media_gallery_lightbox_page',
'page arguments' => array(2, 3),
'access callback' => 'media_gallery_view_item_access',
'access arguments' => array(2, 3),
'file' => 'media_gallery.pages.inc',
'delivery callback' => 'media_gallery_lightbox_delivery_callback',
);
$items['media-gallery/add-images/%node/%'] = array(
'access callback' => 'media_gallery_edit_access_ajax',
'access arguments' => array('gallery', 2, 3),
'page callback' => 'media_gallery_add_images',
'page arguments' => array(2),
'file' => 'media_gallery.pages.inc',
);
// An in-gallery-context version of media/%media_multi/edit.
$items['node/%node/multiedit'] = array(
'title' => 'Edit media',
'page callback' => 'media_gallery_media_page_multiedit',
'page arguments' => array(1),
'access callback' => 'media_gallery_multiedit_access',
'access arguments' => array(1),
'context' => MENU_CONTEXT_PAGE | MENU_CONTEXT_INLINE,
'type' => MENU_LOCAL_TASK,
'file' => 'media_gallery.pages.inc',
);
// @todo Move to Media module once it is ready.
$items['media/%file/download'] = array(
'title' => 'Download',
'page callback' => 'media_download',
'page arguments' => array(1),
'access callback' => 'media_access',
'access arguments' => array('view'),
'type' => MENU_CALLBACK,
'file' => 'media.pages.inc',
);
return $items;
}
/**
* Implements hook_menu_alter().
*/
function media_gallery_menu_alter(&$items) {
// Take over taxonomy term list pages by substituting our own callback.
// TODO: Use hook_entity_info_alter() to change the entity uri callback for
// gallery collections only.
$items['taxonomy/term/%taxonomy_term']['page callback'] = 'media_gallery_list_galleries';
$items['taxonomy/term/%taxonomy_term']['file'] = 'media_gallery.pages.inc';
$items['taxonomy/term/%taxonomy_term']['module'] = 'media_gallery';
// If you're viewing a media item in context somewhere (which we do inside
// media gallery nodes), that means it's being used on your site, which means
// you won't be allowed to delete it anyway. Therefore, do not show
// contextual links there.
// @todo Perhaps this should be changed in the media module itself?
$items['media/%file/delete']['context'] = MENU_CONTEXT_PAGE;
}
/**
* Implements hook_admin_paths().
*/
function media_gallery_admin_paths() {
$paths = array(
'media-gallery/detail/*/*/edit' => TRUE,
'media-gallery/detail/*/*/remove' => TRUE,
'node/*/multiedit' => TRUE,
);
return $paths;
}
/**
* Implements hook_menu_local_tasks_alter().
*/
function media_gallery_menu_local_tasks_alter(&$data, $router_item, $root_path) {
// Rename the "Edit" tab on gallery nodes to "Edit gallery".
if (($node = menu_get_object()) && isset($node->type) && $node->type == 'media_gallery' && !empty($data['tabs'])) {
$tabs = &$data['tabs'][0]['output'];
foreach ($tabs as &$tab) {
if (isset($tab['#link']['path']) && $tab['#link']['path'] == 'node/%/edit') {
$tab['#link']['title'] = t('Edit gallery');
}
}
}
// Rename the "Edit" tab on the "All Galleries" taxonomy term to "Edit all
// galleries" and point it to our configuration page.
// @todo: Once we have additional gallery-related taxonomy terms and
// http://drupal.org/node/678592 is committed to core (so the term edit
// pages show the correct admin theme) we'll do something different here,
// perhaps not even alter anything at all.
if (($term = menu_get_object('taxonomy_term', 2)) && isset($term->vid) && $term->vid == variable_get('media_gallery_collection_vid')) {
$tabs = &$data['tabs'][0]['output'];
foreach ($tabs as &$tab) {
if (isset($tab['#link']['path']) && $tab['#link']['path'] == 'taxonomy/term/%/edit') {
$tab['#link']['href'] = 'admin/config/media/galleries';
$tab['#link']['title'] = t('Edit all galleries');
}
}
}
}
/**
* Implements hook_node_load().
*/
function media_gallery_node_load($nodes, $types) {
// Store a copy of the media_gallery_media field before mucking with it in
// media_gallery_view(). We use hook_node_load() instead of hook_load(),
// because the latter runs before fields are loaded.
if (in_array('media_gallery', $types)) {
foreach ($nodes as $node) {
if ($node->type == 'media_gallery') {
$node->media_gallery_media_original = $node->media_gallery_media;
}
}
}
}
/**
* Implements hook_view().
*/
function media_gallery_view($node, $view_mode) {
// Add display elements and resources for users who can edit the gallery.
if (node_access('update', $node)) {
// Add the "Add images" link, themed as a local action. Note that this
// element is listed in hook_field_extra_fields(), so whether or not it
// will *actually* be displayed in the current view mode depends on the
// site's configuration for the corresponding pseudo-field.
$node->content['add_media_link'] = array(
'#theme' => 'menu_local_action',
'#link' => array(
'title' => t('Add media'),
'href' => 'media/browser',
'localized_options' => array(
'query' => array('render' => 'media-popup'),
'attributes' => array(
'class' => 'media-gallery-add launcher',
),
),
),
// @todo Drupal could really use a theme_menu_local_actions() function...
'#prefix' => '<ul class="field action-links">',
'#suffix' => '</ul>',
);
// Enable the "Add media" link to launch the media browser.
module_load_include('inc', 'media', 'includes/media.browser');
media_attach_browser_js($node->content['add_media_link']);
$node->content['add_media_link']['#attached']['js'][] = drupal_get_path('module', 'media_gallery') . '/media_gallery.addimage.js';
// These JS settings are used by the "add media" link but some are also
// shared by the drag-and-drop code below.
$instance = field_info_instance('node', 'media_gallery_media', $node->type);
$token = drupal_get_token('media_gallery');
$gallery_js_settings = array(
'mediaGalleryAddImagesUrl' => url('media-gallery/add-images/' . $node->nid . '/' . $token),
'mediaGallerySortGalleryUrl' => url('media-gallery/sort/gallery/' . $node->nid . '/' . $token),
'mediaGalleryAllowedMediaTypes' => array_filter($instance['widget']['settings']['allowed_types']),
);
// When viewing the full node, add front-end resources for drag-and-drop
// sorting.
if ($view_mode == 'full') {
drupal_add_css(drupal_get_path('module', 'media_gallery') . '/media_gallery.dragdrop.css');
drupal_add_library('system', 'ui.sortable');
drupal_add_library('system', 'jquery.bbq');
drupal_add_js(drupal_get_path('module', 'media_gallery') . '/media_gallery.dragdrop.js');
drupal_add_js($gallery_js_settings, array('type' => 'setting'));
}
else {
// Otherwise, attach the setting to the "add media" link, as per above.
$node->content['add_media_link']['#attached']['js'][] = array(
'type' => 'setting',
'data' => $gallery_js_settings,
);
}
}
// For the teaser, only the first thumbnail needs to be displayed, so remove the
// rest from the node's field data, so that the field formatter doesn't waste
// time building the render structure for items that won't be shown.
if ($view_mode == 'teaser') {
if (!empty($node->media_gallery_media[LANGUAGE_NONE])) {
if (media_access('view')) {
$first_item = array_shift($node->media_gallery_media[LANGUAGE_NONE]);
$node->media_gallery_media[LANGUAGE_NONE] = array($first_item);
}
else {
$node->media_gallery_media[LANGUAGE_NONE] = array();
}
}
}
// For the full display, implement pagination.
elseif ($view_mode == 'full' || $view_mode == 'media_gallery_block') {
$full = $view_mode == 'full' ? TRUE : FALSE;
if (!empty($node->media_gallery_media) && media_access('view')) {
$media = $node->media_gallery_media[LANGUAGE_NONE];
}
else {
$media = array();
}
// Only display the requested number of media items per page.
$columns = $full ? $node->media_gallery_columns[LANGUAGE_NONE][0]['value'] : $node->media_gallery_block_columns[LANGUAGE_NONE][0]['value'];
$rows = $full ? $node->media_gallery_rows[LANGUAGE_NONE][0]['value'] : $node->media_gallery_block_rows[LANGUAGE_NONE][0]['value'];
$number_per_page = $columns * $rows;
$deltas = array_keys($media);
$total = count($deltas);
// Initialize the pager and find out what page we are viewing.
$page = $full ? pager_default_initialize($total, $number_per_page, MEDIA_GALLERY_PAGER_ELEMENT) : 0;
// Deny access to all media items that aren't on this page.
$min_on_page = $number_per_page * $page;
$max_on_page = $number_per_page * ($page + 1) - 1;
$pre_links = array();
$post_links = array();
foreach ($deltas as $key => $delta) {
$item = $media[$delta];
$fid = _media_gallery_get_media_fid($item);
if ($key < $min_on_page) {
$pre_links[$key] = array(
'title' => '',
'href' => 'media-gallery/detail/' . $node->nid . '/' . $fid,
'attributes' => array('class' => array('colorbox-supplemental-link pre')),
);
unset($media[$delta]);
}
elseif ($key > $max_on_page) {
$post_links[$key] = array(
'title' => '',
'href' => 'media-gallery/detail/' . $node->nid . '/' . $fid,
'attributes' => array('class' => array('colorbox-supplemental-link post')),
);
unset($media[$delta]);
}
}
// Field rendering requires sequential deltas, so re-key.
// @todo Open a Drupal core issue about this.
if ($media) {
$node->media_gallery_media[LANGUAGE_NONE] = array_values($media);
}
else {
$node->media_gallery_media[LANGUAGE_NONE] = array();
}
// Create a set of dummy links to media items that don't appear on this
// page, so colorbox can link to them in the slideshow.
// @todo If the gallery contains 1000 media, then rendering each link takes
// extra server-side time, extra network time to transfer the markup, and
// extra client-side time to initialize the DOM. Performance can likely be
// significantly improved if we only send the fids to Drupal.settings, and
// add JavaScript code to make that information usable by Colorbox.
$node->content['colorbox_links_pre'] = array(
'#theme' => 'links',
'#links' => $pre_links,
'#weight' => -20,
'#attributes' => array('class' => array('colorbox-supplemental-links')),
);
$node->content['colorbox_links_post'] = array(
'#theme' => 'links',
'#links' => $post_links,
'#weight' => 20,
'#attributes' => array('class' => array('colorbox-supplemental-links')),
);
// Finally, display the pager, with a high weight so it appears at the
// bottom.
if ($full) {
$node->content['media_gallery_pager'] = array(
'#theme' => 'pager',
'#element' => MEDIA_GALLERY_PAGER_ELEMENT,
'#weight' => 2000,
);
}
}
return $node;
}
/**
* Implements hook_field_extra_fields().
*/
function media_gallery_field_extra_fields() {
// Allow the "Add media" link to be sorted with respect to the actual media
// gallery fields.
$extra['node']['media_gallery'] = array(
'display' => array(
'add_media_link' => array(
'label' => t('"Add media" link'),
'weight' => 1,
),
),
);
return $extra;
}
/**
* Access callback for AJAX-based gallery editing operations.
*
* @param string $type
* The type of item being edited: 'gallery' for an individual gallery or
* 'collection' for a gallery collection.
* @param mixed $item
* For a media gallery, the $node object for that gallery; for gallery
* collections, the taxonomy term corresponding to the collection.
* @param string $token
* A token from drupal_get_token.
*/
function media_gallery_edit_access_ajax($type, $item, $token) {
if (!drupal_valid_token($token, 'media_gallery')) {
return FALSE;
}
switch ($type) {
case 'gallery':
return node_access('update', $item);
break;
case 'collection':
return user_access('administer media galleries');
break;
default:
return FALSE;
}
}
/**
* Implements hook_theme().
*/
function media_gallery_theme() {
return array(
'media_gallery_collection' => array(
'render element' => 'element',
'file' => 'media_gallery.theme.inc',
),
'media_gallery_teaser' => array(
'render element' => 'element',
'file' => 'media_gallery.theme.inc',
),
'media_gallery_media_item_thumbnail' => array(
'render element' => 'element',
'file' => 'media_gallery.theme.inc',
'template' => 'media-gallery-media-item-thumbnail',
),
'media_gallery_media_item_lightbox' => array(
'render element' => 'element',
'file' => 'media_gallery.theme.inc',
),
'media_gallery_media_item_detail' => array(
'render element' => 'element',
'file' => 'media_gallery.theme.inc',
),
'media_gallery_block_thumbnail' => array(
'render element' => 'element',
'file' => 'media_gallery.theme.inc',
),
'media_gallery_collection_thumbnail' => array(
'render element' => 'element',
'file' => 'media_gallery.theme.inc',
),
'media_gallery_download_link' => array(
'variables' => array('file' => NULL, 'text' => NULL, 'options' => array()),
'file' => 'media_gallery.theme.inc',
),
'media_gallery_meta' => array(
'variables' => array('display' => NULL, 'location' => NULL, 'title' => NULL, 'license' => NULL, 'description' => NULL),
'file' => 'media_gallery.theme.inc',
),
'media_gallery_item' => array(
'variables' => array('image' => NULL, 'link_path' => NULL, 'classes' => NULL),
'file' => 'media_gallery.theme.inc',
),
'media_gallery_license' => array(
'variables' => array('element' => NULL, 'color' => 'dark'),
'file' => 'media_gallery.theme.inc',
),
'media_gallery_file_field_inline' => array(
'render element' => 'element',
'file' => 'media_gallery.theme.inc',
),
);
}
/**
* Implements hook_permission().
*/
function media_gallery_permission() {
return array(
'administer media galleries' => array(
'title' => t('Administer media galleries'),
),
);
}
/**
* Implements hook_node_info().
*/
function media_gallery_node_info() {
return array(
'media_gallery' => array(
'name' => t('Gallery'),
'base' => 'media_gallery',
'description' => t('A flexible gallery of media.'),
'help' => t('Create a gallery of thumbnails including custom display settings. Once your gallery is saved, your media can be added.'),
),
);
}
/**
* Implements hook_update().
*/
function media_gallery_update($node) {
// If the media gallery node is being saved and is configured to not provide
// a block, remove all blocks associated with it from the database. The block
// module might not be installed, so we need to check that the database table
// exists before querying it.
if (empty($node->media_gallery_expose_block[LANGUAGE_NONE][0]['value']) && db_table_exists('block')) {
db_delete('block')
->condition('module', 'media_gallery')
->condition('delta', $node->nid)
->execute();
}
}
/**
* Implements hook_block_info().
*/
function media_gallery_block_info() {
$blocks = array();
// Define a block for each media gallery node that is configured to expose
// one.
$query = new EntityFieldQuery();
$query->entityCondition('entity_type', 'node');
$query->entityCondition('bundle', 'media_gallery');
$query->fieldCondition('media_gallery_expose_block', 'value', 1);
$result = $query->execute();
if (!empty($result['node'])) {
// There is no reason to waste going through a full node_load_multiple()
// when we only need the titles.
$nids = array_keys($result['node']);
$node_titles = db_query("SELECT nid, title FROM {node} WHERE nid IN (:nids)", array(':nids' => $nids))->fetchAllKeyed();
foreach ($node_titles as $nid => $title) {
// The 'info' element is escaped on display, so we pass it through
// unfiltered here.
$blocks[$nid]['info'] = t('Recent gallery items: !title', array('!title' => $title));
$blocks[$nid]['visibility'] = 0;
$blocks[$nid]['pages'] = 'node/' . $nid . "\ngalleries";
}
}
return $blocks;
}
/**
* Implements hook_block_view().
*/
function media_gallery_block_view($delta = '') {
$node = node_load($delta);
if (empty($node->media_gallery_expose_block[LANGUAGE_NONE][0]['value'])) {
// Bail out now if the node doesn't exist or if it is configured not to
// display a block.
$block['subject'] = NULL;
$block['content'] = '';
}
elseif (empty($node->media_gallery_media_original) || !media_access('view')) {
// Bail out now if there won't be any media items to show.
$block['subject'] = check_plain($node->title);
$block['content'] = t('No content available.');
}
else {
// Collect an array of file IDs associated with this gallery. For
// simplicity we will assume (here and below) that this is not a
// multilingual field. Also note that the node may have been loaded and
// viewed elsewhere on the page, in which case the 'media_gallery_media'
// field was modified and does not contain what we want, so we have to go
// back to the original field value set in hook_node_load() instead, and
// also clone the node before changing it so our modifications do not
// affect other places where it might be being viewed.
$node = clone $node;
$node->media_gallery_media = $node->media_gallery_media_original;
$files = &$node->media_gallery_media[LANGUAGE_NONE];
$gallery_fids = array();
foreach ($files as $file) {
$gallery_fids[] = _media_gallery_get_media_fid($file);
}
// Construct a list of file IDs that is limited to the specified number of
// items and ordered by most recent; these are the files that will be
// displayed in the block.
$columns = !empty($node->media_gallery_block_columns[LANGUAGE_NONE][0]['value']) ? $node->media_gallery_block_columns[LANGUAGE_NONE][0]['value'] : 1;
$rows = !empty($node->media_gallery_block_rows[LANGUAGE_NONE][0]['value']) ? $node->media_gallery_block_rows[LANGUAGE_NONE][0]['value'] : 1;
$number_to_show = $columns * $rows;
$block_fids = db_select('file_managed', 'f')
->fields('f', array('fid'))
->condition('fid', $gallery_fids, 'IN')
->orderBy('timestamp', 'DESC')
->range(0, $number_to_show)
->execute()
->fetchCol();
// Before sorting, remove any items that will not display in the block.
$fid_order = array_flip($block_fids);
if ($number_to_show < count($files)) {
foreach ($files as $key => $file) {
if (!isset($fid_order[_media_gallery_get_media_fid($file)])) {
unset($files[$key]);
}
}
}
// Prepare the sorting function with the list of file ID orders.
_media_gallery_sort_by_recent(NULL, NULL, $fid_order);
// Perform the sort.
usort($files, '_media_gallery_sort_by_recent');
// Display the block.
$block['subject'] = check_plain($node->title);
$block['content']['gallery'] = node_view($node, 'media_gallery_block');
// Move the node's contextual links so that they display on the block
// rather than the node (i.e., in the same dropdown as the "Configure
// block" link). This is also required in order to properly integrate with
// the code in media_gallery_contextual_links_view_alter().
if (isset($block['content']['gallery']['#contextual_links'])) {
$block['content']['#contextual_links'] = $block['content']['gallery']['#contextual_links'];
unset($block['content']['gallery']['#contextual_links']);
}
$block['content']['more_link'] = array(
'#theme' => 'more_link',
'#url' => 'node/' . $node->nid,
'#title' => t('Show the complete gallery'),
'#weight' => 1000,
);
}
return $block;
}
/**
* Implements hook_block_configure().
*/
function media_gallery_block_configure($delta = '') {
// Duplicate the form for configuring media gallery node fields, including
// our module's custom alterations. We can't use drupal_get_form() here
// because that will mess up the form submission, so for now we have to live
// without getting any other module's alterations to this part of the node
// form.
$node = node_load($delta);
$form = array();
$form_state = array();
field_attach_form('node', $node, $form, $form_state, $node->language);
media_gallery_form_media_gallery_node_form_alter($form, $form_state);
// Pull out only the parts of the node form that allow configuration of the
// block settings; these are the ones we want to display.
$block_settings = array('block' => $form['block']);
// Store a record of all node fields that we will need to save when
// hook_block_save() is called.
$block_settings['block']['media_gallery_block_fields'] = array(
'#type' => 'value',
'#value' => element_children($block_settings['block']),
);
// Don't allow people to destroy the block itself from the block
// configuration page.
$block_settings['block']['media_gallery_expose_block']['#access'] = FALSE;
// Customize the fieldset display.
$block_settings['block']['#collapsible'] = FALSE;
$block_settings['block']['#title'] = t('Block settings');
unset($block_settings['block']['#weight']);
// Add the necessary attached JS and CSS.
_media_gallery_attach_form_resources($block_settings['block']);
return $block_settings;
}
/**
* Implements hook_block_save().
*/
function media_gallery_block_save($delta = '', $edit = array()) {
// Save the block-related media gallery fields on the node.
$node = node_load($delta);
foreach ($edit['media_gallery_block_fields'] as $field) {
$node->{$field} = $edit[$field];
}
node_save($node);
}
/**
* Implements hook_library().
*/
function media_gallery_library() {
$colorbox_path = variable_get('media_gallery_library_path', FALSE);
if ($colorbox_path === FALSE ) {
$colorbox_path = module_exists('libraries') ? libraries_get_path('colorbox') : 'sites/all/libraries/colorbox';
}
else {
$colorbox_path .= '/colorbox';
}
$stylesheet = variable_get('media_gallery_colorbox_stylesheet', 'example1');
$libraries['colorbox'] = array(
'title' => 'Colorbox',
'website' => 'http://colorpowered.com/colorbox/',
'version' => '1.3.9',
'js' => array(
$colorbox_path . '/colorbox/jquery.colorbox-min.js' => array(),
),
'css' => array(
$colorbox_path . '/' . $stylesheet . '/colorbox.css' => array(
'type' => 'file',
'media' => 'screen',
),
),
);
return $libraries;
}
/**
* Helper function to sort media gallery items by an ordered list of file IDs.
*
* Call once with $set_fid_order set to an array of file orders, keyed by the
* file ID, before performing the actual sort.
*/
function _media_gallery_sort_by_recent($a, $b, $set_fid_order = NULL) {
$fid_order = &drupal_static(__FUNCTION__, array());
// Stored the ordered list if this is a preparatory call.
if (isset($set_fid_order)) {
$fid_order = $set_fid_order;
return;
}
// Otherwise, perform the sort.
$a_order = $fid_order[_media_gallery_get_media_fid($a)];
$b_order = $fid_order[_media_gallery_get_media_fid($b)];
if ($a_order < $b_order) {
return -1;
}
elseif ($b_order < $a_order) {
return 1;
}
else {
return 0;
}
}
/**
* Returns the number of files of each type attached to a media gallery node.
*/
function media_gallery_get_media_type_count($node, $media_field = 'media_gallery_media') {
$fids = media_gallery_get_file_ids($node, $media_field);
if (empty($fids)) {
return array();
}
$query = db_select('file_managed', 'f');
$type = $query->addField('f', 'type');
$query->addExpression('COUNT(*)');
$type_count = $query->condition('f.fid', $fids, 'IN')
->groupBy($type)
->execute()
->fetchAllKeyed();
return $type_count;
}
/**
* Returns all file IDs attached to a media gallery node.
*/
function media_gallery_get_file_ids($node, $media_field = 'media_gallery_media') {
$fids = array();
$media_items = _media_gallery_field_get_items('node', $node, $media_field);
if( $media_items !== FALSE ) {
foreach ($media_items as $item) {
$fids[] = _media_gallery_get_media_fid($item);
}
}
return drupal_map_assoc($fids);
}
/**
* media_gallery_media_original is not a field and therefore cannot be used by field_get_items.
*/
function _media_gallery_field_get_items($entity_type, $entity, $field_name, $langcode = NULL) {
if ($entity_type == 'node' && $field_name == 'media_gallery_media_original') {
$media = $entity->media_gallery_media;
$entity->media_gallery_media = $entity->media_gallery_media_original;
$field_name = 'media_gallery_media';
}
$items = field_get_items($entity_type, $entity, $field_name, $langcode);
if (isset($media)) {
$entity->media_gallery_media = $media;
}
return $items;
}
/**
* Determines the file ID from a media file array or object.
*
* This is ugly, but necessary since a media field attached to a node may
* be represented either as an array or a full object, depending on whether the
* node has been processed for viewing yet or not.
*
* @param $file
* Either a media file object or media file array.
*
* @return
* The value of the 'fid' object property or array key.
*/
function _media_gallery_get_media_fid($file) {
return is_object($file) ? $file->fid : $file['fid'];
}
/**
* Removes a media item from a gallery.
*
* @param $node
* The gallery node object.
* @param $file
* The file to remove from the gallery.
*
* @return
* The updated gallery node object.
*/
function media_gallery_remove_item_from_gallery($node, $file) {
$items = &$node->media_gallery_media[LANGUAGE_NONE];
foreach ($items as $key => $item) {
if ($file->fid == _media_gallery_get_media_fid($item)) {
unset($items[$key]);
}
}
node_save($node);
return $node;
}
/**
* Implements hook_entity_info_alter().
*/
function media_gallery_entity_info_alter(&$entity_info) {
// Add view modes for displaying files in gallery contexts.
foreach (media_gallery_file_view_modes() as $view_mode => $label) {
$entity_info['file']['view modes'][$view_mode] = array('label' => $label, 'custom settings' => FALSE);
}
// Add a view mode for media_gallery_block_view() to use for displaying a
// media gallery node in a block. Drupal does not support restricting view
// modes to specific bundles.
$entity_info['node']['view modes']['media_gallery_block'] = array('label' => t('Media gallery block'), 'custom settings' => FALSE);
}
/**
* Implements hook_form().
*/
function media_gallery_form($node, $form_state) {
$form = node_content_form($node, $form_state);
return $form;
}
/**
* Implements hook_form_alter().
*/
function media_gallery_form_alter(&$form, &$form_state, $form_id) {
if (strpos($form_id, 'media_edit') === 0) {
// Act on both the regular and multiform versions of the edit form.
if ($form_id === 'media_edit' || preg_match('/^media_edit_[0-9]+$/', $form_id)) {
// Prepopulate the media_edit form with our best guess at the image title.
if (!empty($form['media_title']) && empty($form['media_title'][LANGUAGE_NONE][0]['value']['#default_value'])) {
$fid = $form['fid']['#value'];
$file = file_load($fid);
if ($file->type === 'image') {
$form['media_title'][LANGUAGE_NONE][0]['value']['#default_value'] = _media_gallery_get_media_title($file);
}
}
// Prepopulate the license field with the correct default.
if ($form['field_license'][LANGUAGE_NONE]['#default_value'] == '_none') {
$form['field_license'][LANGUAGE_NONE]['#default_value'] = 'none';
}
unset($form['field_license'][LANGUAGE_NONE]['#options']['_none']);
}
// Attach JavaScript and CSS needed to alter elements in the form.
_media_gallery_attach_edit_resources($form);
}
}
/*
* Implements hook_form_FORM_ID_alter().
*/
function media_gallery_form_media_gallery_node_form_alter(&$form, &$form_state) {
_media_gallery_attach_form_resources($form);
// The UI for the multi value media field and the node weight is elsewhere.
$form['media_gallery_media']['#access'] = FALSE;
$form['media_gallery_weight']['#access'] = FALSE;
// Hiding this field because we only support a single collection at the moment.
$form['media_gallery_collection']['#access'] = FALSE;
// Wrap a fieldset around the gallery settings.
$form['settings_wrapper'] = array(
'#type' => 'fieldset',
'#title' => t('Gallery settings'),
'#weight' => 10,
);
unset($form['media_gallery_lightbox_extras'][LANGUAGE_NONE]['#description']);
$form['media_gallery_lightbox_extras'][LANGUAGE_NONE]['#label'] = 'Show title and description';
// These are the items that need to be added to the fieldset. The array
// values represent a subgroup within the fieldset array that the items are
// further grouped by.
$fieldset = array(
'media_gallery_columns' => 'gallery',
'media_gallery_rows' => 'gallery',
'media_gallery_image_info_where' => 'gallery',
'media_gallery_allow_download' => 'presentation',
'media_gallery_format' => 'presentation',
'media_gallery_lightbox_extras' => 'presentation',
);
// Move the items to the fieldset.
foreach($fieldset as $id => $subgroup) {
$form['settings_wrapper'][$subgroup][$id] = $form[$id];
// locale_field_node_form_submit() looks for field language information in
// a hard-coded part of $form.
// @todo Other modules may as well, so would be best to move form elements
// within #pre_render rather than in hook_form_alter().
$form[$id] = array('#language' => $form[$id]['#language']);
}
// Add a vertical tab menu for blocks
$form['block'] = array(
'#type' => 'fieldset',
'#title' => 'Blocks',
'#collapsible' => TRUE,
'#collapsed' => FALSE,
'#group' => 'additional_settings',
'#attached' => array(),
'#weight' => -100,
);
$fieldset = array(
'media_gallery_expose_block' => 'block',
'media_gallery_block_columns' => 'block',
'media_gallery_block_rows' => 'block',
);
// Move the items to the fieldset.
foreach($fieldset as $id => $subgroup) {
$form[$subgroup][$id] = $form[$id];
// locale_field_node_form_submit() looks for field language information in
// a hard-coded part of $form.
// @todo Other modules may as well, so would be best to move form elements
// within #pre_render rather than in hook_form_alter().
$form[$id] = array('#language' => $form[$id]['#language']);
}
// Add a class to the fieldset to target it in the js
$form['block']['#attributes']['class'] = array('block-form');
// Add classes where necessary for JS enhancement.
$form['settings_wrapper']['gallery']['media_gallery_image_info_where']['#attributes']['class'][] = 'form-inline label';
$form['settings_wrapper']['gallery']['media_gallery_image_info']['#attributes']['class'][] = 'form-inline';
// Use #prefix and #suffix to group the fields.
$form['settings_wrapper']['presentation']['media_gallery_format']['#attributes']['class'][] = 'media-gallery-show no-group-label';
$form['settings_wrapper']['gallery']['#prefix'] = '<div class="gallery-settings settings-group hidden clearfix"><div class="setting-icon"></div><div class="no-overflow">';
$form['settings_wrapper']['gallery']['#suffix'] = '</div></div>';
$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">';
$form['settings_wrapper']['presentation']['#suffix'] = '</div></div>';
// Enhance the "number of rows" textfields by adding a dropdown element.
$form['settings_wrapper']['gallery']['media_gallery_rows']['#process'][] = 'media_gallery_process_dropdown';
$form['settings_wrapper']['gallery']['media_gallery_rows']['#media_gallery_dropdown_options'] = array('1', '3', '5', '10', 'other');
$form['block']['media_gallery_block_rows']['#process'][] = 'media_gallery_process_dropdown';
$form['block']['media_gallery_block_rows']['#media_gallery_dropdown_options'] = array('1', '2', '3', '4', 'other');
// Adjust the weight of the fields in the presentation wrapper
$form['settings_wrapper']['presentation']['media_gallery_allow_download']['#weight'] = 0;
// @todo At some point, it would be nice to have a functional preview display
// of gallery nodes, but until happens, remove the Preview button.
$form['actions']['preview']['#access'] = FALSE;
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function media_gallery_form_media_edit_alter(&$form, &$form_state) {
// Adjust the media edit form when it is shown within a gallery context.
if (isset($form_state['media_gallery']['gallery'])) {
// Remove the Delete button, since media entities can't be deleted when they
// are in use.
$form['actions']['delete']['#access'] = FALSE;
// Instead, provide a "Remove" checkbox to let users remove the item from
// the gallery.
_media_gallery_add_remove_checkbox($form, $form_state, $form_state['media_gallery']['gallery']);
// Add a submit handler to alter $form_state['redirect'] to the
// in-gallery-context View page. It's annoying to have to add a submit
// handler for this, but see http://drupal.org/node/579366#comment-2099836.
// Make sure to add this for the form-level submit handlers and also for the
// button-level submit handlers of the "Save" button, in case those are
// being used.
$form['#submit'][] = 'media_gallery_media_edit_submit';
if (isset($form['actions']['submit']['#submit'])) {
$form['actions']['submit']['#submit'][] = 'media_gallery_media_edit_submit';
}
}
// On the media gallery multiedit page, add a "Remove" checkbox to each item.
elseif (($node = menu_get_object()) && arg(2) === 'multiedit' && $node->type === 'media_gallery') {
_media_gallery_add_remove_checkbox($form, $form_state, $node);
}
}
/**
* Add a "remove" checkbox to the media edit form.
*/
function _media_gallery_add_remove_checkbox(&$form, &$form_state, $node) {
// Keep a reference to the gallery this media item belongs to, so we know
// what to remove it from.
$form['#gallery'] = $node;
// Put the remove checkbox inside the "preview" section, so it shows up
// underneath the thumbnail.
// @todo: Move into $form['preview']['remove'] when issue
// http://drupal.org/node/1055986 get committed.
$form['remove'] = array(
'#type' => 'checkbox',
'#title' => t('Remove from gallery'),
'#description' => t('The original file remains in your <a href="@library">media library</a>.', array('@library' => url('admin/content/media'))),
'#access' => node_access('update', $node),
);
// Add our own submit handler. We need to add it to both the form and the
// submit button to make sure it gets fired.
// Also note that this requires one call to node_save() per media item
// removed. A better approach, if it were possible, would be to add a submit
// handler to the entire multiform (see http://drupal.org/node/1033258).
$form['#submit'][] = 'media_gallery_multiedit_remove_item';
if (isset($form['actions']['submit']['#submit'])) {
$form['actions']['submit']['#submit'][] = 'media_gallery_multiedit_remove_item';
}
}
/**
* Form submit handler to remove a media item from a gallery.
*/
function media_gallery_multiedit_remove_item($form, &$form_state) {
if (isset($form['#gallery'])) {
$gallery = $form['#gallery'];
if (!empty($form_state['values']['remove'])) {
// Remove the item from the gallery.
$file = file_load($form_state['values']['fid']);
media_gallery_remove_item_from_gallery($gallery, $file);
}
// Redirect to the gallery page.
$uri = entity_uri('node', $gallery);
$form_state['redirect'] = $uri;
}
}
/**
* Form submit handler for media entity edit form in gallery context.
*
* @see media_gallery_form_media_edit_alter()
*/
function media_gallery_media_edit_submit($form, &$form_state) {
$form_state['redirect'] = 'media-gallery/detail/' . $form_state['media_gallery']['gallery']->nid . '/' . $form_state['values']['fid'];
}
/**
* Implements hook_field_attach_form().
*/
function media_gallery_field_attach_form($entity_type, $entity, &$form, &$form_state, $langcode) {
// Remove the ability for a user to select a license for externally hosted
// media.
if ($entity_type == 'file') {
$scheme = file_uri_scheme($entity->uri);
// @todo Implement a more generic determination for when it makes sense for
// a user to select a license and when it doesn't.
if ($scheme == 'youtube') {
$form['field_license']['#access'] = FALSE;
}
}
}
/**
* Helper function to attach JS/CSS for media galleries to a form element.
*/
function _media_gallery_attach_form_resources(&$element) {
$element['#attached']['js'][] = drupal_get_path('module', 'media_gallery') . '/media_gallery.form.js';
_media_gallery_attach_css_resources($element);
}
/**
* Helper function to attach CSS for media galleries to a render element.
*/
function _media_gallery_attach_css_resources(&$element) {
$path = drupal_get_path('module', 'media_gallery');
$element['#attached']['css'][] = $path . '/media_gallery.css';
$element['#attached']['css'][] = array(
'data' => $path . '/media_gallery.ie7.css',
'browsers' => array('IE' => 'lt IE 8', '!IE' => FALSE),
);
}
/**
* Helper function to attach JS for media galleries to
*/
function _media_gallery_attach_edit_resources(&$element) {
$path = drupal_get_path('module', 'media_gallery');
$element['#attached']['js'][] = $path . '/js/media_gallery.edit.js';
$element['#attached']['css'][] = $path . '/css/media_gallery.edit.css';
}
/**
* Implements hook_node_view_alter().
*/
function media_gallery_node_view_alter(&$build) {
// This is for the Galleries plural page
if ($build['#bundle'] == 'media_gallery' && $build['#view_mode'] == 'teaser') {
// Hide node links.
$build['links']['#access'] = FALSE;
unset($build['#contextual_links']);
_media_gallery_attach_css_resources($build);
}
// This is for when a gallery is being shown in a block
elseif ($build['#view_mode'] == 'media_gallery_block') {
// Hide node links.
$build['links']['#access'] = FALSE;
_media_gallery_attach_css_resources($build);
}
// This is for when a gallery is being shown on its own, single gallery page.
elseif ($build['#bundle'] == 'media_gallery' && $build['#view_mode'] == 'full') {
if (!empty($build['media_gallery_media'])) {
foreach (element_children($build['media_gallery_media']) as $delta) {
// For each media item, add contextual links to the in-gallery-context
// tasks that can be performed on a media item.
$fid = $build['media_gallery_media'][$delta]['#file']->fid;
$build['media_gallery_media'][$delta]['#contextual_links']['media_gallery'] = array('media-gallery/detail', array($build['#node']->nid, $fid));
}
}
_media_gallery_attach_css_resources($build);
}
}
/**
* Implements MODULE_preprocess_node().
*/
function media_gallery_preprocess_node(&$variables) {
// Do not show the title when a node is being displayed in a media gallery
// block.
if ($variables['view_mode'] == 'media_gallery_block') {
$variables['title'] = '';
}
// Gallery teasers (for example, the ones that appear on the Galleries page)
// require special theming of their content. We set that up here instead of as
// part of hook_node_view_alter() or similar, because we want the node itself
// to have #theme='node' as normal, and only want to add special theming for
// the node content, but the content element isn't created until
// template_preprocess_node().
if ($variables['node']->type == 'media_gallery' && $variables['view_mode'] == 'teaser') {
$variables['content']['#theme'] = 'media_gallery_teaser';
$variables['content']['#node'] = $variables['node'];
$variables['classes_array'][] = 'mg-gallery';
$variables['classes_array'][] = 'mg-teaser';
}
}
/**
* Implements MODULE_preprocess_menu_local_task().
*/
function media_gallery_preprocess_menu_local_task(&$variables) {
// Persist the "page" URL query parameter from the "view" tab to the
// "multiedit" tab for gallery nodes. In the future, we may want to expand
// this to cover more than just the "multiedit" tab. Since this code runs for
// every local task of every page, we try to determine no-op conditions as
// quickly as possible.
if (isset($_GET['page']) && !isset($variables['element']['#link']['localized_options']['query']['page']) && strpos($variables['element']['#link']['href'], 'node/') == 0) {
$nid = arg(1, $variables['element']['#link']['href']);
if (is_numeric($nid) && arg(2, $variables['element']['#link']['href']) == 'multiedit') {
$node = node_load($nid);
if ($node->type == 'media_gallery') {
$page = pager_find_page(MEDIA_GALLERY_PAGER_ELEMENT);
if (is_int($page)) {
$variables['element']['#link']['localized_options']['query']['page'] = "$page";
}
}
}
}
}
/**
* Implements hook_contextual_links_view_alter().
*/
function media_gallery_contextual_links_view_alter(&$element, $items) {
// Modify the contextual links on gallery blocks; we only want to allow
// editing the gallery and configuring the block, and we want a more
// descriptive title for the edit link.
if (isset($element['#element']['#block']->module) && $element['#element']['#block']->module == 'media_gallery' && !empty($element['#links'])) {
$links = &$element['#links'];
foreach ($links as $key => &$link) {
if ($key != 'node-edit' && $key != 'block-configure') {
unset($links[$key]);
}
elseif ($key == 'node-edit') {
$link['title'] = t('Edit gallery');
}
}
}
}
/**
* Preprocess function for theme_field().
*/
function media_gallery_preprocess_field(&$variables, $hook) {
if ($variables['element']['#field_name'] === 'media_gallery_media') {
$columns = 1;
switch($variables['element']['#view_mode']) {
case 'media_gallery_block':
$columns = $variables['element']['#object']->media_gallery_block_columns['und'][0]['value'];
break;
case 'full':
$columns = $variables['element']['#object']->media_gallery_columns['und'][0]['value'];
$media_gallery_view_mode_css = 'media-gallery-view-full';
break;
}
// Don't add the columning classes if the field is being displayed in a teaser
$variables['classes_array'][] = ($variables['element']['#view_mode'] != 'teaser') ? 'clearfix media-gallery-media mg-col mg-col-' . $columns : 'clearfix media-gallery-media';
// add css to find draggalbe elements (see media_gallery.dragdrop.js)
if (!empty($media_gallery_view_mode_css)) {
$variables['classes_array'][] = $media_gallery_view_mode_css;
}
foreach ($variables['items'] as $delta => $item) {
$variables['item_attributes_array'][$delta] = array('id' => 'media-gallery-media-' . $delta);
}
}
}
/**
* Media gallery equivalent to taxonomy_select_nodes().
*/
function media_gallery_select_galleries($tid, $pager = TRUE, $limit = FALSE) {
if (!variable_get('taxonomy_maintain_index_table', TRUE)) {
return array();
}
$query = db_select('taxonomy_index', 't');
$query->leftJoin('media_gallery_weight', 'mgw', 'mgw.nid = t.nid AND mgw.tid = :tid', array(':tid' => $tid));
$query->addTag('node_access');
$query->condition('t.tid', $tid);
if ($pager) {
$count_query = clone $query;
$count_query->addExpression('COUNT(t.nid)');
$query = $query->extend('PagerDefault');
if ($limit !== FALSE) {
$query = $query->limit($limit);
}
$query->setCountQuery($count_query);
}
else {
if ($limit !== FALSE) {
$query->range(0, $limit);
}
}
$query->addField('t', 'nid');
$query->addField('t', 'tid');
$query->addField('mgw', 'weight');
$query->orderBy('mgw.weight', 'ASC');
$query->orderBy('t.nid', 'ASC');
$result = $query->execute();
return $result->fetchCol();
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Used to modify the taxonomy term edit screen for gallery collection settings.
*/
function media_gallery_form_taxonomy_form_term_alter(&$form, &$form_state) {
// Don't do anything unless this is a gallery collection edit form.
if (isset($form_state['confirm_delete']) || !isset($form['#vocabulary']) || $form['#vocabulary']->vid != variable_get('media_gallery_collection_vid')) {
return;
}
$form['introduction'] = array(
'#weight' => -10,
'#markup' => check_plain(t('The following settings affect the "All galleries" page, which shows a thumbnail of every gallery created.')),
);
$form['#attributes']['class'][] = 'form-media-gallery-collection';
$form['name']['#title'] = t('Title');
$form['path']['alias']['#title'] = check_plain(t('"All galleries" URL'));
$form['path']['alias']['#weight'] = -1;
$form['path']['alias']['#field_prefix'] = url(NULL, array('absolute' => TRUE)) . (variable_get('clean_url', 0) ? '' : '?q=');
unset($form['path']['alias']['#description']);
_media_gallery_attach_form_resources($form);
// These are the items that need to be added to the fieldset. The array
// values represent a subgroup within the fieldset array that the items are
// further grouped by.
$fieldset = array(
'media_gallery_columns' => 'gallery',
'media_gallery_rows' => 'gallery',
'media_gallery_image_info_where' => 'gallery',
);
// Move the items to the fieldset.
foreach($fieldset as $id => $subgroup) {
$form['settings_wrapper'][$subgroup][$id] = $form[$id];
unset($form[$id]);
}
$form['settings_wrapper']['gallery']['media_gallery_image_info_where']['#attributes']['class'][] = 'form-inline label';
// Use #prefix and #suffix to group the fields.
$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">';
$form['settings_wrapper']['gallery']['#suffix'] = '</div></div>';
// Enhance the "number of rows" textfield by adding a dropdown element.
$form['settings_wrapper']['gallery']['media_gallery_rows']['#process'][] = 'media_gallery_process_dropdown';
$form['settings_wrapper']['gallery']['media_gallery_rows']['#media_gallery_dropdown_options'] = array('1', '3', '5', '10', 'other');
$form['relations']['#access'] = FALSE;
$form['actions']['delete']['#access'] = FALSE;
$form['field_license']['#access'] = FALSE;
// Add a submit handler to change the "Updated term" message on submit.
$form['#submit'][] = 'media_gallery_taxonomy_form_term_submit';
}
/**
* Submit handler for the taxonomy_form_term form.
*/
function media_gallery_taxonomy_form_term_submit($form, &$form_state) {
// Change the "Updated term Galleries" message into something that makes
// sense in this context.
$term_name = $form_state['values']['name'];
$messages = $_SESSION['messages']['status'];
$updated_message = t('Updated term %term.', array('%term' => $term_name));
foreach ($messages as $key => $message) {
if ($message === $updated_message) {
$_SESSION['messages']['status'][$key] = t('The gallery settings have been saved.');
}
}
}
/**
* Implements hook_form_FORM_ID_alter().
*
* Used to hide the gallery_collections taxonomy admin screens.
*/
function media_gallery_form_taxonomy_overview_vocabularies_alter(&$form, &$form_state) {
$gallery_collection_vid = variable_get('media_gallery_collection_vid');
unset($form[$gallery_collection_vid]);
}
/**
* Implements hook_module_implements_alter().
*/
function media_gallery_module_implements_alter(&$implementations, $hook) {
switch ($hook) {
// TODO: All we really need to control here is
// form_taxonomy_form_term_alter; if D7 gets fixed to allow that level of
// control, this can be changed.
//case 'form_taxonomy_form_term_alter':
case 'form_alter':
if (!isset($implementations['media_gallery'])){
break;
}
$group = $implementations['media_gallery'];
unset($implementations['media_gallery']);
$implementations['media_gallery'] = $group;
break;
// We need to ensure that these hooks run before the corresponding Pathauto
// implementations. Given what they do, it's harmless to put them at the
// very front of the list, so we do that because it's easiest.
case 'taxonomy_term_insert':
case 'taxonomy_term_update':
if (isset($implementations['media_gallery'])) {
$implementations = array('media_gallery' => $implementations['media_gallery']) + $implementations;
}
break;
}
}
/**
* Gets the first term in the media_gallery_collection vocabulary
*/
function media_gallery_get_default_gallery_collection() {
$gallery_collection_vid = variable_get('media_gallery_collection_vid');
$tid = db_select('taxonomy_term_data', 'ttd')
->fields('ttd', array('tid'))
->condition('vid', $gallery_collection_vid)
->range(0,1)
->execute()
->fetchField();
return taxonomy_term_load($tid);
}
/**
* Access callback for viewing parts of a node that are only relevant for media
* galleries.
*/
function media_gallery_view_access($node) {
if (!node_access('view', $node)) {
return FALSE;
}
if ($node->type == 'media_gallery') {
return TRUE;
}
}
/**
* Access callback for editing parts of a node that are only relevant for media
* galleries.
*/
function media_gallery_edit_access($node) {
if (!node_access('update', $node)) {
return FALSE;
}
if ($node->type == 'media_gallery') {
return TRUE;
}
}
/**
* Access callback for editing parts of a node that are only relevant for media
* galleries.
*/
function media_gallery_multiedit_access($node) {
if (media_gallery_edit_access($node) && media_access('edit')) {
$media_items = field_get_items('node', $node, 'media_gallery_media');
if( $media_items !== FALSE && count($media_items) > 0 ) {
return TRUE;
}
}
}
/**
* Access callback for viewing a media item in a gallery.
*
* @param $node
* The gallery node object.
* @param $file
* The file to view.
*
* @return
* TRUE if access is granted; FALSE otherwise.
*/
function media_gallery_view_item_access($node, $file) {
// Only grant access if the user can view the gallery and the provided media.
return media_gallery_view_access($node) && media_access('view')
&& in_array($file->fid, media_gallery_get_file_ids($node));
}
/**
* Access callback for editing a media item in a gallery.
*
* @param $node
* The gallery node object.
* @param $file
* The file to view.
*
* @return
* TRUE if access is granted; FALSE otherwise.
*/
function media_gallery_edit_item_access($node, $file) {
// Only grant access if the user can edit the provided media
// and the media is part of the gallery.
return media_access('edit')
&& in_array($file->fid, media_gallery_get_file_ids($node));
}
/**
* Access callback for removing a media item from a gallery.
*
* @param $node
* The gallery node object.
* @param $file
* The file to remove from the gallery.
*
* @return
* TRUE if access is granted; FALSE otherwise.
*/
function media_gallery_remove_item_access($node, $file) {
// Only grant access if the user can edit the gallery and the provided media
// item is attached to the gallery.
return media_gallery_edit_access($node) && in_array($file->fid, media_gallery_get_file_ids($node));
}
/**
* Implements hook_image_default_styles().
*/
function media_gallery_image_default_styles() {
$styles = array();
$styles['media_gallery_thumbnail'] = array(
'effects' => array(
array(
// @todo We want to not upscale if the user uploads a smaller image, but
// image_scale_and_crop doesn't support that option. Try to get
// http://drupal.org/node/872206 into core, or solve it in contrib.
'name' => 'image_scale_and_crop',
'data' => array('width' => 450, 'height' => 450, 'upscale' => FALSE),
'weight' => 0,
),
)
);
$styles['media_gallery_large'] = array(
'effects' => array(
array(
'name' => 'image_scale',
'data' => array('width' => 900, 'height' => 900, 'upscale' => FALSE),
'weight' => 0,
),
)
);
return $styles;
}
/**
* Implements hook_styles_default_styles().
*/
function media_gallery_styles_default_styles() {
return array(
'file' => array(
'styles' => array(
'media_gallery_thumbnail' => array(
'label' => 'Media gallery thumbnail',
'description' => 'A square thumbnail for display within a Media Gallery.',
),
'media_gallery_large' => array(
'label' => 'Media gallery large',
'description' => 'A large format for display within a Media Gallery.',
),
),
),
);
}
/**
* Implements hook_styles_default_presets_alter().
*/
function media_gallery_styles_default_presets_alter(&$styles) {
foreach (array_keys(media_gallery_image_default_styles()) as $image_style) {
foreach (array('image', 'media_youtube') as $container) {
$styles['file']['containers'][$container]['styles'][$image_style]['default preset'] = $image_style;
$styles['file']['containers'][$container]['presets'][$image_style] = array(
array(
// @todo Styles 2.0-alpha6 and later uses 'imageStyle', while earlier
// versions use 'image_style'. Change to simply using 'imageStyle'
// when it's okay to drop compatibility with the earlier versions.
'name' => (class_exists('FileStyles') && method_exists('FileStyles', 'imageStyle')) ? 'imageStyle' : 'image_style',
'settings' => array(
'image_style' => $image_style,
),
),
array(
'name' => 'thumbnail',
'settings' => array(),
),
);
}
}
$styles['file']['containers']['media_youtube']['styles']['media_gallery_large']['default preset'] = 'video';
}
/**
* Implements hook_styles_presets().
*
* This function is for Styles 1.x only. For Styles 2.x,
* media_gallery_styles_default_presets_alter() is used instead.
*/
function media_gallery_styles_presets() {
$presets = array(
'file' => array(
'media_gallery_thumbnail' => array(
'media_youtube' => array(
'youtube_thumbnail_media_gallery_thumbnail',
),
),
'media_gallery_large' => array(
'media_youtube' => array(
'youtube_full',
),
),
),
);
return $presets;
}
/**
* Implements hook_media_wysiwyg_allowed_view_modes_alter().
*
* Removes view modes intended for gallery context only from the formatting
* options of media added to wysiwyg.
*/
function media_gallery_media_wysiwyg_allowed_view_modes_alter(&$view_modes) {
$view_modes = array_diff_key($view_modes, media_gallery_file_view_modes());
}
/**
* Form #process function for attaching dropdown-related classes and settings.
*/
function media_gallery_process_dropdown($element, &$form_state) {
$element['#attributes']['class'][] = 'media-gallery-dropdown';
$element['#attached']['js'][] = array(
'type' => 'setting',
'data' => array(
'media_gallery_dropdown_options' => array(
$element['#id'] => $element['#media_gallery_dropdown_options'],
),
),
);
return $element;
}
/**
* Implements hook_taxonomy_term_insert().
*/
function media_gallery_taxonomy_term_insert($term) {
// Note that in hook_module_implements_alter() we guarantee that this code
// will always run before Pathauto's implementation.
_media_gallery_prevent_unwanted_pathauto_aliases($term);
}
/**
* Implements hook_taxonomy_term_update().
*/
function media_gallery_taxonomy_term_update($term) {
// Note that in hook_module_implements_alter() we guarantee that this code
// will always run before Pathauto's implementation.
_media_gallery_prevent_unwanted_pathauto_aliases($term);
}
/**
* Implements hook_entity_insert().
*/
function media_gallery_entity_insert($entity, $type) {
// This hook is used because it always runs after Pathauto's
// hook_taxonomy_term_insert() implementation.
if ($type == 'taxonomy_term') {
_media_gallery_allow_all_pathauto_aliases();
}
}
/**
* Implements hook_entity_update().
*/
function media_gallery_entity_update($entity, $type) {
// This hook is used because it always runs after Pathauto's
// hook_taxonomy_term_update() implementation.
if ($type == 'taxonomy_term') {
_media_gallery_allow_all_pathauto_aliases();
}
}
/**
* Hack to prevent Pathauto from generating unwanted taxonomy aliases.
*
* This function can be called before allowing the Pathauto module to act on a
* saved term for the taxonomy vocabulary used for media galleries. It prevents
* Pathauto from generating an alias for the term based on the generic Pathauto
* taxonomy alias settings (i.e., an alias will only be generated if the site
* is specifically configured to have aliases generated for the vocabulary, not
* for taxonomy terms in general).
*
* The reason we want to do this is so that the URL alias people save on the
* media gallery settings page will actually work.
*
* If a $term object is not provided, then this function will always act; if
* one is provided, then it will only act if the term corresponds to the media
* gallery default collection.
*
* Call _media_gallery_allow_all_pathauto_aliases() after the term is saved to
* resume normal Pathauto behavior for the rest of the page request.
*/
function _media_gallery_prevent_unwanted_pathauto_aliases($term = NULL) {
if (!isset($term) || $term->tid == variable_get('media_gallery_default_collection_tid')) {
if (isset($GLOBALS['conf']['pathauto_taxonomy_pattern'])) {
$GLOBALS['conf']['media_gallery_original_pathauto_taxonomy_pattern'] = $GLOBALS['conf']['pathauto_taxonomy_pattern'];
}
$GLOBALS['conf']['pathauto_taxonomy_pattern'] = '';
}
}
/**
* Restores Pathauto behavior after we are done hacking with it.
*
* @see _media_gallery_prevent_unwanted_pathauto_aliases()
*/
function _media_gallery_allow_all_pathauto_aliases() {
if (isset($GLOBALS['conf']['media_gallery_original_pathauto_taxonomy_pattern'])) {
$GLOBALS['conf']['pathauto_taxonomy_pattern'] = $GLOBALS['conf']['media_gallery_original_pathauto_taxonomy_pattern'];
}
}
/**
* Implements hook_ctools_plugin_api().
*
* Lets CTools know which plugin APIs are implemented by this module.
*/
function media_gallery_ctools_plugin_api($owner, $api) {
static $api_versions = array(
'file_entity' => array(
'file_default_displays' => 1,
),
);
if (isset($api_versions[$owner][$api])) {
return array('version' => $api_versions[$owner][$api]);
}
}
/**
* Implements hook_file_default_displays().
*
* Provides default display configurations for files displayed in gallery view
* modes.
*
* @see file_entity_schema()
*/
function media_gallery_file_default_displays() {
$default_displays = array();
$default_image_styles = array(
'media_gallery_thumbnail' => 'media_gallery_thumbnail',
'media_gallery_lightbox' => 'media_gallery_large',
'media_gallery_detail' => 'media_gallery_large',
'media_gallery_block_thumbnail' => 'media_gallery_thumbnail',
'media_gallery_collection_thumbnail' => 'media_gallery_thumbnail',
);
// People updating from older versions of Media module will have Styles module
// formatters enabled at weight 0. By default, we want the following taking
// precedence, but we do not want to disable the Styles module ones since
// those might be capable of rendering files not covered by these. Therefore,
// set these at a lower weight.
$default_weight = -1;
foreach ($default_image_styles as $view_mode => $image_style) {
// Images.
$display_name = 'image__' . $view_mode . '__file_image';
$default_displays[$display_name] = (object) array(
'api_version' => 1,
'name' => $display_name,
'status' => 1,
'settings' => array('image_style' => $image_style),
'weight' => $default_weight,
);
// YouTube.
if (module_exists('media_youtube')) {
if (in_array($view_mode, array('media_gallery_lightbox', 'media_gallery_detail'))) {
// Video. Omit settings to use media_youtube_video defaults.
$display_name = 'video__' . $view_mode . '__media_youtube_video';
$default_displays[$display_name] = (object) array(
'api_version' => 1,
'name' => $display_name,
'status' => 1,
'weight' => $default_weight,
);
}
else {
// Thumbnail.
$display_name = 'video__' . $view_mode . '__media_youtube_image';
$default_displays[$display_name] = (object) array(
'api_version' => 1,
'name' => $display_name,
'status' => 1,
'settings' => array('image_style' => $image_style),
'weight' => $default_weight,
);
}
}
}
return $default_displays;
}
/**
* Menu page delivery callback.
* This is a delegate function. In case, the user has no access to the menu
* item, the menu system does not load the specified file and therefore can
* not use the custom deliver function.
*/
function media_gallery_lightbox_delivery_callback($page_content) {
if (!function_exists('media_gallery_lightbox_page_deliver')) {
module_load_include('inc', 'media_gallery', 'media_gallery.pages');
}
media_gallery_lightbox_page_deliver($page_content);
}