You are here

absolute_messages.module in Absolute Messages 7

Same filename and directory in other branches
  1. 6 absolute_messages.module

Module displaying system messages in colored horizontal bars on top of the page, similar to Stack Overflow / Stack Exchange network notifications.

File

absolute_messages.module
View source
<?php

/**
 * @file
 * Module displaying system messages in colored horizontal bars on top
 * of the page, similar to Stack Overflow / Stack Exchange network notifications.
 */

/**
 * Implements hook_permission().
 */
function absolute_messages_permission() {
  return array(
    'access absolute messages' => array(
      'title' => t('Access absolute messages'),
    ),
    'administer absolute messages' => array(
      'title' => t('Administer absolute messages'),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function absolute_messages_menu() {
  $items = array();
  $items['admin/config/system/absolute_messages'] = array(
    'title' => 'Absolute Messages',
    'description' => 'Absolute Messages module settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'absolute_messages_admin_settings_form',
    ),
    'access callback' => 'user_access',
    'access arguments' => array(
      'administer absolute messages',
    ),
    'file' => 'absolute_messages.admin.inc',
  );
  return $items;
}

/**
 * Implements hook_page_build().
 */
function absolute_messages_page_build() {

  // Add module JS and CSS.
  drupal_add_css(drupal_get_path('module', 'absolute_messages') . '/absolute_messages.css');
  drupal_add_js(drupal_get_path('module', 'absolute_messages') . '/absolute_messages.js');
  if (variable_get('absolute_messages_fixed', FALSE)) {
    drupal_add_css(drupal_get_path('module', 'absolute_messages') . '/absolute_messages_fixed.css');
  }

  // Module configuration for JS.
  $settings = array(
    'dismiss' => array(),
    'dismiss_time' => array(),
    'dismiss_all_count' => variable_get('absolute_messages_dismiss_all_count', 2),
  );
  foreach (_absolute_messages_message_types() as $message_type) {
    $settings['dismiss'][$message_type] = variable_get('absolute_messages_dismiss_' . $message_type, FALSE);
    $settings['dismiss_time'][$message_type] = variable_get('absolute_messages_dismiss_time_' . $message_type, '');
  }

  // Maximum number of lines to display.
  if ($max_lines = variable_get('absolute_messages_display_lines', '')) {
    $settings['max_lines'] = $max_lines;
  }

  // Pass configuration to JS.
  drupal_add_js(array(
    'absoluteMessages' => $settings,
  ), 'setting');
}

/**
 * Implements hook_theme().
 */
function absolute_messages_theme() {
  $path = drupal_get_path('module', 'absolute_messages');
  return array(
    'absolute_messages_messages' => array(
      'variables' => array(
        'vars' => NULL,
      ),
    ),
    'absolute_messages_wrapper' => array(
      'template' => 'absolute-messages-wrapper',
      'path' => "{$path}/theme",
      'variables' => array(
        'vars' => NULL,
      ),
    ),
    'absolute_messages_message' => array(
      'template' => 'absolute-messages-message',
      'path' => "{$path}/theme",
      'variables' => array(
        'vars' => NULL,
      ),
    ),
    'absolute_messages_dismiss_all' => array(
      'template' => 'absolute-messages-dismiss-all',
      'path' => "{$path}/theme",
      'variables' => array(
        'vars' => NULL,
      ),
    ),
    'absolute_messages_grouped_message' => array(
      'variables' => array(
        'vars' => NULL,
      ),
    ),
  );
}

/**
 * Implements hook_theme_registry_alter().
 * Replace original messages theming function with our own.
 */
function absolute_messages_theme_registry_alter(&$theme_registry) {
  $theme_registry['status_messages']['function'] = 'theme_absolute_messages';
}

/**
 * Theme function, overriding Drupal's theme_status_messages().
 */
function theme_absolute_messages($variables) {
  global $user;

  // Check whether Absolute Messages should be enabled
  // on current page and for current user role.
  if (!_absolute_messages_visibility_pages() || !_absolute_messages_visibility_roles($user)) {
    return theme_status_messages($variables);
  }

  // Fall back to standard Drupal's way of displaying messages if JS is not
  // available or user does not have 'access absolute messages' permission.
  // Still though use AM theme function if not checking "has_js" cookie.
  $skip_cookie_check = variable_get('absolute_messages_no_js_check', FALSE);
  if (!user_access('access absolute messages') || !$skip_cookie_check && !isset($_COOKIE['has_js'])) {
    return theme_status_messages($variables);
  }

  // Get all messages, and skip further processing if no messages found.
  $all_messages = drupal_get_messages($variables['display']);
  if (empty($all_messages)) {
    return;
  }

  // Provide hook_messages_alter($messages) to other modules.
  // Allows modules to update messages before they are displayed.
  drupal_alter('messages', $all_messages);

  // Theme all messages for output.
  $output = '';
  $total_messages = 0;
  foreach ($all_messages as $type => $messages) {

    // Group duplicate messages if enabled.
    if (variable_get('absolute_messages_group', FALSE)) {
      $messages = _absolute_messages_group_duplicates($messages);
    }
    $vars = array(
      'type' => $type,
      'messages' => $messages,
    );
    $output .= theme('absolute_messages_messages', $vars);
    $total_messages += count($messages);
  }

  // Add 'Dismiss all messages'.
  $vars = array(
    'dismiss_all' => t('Dismiss all messages'),
  );
  $output .= theme('absolute_messages_dismiss_all', array(
    'vars' => $vars,
  ));

  // Return formatted messages.
  $vars = array(
    'messages' => $output,
    'show_dismissed' => t('Show dismissed messages'),
  );

  // Return all AM-themes messages together with devel messages
  // themed in standard Drupal way.
  return theme('absolute_messages_wrapper', array(
    'vars' => $vars,
  )) . theme_status_messages($variables);
}

/**
 * Theme function, which could be overriden by other modules/themes.
 */
function theme_absolute_messages_messages($variables) {
  $output = '';
  if (isset($variables['messages']) && count($variables['messages'])) {
    foreach ($variables['messages'] as $message) {

      // Devel messages should be displayed in standard Drupal format,
      // so let's just set them again and at the end pass through
      // default theme_status_messages().
      if (_absolute_messages_is_devel_message($message)) {
        drupal_set_message($message, $variables['type']);
        continue;
      }

      // All other messages will be AM-themed.
      $vars = array(
        'type' => $variables['type'],
        'message' => $message,
        'dismiss' => t('Dismiss this message'),
      );
      $output .= theme('absolute_messages_message', array(
        'vars' => $vars,
      ));
    }
  }
  return $output;
}

/**
 * Theme function used to additionally format a single message
 * when "Group duplicate messages" option is enabled, by adding
 * the number of repetitions at the end of grouped messages.
 */
function theme_absolute_messages_grouped_message($variables) {
  $output = $variables['message'];
  if ($variables['count'] > 1) {
    $output .= strtr(' <span title="!title">(x!count)</span>', array(
      '!title' => t('This message has been repeated !count times.', array(
        '!count' => $variables['count'],
      )),
      '!count' => $variables['count'],
    ));
  }
  return $output;
}

/**
 * Finds all duplicate messages and groups them together.
 */
function _absolute_messages_group_duplicates($messages) {
  $processed = array();
  foreach (array_count_values($messages) as $message => $count) {
    $processed[] = theme('absolute_messages_grouped_message', array(
      'message' => $message,
      'count' => $count,
    ));
  }
  return $processed;
}

/**
 * Returns array of standard Drupal's message types.
 * Provides hook_message_types_alter() to other modules,
 * allowing them to add new message types if required.
 */
function _absolute_messages_message_types() {
  $message_types = array(
    'status',
    'warning',
    'error',
  );
  drupal_alter('message_types', $message_types);
  return $message_types;
}

/**
 * Checks whether provided message is a devel message.
 */
function _absolute_messages_is_devel_message($message) {
  $devel_strings = array(
    '"krumo-root',
    '<pre',
    '<textarea',
  );
  foreach ($devel_strings as $devel_string) {
    if (strstr($message, $devel_string)) {
      return TRUE;
    }
  }
}

/**
 * Based on visibility setting this function returns TRUE if AM should
 * be enabled on the current page or FALSE otherwise.
 */
function _absolute_messages_visibility_pages() {
  static $page_match;

  // Cache visibility result if function is called more than once.
  if (!isset($page_match)) {
    $visibility = variable_get('absolute_messages_visibility_pages', 0);
    $setting_pages = variable_get('absolute_messages_pages', NULL);

    // Match path if necessary.
    if (!empty($setting_pages)) {

      // Convert path to lowercase. This allows comparison of the same path
      // with different case. Ex: /Page, /page, /PAGE.
      $pages = drupal_strtolower($setting_pages);
      if ($visibility < 2) {

        // Convert the Drupal path to lowercase
        $path = drupal_strtolower(drupal_get_path_alias($_GET['q']));

        // Compare the lowercase internal and lowercase path alias (if any).
        $page_match = drupal_match_path($path, $pages);
        if ($path != $_GET['q']) {
          $page_match = $page_match || drupal_match_path($_GET['q'], $pages);
        }

        // When $visibility has a value of 0, Absolute Messages is enabled
        // on all pages except those listed in $pages. When set to 1,
        // it is enabled only on those pages listed in $pages.
        $page_match = !($visibility xor $page_match);
      }
      elseif (module_exists('php')) {
        $page_match = php_eval($setting_pages);
      }
      else {
        $page_match = FALSE;
      }
    }
    else {
      $page_match = TRUE;
    }
  }
  return $page_match;
}

/**
 * Based on visibility setting this function returns TRUE if AM should
 * be enabled for the current role or FALSE otherwise.
 */
function _absolute_messages_visibility_roles($account) {
  $visibility = variable_get('absolute_messages_visibility_roles', 0);
  $enabled = $visibility;
  $roles = variable_get('absolute_messages_roles', array());
  if (array_sum($roles) > 0) {

    // One or more roles are selected.
    foreach (array_keys($account->roles) as $rid) {

      // Is the current user a member of one of these roles?
      if (isset($roles[$rid]) && $rid == $roles[$rid]) {

        // Current user is a member of a role
        // that should have AM enabled/disabled.
        $enabled = !$visibility;
        break;
      }
    }
  }
  else {

    // No role is selected for tracking, therefore all roles should be tracked.
    $enabled = TRUE;
  }
  return $enabled;
}

Functions

Namesort descending Description
absolute_messages_menu Implements hook_menu().
absolute_messages_page_build Implements hook_page_build().
absolute_messages_permission Implements hook_permission().
absolute_messages_theme Implements hook_theme().
absolute_messages_theme_registry_alter Implements hook_theme_registry_alter(). Replace original messages theming function with our own.
theme_absolute_messages Theme function, overriding Drupal's theme_status_messages().
theme_absolute_messages_grouped_message Theme function used to additionally format a single message when "Group duplicate messages" option is enabled, by adding the number of repetitions at the end of grouped messages.
theme_absolute_messages_messages Theme function, which could be overriden by other modules/themes.
_absolute_messages_group_duplicates Finds all duplicate messages and groups them together.
_absolute_messages_is_devel_message Checks whether provided message is a devel message.
_absolute_messages_message_types Returns array of standard Drupal's message types. Provides hook_message_types_alter() to other modules, allowing them to add new message types if required.
_absolute_messages_visibility_pages Based on visibility setting this function returns TRUE if AM should be enabled on the current page or FALSE otherwise.
_absolute_messages_visibility_roles Based on visibility setting this function returns TRUE if AM should be enabled for the current role or FALSE otherwise.