breakpoint.module

Manage breakpoints and breakpoint groups for responsive designs.

File

drupal/core/modules/breakpoint/breakpoint.module
View source
<?php

/**
 * @file
 * Manage breakpoints and breakpoint groups for responsive designs.
 */
use Drupal\breakpoint\Plugin\Core\Entity\Breakpoint;
use Drupal\breakpoint\Plugin\Core\Entity\BreakpointGroup;
use Drupal\Core\Config\Entity\ConfigStorageController;

/**
 * Implements hook_help().
 */
function breakpoint_help($path, $arg) {
  switch ($path) {
    case 'admin/help#breakpoint':
      $output = '';
      $output .= '<h3>' . t('About') . '</h3>';
      $output .= '<p>' . t('The Breakpoints module keeps track of the height, width, and resolution breakpoints where a responsive design needs to change in order to respond to different devices being used to view the site.') . '</p>';
      $output .= '<h3>' . t('Uses') . '</h3>';
      $output .= '<dl>';
      $output .= '<dt>' . t('Defining breakpoints') . '</dt>';
      $output .= '<dd><p>' . t('The Breakpoint module can be used by themes and other modules to define breakpoints, which separate the height or width of viewports (screens, printers, and other media output types) into steps. For instance, a width breakpoint of 40em creates two steps: one for widths up to 40em and one for widths above 40em. Breakpoints can be used to define when layouts should shift from one form to another, when images should be resized, and other changes that need to respond to changes in viewport height or width.') . '</p>';
      $output .= '<p>' . t('<a href="http://www.w3.org/TR/css3-mediaqueries/">Media  queries</a> are a formal way to encode breakpoints. For instance, a width breakpoint at 40em would be written as the media query "(min-width: 40em)". Breakpoints are really just media queries with some additional meta-data, such as a name and multiplier information.') . '</p></dd>';
      $output .= '<dt>' . t('Assigning resolution multipliers to breakpoints') . '</dt>';
      $output .= '<dd>' . t('Multipliers are a measure of the viewport\'s device resolution, defined to be the ratio between the physical pixel size of the active device and the <a href="http://en.wikipedia.org/wiki/Device_independent_pixel">device-independent pixel</a> size. The Breakpoint module defines multipliers of 1, 1.5, and 2; when defining breakpoints, modules and themes can define which multipliers apply to each breakpoint.') . '</dd>';
      $output .= '<dt>' . t('Defining breakpoint groups') . '</dt>';
      $output .= '<dd>' . t('Breakpoints can be organized into groups. Modules and themes should use groups to separate out breakpoints that are meant to be used for different purposes, such as breakpoints for layouts or breakpoints for image sizing.') . '</dd>';
      $output .= '</dl>';
      return $output;
  }
}

/**
 * Implements hook_themes_enabled().
 *
 * @param array $theme_list
 *   An array of theme names.
 *
 * @see _breakpoint_theme_enabled()
 *
 * @todo: This should be removed if https://drupal.org/node/1813100 is resolved.
 */
function breakpoint_themes_enabled($theme_list) {
  _breakpoint_theme_enabled($theme_list);
}

/**
 * Implements hook_themes_disabled().
 *
 * @param array $theme_list
 *   An array of theme names.
 *
 * @see _breakpoint_delete_breakpoints()
 *
 * @todo: This should be removed if https://drupal.org/node/1813100 is resolved.
 */
function breakpoint_themes_disabled($theme_list) {
  _breakpoint_delete_breakpoints($theme_list, Breakpoint::SOURCE_TYPE_THEME);
}

/**
 * Implements hook_modules_enabled().
 *
 * @param array $modules
 *   An array of the modules that were enabled.
 *
 * @see _breakpoint_modules_enabled()
 *
 * @todo: This should be removed if https://drupal.org/node/1813100 is resolved.
 */
function breakpoint_modules_enabled($modules) {
  _breakpoint_modules_enabled($modules);
}

/**
 * Implements hook_modules_uninstalled().
 *
 * @param array $modules
 *   An array of the modules that were uninstalled.
 *
 * @see _breakpoint_delete_breakpoints()
 *
 * @todo: This should be removed if https://drupal.org/node/1813100 is resolved.
 */
function breakpoint_modules_uninstalled($modules) {
  _breakpoint_delete_breakpoints($modules, Breakpoint::SOURCE_TYPE_MODULE);
}

/**
 * Import breakpoints from all new enabled themes.
 *
 * @param array $theme_list
 *   An array of theme names.
 */
function _breakpoint_theme_enabled($theme_list) {
  $themes = list_themes();
  foreach ($theme_list as $theme_key) {
    $media_queries = breakpoint_get_theme_media_queries($theme_key);
    _breakpoint_import_media_queries($theme_key, $themes[$theme_key]->info['name'], Breakpoint::SOURCE_TYPE_THEME, $media_queries);

    // Import custom groups.
    _breakpoint_import_breakpoint_groups($theme_key, Breakpoint::SOURCE_TYPE_THEME);
  }
}

/**
 * Import breakpoints from all new enabled modules.
 *
 * @param array $modules
 *   An array of the modules that were enabled.
 */
function _breakpoint_modules_enabled($modules) {
  foreach ($modules as $module) {
    $media_queries = breakpoint_get_module_media_queries($module);
    _breakpoint_import_media_queries($module, $module, Breakpoint::SOURCE_TYPE_MODULE, $media_queries);

    // Import custom groups.
    _breakpoint_import_breakpoint_groups($module, Breakpoint::SOURCE_TYPE_MODULE);
  }
}

/**
 * Import media queries from a theme or module and create a default group.
 *
 * @param string $group_name
 *   Machine readable name of the breakpoint group.
 * @param string $label
 *   Human readable name of the breakpoint group.
 * @param string $source_type
 *   Either Breakpoint::SOURCE_TYPE_THEME or Breakpoint::SOURCE_TYPE_MODULE.
 * @param array $media_queries
 *   An array of breakpoints in the form $breakpoint['name'] = 'media query'.
 */
function _breakpoint_import_media_queries($group_name, $label, $source_type, $media_queries) {
  if (!empty($media_queries)) {

    // Create a new breakpoint group if it doesn't exist.
    $breakpoint_group = _breakpoint_group_create_or_load($group_name, $label, $group_name, $source_type);

    // Load all media queries, create a breakpoint for each one and add them
    // to this breakpoint group.
    foreach ($media_queries as $name => $media_query) {
      $breakpoint_group
        ->addBreakpointFromMediaQuery($name, $media_query);
    }
    $breakpoint_group
      ->save();
  }
}

/**
 * Import breakpoint groups from theme or module.
 *
 * @param string $source
 *   The theme or module name
 * @param string $source_type
 *   Either Breakpoint::SOURCE_TYPE_THEME or Breakpoint::SOURCE_TYPE_MODULE.
 */
function _breakpoint_import_breakpoint_groups($source, $source_type) {
  $breakpoint_groups = config($source . '.breakpoint_groups');
  if ($breakpoint_groups) {
    foreach ($breakpoint_groups
      ->get() as $group_name => $data) {

      // Breakpoints is mandatory, extra check since this is coming from config.
      if (isset($data['breakpoints']) && !empty($data['breakpoints'])) {

        // Create a new breakpoint group if it doesn't exist.
        $breakpoint_group = _breakpoint_group_create_or_load($group_name, isset($data['label']) ? $data['label'] : $group_name, $source, $source_type);

        // Add the breakpoints.
        $breakpoint_group
          ->addBreakpoints($data['breakpoints']);
        $breakpoint_group
          ->save();
      }
      else {
        throw new \Exception('Illegal config file detected.');
      }
    }
  }
}

/**
 * Remove breakpoints from all disabled themes or uninstalled modules.
 *
 * The source type has to match the original source type, otherwise the group
 * will not be deleted. All groups created by the theme or module will be
 * deleted as well.
 *
 * @param array $list
 *   A list of modules or themes that are disabled.
 * @param string $source_type
 *   Either Breakpoint::SOURCE_TYPE_THEME or Breakpoint::SOURCE_TYPE_MODULE.
 */
function _breakpoint_delete_breakpoints($list, $source_type) {
  $ids = config_get_storage_names_with_prefix('breakpoint.breakpoint_group.' . $source_type . '.');
  $entity_info = entity_get_info('breakpoint_group');

  // Remove the breakpoint.breakpoint part of the breakpoint identifier.
  foreach ($ids as &$id) {
    $id = ConfigStorageController::getIDFromConfigName($id, $entity_info['config_prefix']);
  }
  $breakpoint_groups = entity_load_multiple('breakpoint_group', $ids);
  foreach ($breakpoint_groups as $breakpoint_group) {
    if ($breakpoint_group->sourceType == $source_type && in_array($breakpoint_group->source, $list)) {

      // Delete the automatically created breakpoint group.
      $breakpoint_group
        ->delete();

      // Get all breakpoints defined by this theme/module.
      $breakpoint_ids = drupal_container()
        ->get('config.storage')
        ->listAll('breakpoint.breakpoint.' . $source_type . '.' . $breakpoint_group
        ->id() . '.');
      $entity_info = entity_get_info('breakpoint');

      // Remove the breakpoint.breakpoint part of the breakpoint identifier.
      foreach ($breakpoint_ids as &$breakpoint_id) {
        $breakpoint_id = ConfigStorageController::getIDFromConfigName($breakpoint_id, $entity_info['config_prefix']);
      }
      $breakpoints = entity_load_multiple('breakpoint', $breakpoint_ids);

      // Make sure we only delete breakpoints defined by this theme/module.
      foreach ($breakpoints as $breakpoint) {
        if ($breakpoint->sourceType == $source_type && $breakpoint->source == $breakpoint_group->name) {
          $breakpoint
            ->delete();
        }
      }
    }
  }

  // Delete groups defined by a module/theme even if that module/theme didn't
  // define any breakpoints.
  foreach ($ids as $id) {

    // Delete all breakpoint groups defined by the theme or module.
    _breakpoint_delete_breakpoint_groups($id, $source_type);
  }
}

/**
 * Remove breakpoint groups from all disabled themes or uninstalled modules.
 *
 * @param array $group_id
 *   Machine readable name of the breakpoint group.
 * @param string $source_type
 *   Either Breakpoint::SOURCE_TYPE_THEME or Breakpoint::SOURCE_TYPE_MODULE.
 */
function _breakpoint_delete_breakpoint_groups($group_id, $source_type) {
  $breakpoint_groups = entity_load_multiple('breakpoint_group');
  foreach ($breakpoint_groups as $breakpoint_group) {
    if ($breakpoint_group->sourceType == $source_type && $breakpoint_group->source == $group_id) {
      $breakpoint_group
        ->delete();
    }
  }
}

/**
 * Get a list of available breakpoints from a specified theme.
 *
 * @param string $theme_key
 *   The name of the theme.
 *
 * @return array
 *   An array of breakpoints in the form $breakpoint['name'] = 'media query'.
 */
function breakpoint_get_theme_media_queries($theme_key) {
  $themes = list_themes();
  if (!isset($themes[$theme_key])) {
    throw new \Exception('Illegal theme_key passed.');
  }
  $config = config($theme_key . '.breakpoints');
  if ($config) {
    return $config
      ->get();
  }
  return array();
}

/**
 * Get a list of available breakpoints from a specified module.
 *
 * @param string $module
 *   The name of the module.
 *
 * @return array
 *   An array of breakpoints in the form $breakpoint['name'] = 'media query'.
 */
function breakpoint_get_module_media_queries($module) {
  if (!module_exists($module)) {
    throw new \Exception('Illegal module name passed.');
  }
  $config = config($module . '.breakpoints');
  if ($config) {
    return $config
      ->get();
  }
  return array();
}

/**
 * Load one breakpoint group by its identifier.
 *
 * @param string $id
 *   The id of the breakpoint group to load.
 *
 * @return Drupal\breakpoint\Plugin\Core\Entity\BreakpointGroup|false
 *   The breakpoint group, or FALSE if there is no entity with the given id.
 *
 * @todo Remove this in a follow-up issue.
 * @see http://drupal.org/node/1798214
 */
function breakpoint_group_load($id) {
  return entity_load('breakpoint_group', $id);
}

/**
 * Load one breakpoint by its identifier.
 *
 * @param int $id
 *   The id of the breakpoint to load.
 *
 * @return Drupal\breakpoint\Plugin\Core\Entity\Breakpoint
 *   The entity object, or FALSE if there is no entity with the given id.
 *
 * @todo Remove this in a follow-up issue.
 * @see http://drupal.org/node/1798214
 */
function breakpoint_load($id) {
  return entity_load('breakpoint', $id);
}

/**
 * Load all breakpoint groups as select options.
 *
 * @return array
 *   An array containing breakpoint group labels indexed by their ids.
 */
function breakpoint_group_select_options() {
  $options = array();
  $breakpoint_groups = entity_load_multiple('breakpoint_group');
  foreach ($breakpoint_groups as $breakpoint_group) {
    $options[$breakpoint_group
      ->id()] = $breakpoint_group
      ->label();
  }
  asort($options);
  return $options;
}

/**
 * Load all breakpoints as select options.
 *
 * @return array
 *   An array containing breakpoints indexed by their ids.
 */
function breakpoint_select_options() {
  $options = array();
  $breakpoints = entity_load_multiple('breakpoint');
  foreach ($breakpoints as $breakpoint) {
    $options[$breakpoint
      ->id()] = $breakpoint
      ->label() . ' (' . $breakpoint->source . ' - ' . $breakpoint->sourceType . ') [' . $breakpoint->mediaQuery . ']';
  }
  asort($options);
  return $options;
}

/**
 * Helper function to easily create/load a breakpoint group.
 *
 * @param string $name
 *   Machine readable name of the breakpoint group.
 * @param string $label
 *   Human readable name of the breakpoint group.
 * @param string $source
 *   Machine readable name of the defining theme or module.
 * @param string $source_type
 *   Either Breakpoint::SOURCE_TYPE_THEME or Breakpoint::SOURCE_TYPE_MODULE.
 *
 * @return Drupal\breakpoint\Plugin\Core\Entity\BreakpointGroup
 *
 * @see _breakpoint_import_media_queries()
 * @see _breakpoint_import_breakpoint_groups()
 */
function _breakpoint_group_create_or_load($name, $label, $source, $source_type) {

  // Try loading the breakpoint group.
  $breakpoint_group = entity_load('breakpoint_group', $source_type . '.' . $source . '.' . $name);

  // Create a new breakpoint group if it doesn't exist.
  if (!$breakpoint_group) {

    // Build a new breakpoint group.
    $breakpoint_group = entity_create('breakpoint_group', array(
      'name' => $name,
      'label' => $label,
      'source' => $source,
      'sourceType' => $source_type,
    ));
  }
  return $breakpoint_group;
}

Functions

Namesort descending Description
breakpoint_get_module_media_queries Get a list of available breakpoints from a specified module.
breakpoint_get_theme_media_queries Get a list of available breakpoints from a specified theme.
breakpoint_group_load Load one breakpoint group by its identifier.
breakpoint_group_select_options Load all breakpoint groups as select options.
breakpoint_help Implements hook_help().
breakpoint_load Load one breakpoint by its identifier.
breakpoint_modules_enabled Implements hook_modules_enabled().
breakpoint_modules_uninstalled Implements hook_modules_uninstalled().
breakpoint_select_options Load all breakpoints as select options.
breakpoint_themes_disabled Implements hook_themes_disabled().
breakpoint_themes_enabled Implements hook_themes_enabled().
_breakpoint_delete_breakpoints Remove breakpoints from all disabled themes or uninstalled modules.
_breakpoint_delete_breakpoint_groups Remove breakpoint groups from all disabled themes or uninstalled modules.
_breakpoint_group_create_or_load Helper function to easily create/load a breakpoint group.
_breakpoint_import_breakpoint_groups Import breakpoint groups from theme or module.
_breakpoint_import_media_queries Import media queries from a theme or module and create a default group.
_breakpoint_modules_enabled Import breakpoints from all new enabled modules.
_breakpoint_theme_enabled Import breakpoints from all new enabled themes.