You are here

breakpoints.module in Breakpoints 7

Breakpoints @todo: provide button to reload breakpoints from theme

File

breakpoints.module
View source
<?php

/**
 * @file
 * Breakpoints
 * @todo: provide button to reload breakpoints from theme
 */
define('BREAKPOINTS_SOURCE_TYPE_THEME', 'theme');
define('BREAKPOINTS_SOURCE_TYPE_MODULE', 'module');
define('BREAKPOINTS_SOURCE_TYPE_CUSTOM', 'custom');
define('BREAKPOINTS_GROUP', 'group');

/**
 * Implements hook_permission().
 */
function breakpoints_permission() {
  return array(
    'administer breakpoints' => array(
      'title' => t('Administer Breakpoints'),
      'description' => t('Administer all breakpoints'),
    ),
  );
}

/**
 * Implements hook_ctools_plugin_directory().
 */
function breakpoints_ctools_plugin_directory($module, $plugin) {
  if ($module == 'ctools' && $plugin == 'export_ui') {
    return 'plugins/' . $plugin;
  }
}

/**
 * Implements hook_ctools_plugin_api().
 */
function breakpoints_ctools_plugin_api($owner, $api) {
  return array(
    'version' => 1,
  );
}

/**
 * Implements hook_enable().
 * Import breakpoints from all enabled themes.
 */
function breakpoints_enable() {
  $themes = list_themes();
  foreach ($themes as $theme_key => $theme) {
    if (!$theme->status) {
      unset($themes[$theme_key]);
    }
  }
  breakpoints_themes_enabled(array_keys($themes));
}

/**
 * Implements hook_themes_enabled();
 * Import breakpoints from all new enabled themes.
 * Do not use breakpoints_breakpoints_group_reload_from_theme as is clears the cache.
 */
function breakpoints_themes_enabled($theme_list, $rebuild_menu = TRUE) {
  $themes = list_themes();
  $updated = FALSE;
  $new_breakpoint_group = FALSE;
  foreach ($theme_list as $theme_key) {
    if (isset($themes[$theme_key]->info['breakpoints'])) {
      $updated = TRUE;
      $weight = 0;
      $theme_settings = $themes[$theme_key]->info['breakpoints'];
      $multipliers = isset($themes[$theme_key]->info['multipliers']) ? $themes[$theme_key]->info['multipliers'] : array();
      $settings = breakpoints_settings();
      $current_multipliers = drupal_map_assoc($settings->multipliers);
      $breakpoint_group = breakpoints_breakpoint_group_load($theme_key);
      if (!$breakpoint_group) {

        // Build a group for each theme
        $new_breakpoint_group = TRUE;
        $breakpoint_group = breakpoints_breakpoint_group_empty_object();
        $breakpoint_group->machine_name = $theme_key;
        $breakpoint_group->name = $themes[$theme_key]->info['name'];
        $breakpoint_group->type = BREAKPOINTS_SOURCE_TYPE_THEME;
      }
      foreach ($theme_settings as $name => $media_query) {
        $breakpoint = breakpoints_breakpoint_load($name, $theme_key, 'theme');
        if (!$breakpoint) {
          $breakpoint = breakpoints_breakpoint_empty_object();
          $breakpoint->name = $name;
          $breakpoint->source = $theme_key;
          $breakpoint->source_type = 'theme';
          $breakpoint->theme = '';
          $breakpoint->status = TRUE;
          $breakpoint->weight = $weight++;
          $breakpoint->machine_name = breakpoints_breakpoint_config_name($breakpoint);
        }
        $breakpoint->breakpoint = $media_query;
        $breakpoint->multipliers = isset($multipliers[$name]) ? drupal_map_assoc($multipliers[$name]) : array();
        $current_multipliers += drupal_map_assoc($breakpoint->multipliers);
        breakpoints_breakpoint_save($breakpoint);
        $breakpoint_group->breakpoints[] = $breakpoint->machine_name;
      }
      breakpoints_settings_save($current_multipliers);
      breakpoints_breakpoint_group_save($breakpoint_group);
      if ($new_breakpoint_group) {
        $message_text = 'The breakpoints from theme %theme are imported and <a href="@url">a new group is created</a>.';
      }
      else {
        $message_text = 'The breakpoints from theme %theme are imported and <a href="@url">an existing group was updated</a>.';
      }
      $message = t($message_text, array(
        '%theme' => $themes[$theme_key]->info['name'],
        '@url' => url('admin/config/media/breakpoints/groups/' . $theme_key),
      ));
      drupal_set_message($message, 'status');
    }
  }
  if ($rebuild_menu && $updated) {
    variable_set('menu_rebuild_needed', TRUE);
  }
}

/**
 * Implements hook_themes_disabled();
 * Remove breakpoints from all disabled themes.
 */
function breakpoints_themes_disabled($theme_list) {
  $themes = list_themes();
  foreach ($theme_list as $theme_key) {
    $breakpoints = breakpoints_breakpoint_load_all_theme($theme_key);
    foreach ($breakpoints as $breakpoint) {
      breakpoints_breakpoint_delete($breakpoint, $theme_key);
    }
    breakpoints_breakpoint_group_delete_by_name($theme_key);
  }
  variable_set('menu_rebuild_needed', TRUE);
}

/**
 * Implements hook_menu().
 */
function breakpoints_menu() {
  $items = array();

  // @todo: link to all breakpoints and a list of all groups
  // cf theme settings page
  $items['admin/config/media/breakpoints'] = array(
    'title' => 'Breakpoints',
    'description' => 'Manage breakpoints',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'breakpoints_admin_breakpoints',
    ),
    'access arguments' => array(
      'administer breakpoints',
    ),
    'file' => 'breakpoints.admin.inc',
  );
  $items['admin/config/media/breakpoints/create_style'] = array(
    'title' => 'Add responsive style',
    'description' => 'Add a responsive image style',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'breakpoints_add_style_form',
    ),
    'access arguments' => array(
      'administer breakpoints',
    ),
    'file' => 'breakpoints.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 30,
  );
  $items['admin/config/media/breakpoints/multipliers'] = array(
    'title' => 'Multipliers',
    'description' => 'Manage multipliers',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'breakpoints_multipliers_form',
    ),
    'access arguments' => array(
      'administer breakpoints',
    ),
    'file' => 'breakpoints.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 20,
  );
  $items['admin/config/media/breakpoints/settings'] = array(
    'title' => 'Settings',
    'description' => 'Manage breakpoint settings',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'breakpoints_admin_settings_form',
    ),
    'access arguments' => array(
      'administer breakpoints',
    ),
    'file' => 'breakpoints.admin.inc',
    'type' => MENU_LOCAL_TASK,
    'weight' => 30,
  );
  $items['admin/config/media/breakpoints/multipliers/%/delete'] = array(
    'title' => '',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'breakpoints_admin_multiplier_delete_form',
      5,
    ),
    'type' => MENU_CALLBACK,
    'access arguments' => array(
      'administer breakpoints',
    ),
    'file' => 'breakpoints.admin.inc',
    'weight' => 15,
  );
  $items['admin/config/media/breakpoints/groups'] = array(
    'title' => 'Groups',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => 10,
  );
  $items['admin/config/media/breakpoints/groups/global'] = array(
    'title' => 'All breakpoints',
    'type' => MENU_DEFAULT_LOCAL_TASK,
    'weight' => -1,
  );
  $items['admin/config/media/breakpoints/groups/add'] = array(
    'title' => 'Add a new group',
    'page arguments' => array(
      'breakpoints_admin_breakpoint_group_edit_form',
    ),
    'type' => MENU_LOCAL_TASK,
    'access arguments' => array(
      'administer breakpoints',
    ),
    'file' => 'breakpoints.admin.inc',
    'weight' => 99,
  );
  $items['admin/config/media/breakpoints/groups/import'] = array(
    'title' => 'Import a new group',
    'page arguments' => array(
      'breakpoints_admin_breakpoint_group_import_form',
    ),
    'type' => MENU_LOCAL_TASK,
    'access arguments' => array(
      'administer breakpoints',
    ),
    'file' => 'breakpoints.admin.inc',
    'weight' => 99,
  );
  $items['admin/config/media/breakpoints/groups/import-breakpoint'] = array(
    'title' => 'Import a new breakpoint',
    'page arguments' => array(
      'breakpoints_admin_breakpoint_import_form',
    ),
    'type' => MENU_LOCAL_TASK,
    'access arguments' => array(
      'administer breakpoints',
    ),
    'file' => 'breakpoints.admin.inc',
    'weight' => 99,
  );
  $items['admin/config/media/breakpoints/%/%'] = array(
    'title' => '',
    'page callback' => 'breakpoints_admin_breakpoint_actions_page',
    'page arguments' => array(
      '',
      4,
      5,
    ),
    'type' => MENU_CALLBACK,
    'access arguments' => array(
      'administer breakpoints',
    ),
    'file' => 'breakpoints.admin.inc',
    'weight' => 15,
  );
  $breakpoint_groups = breakpoints_breakpoint_group_load_all();
  foreach ($breakpoint_groups as $breakpoint_group_name => $breakpoint_group) {
    if (!empty($breakpoint_group->machine_name)) {
      $items['admin/config/media/breakpoints/groups/' . $breakpoint_group->machine_name] = array(
        'title' => $breakpoint_group->name,
        'page arguments' => array(
          'breakpoints_admin_breakpoints',
          $breakpoint_group->machine_name,
        ),
        'type' => MENU_LOCAL_TASK,
        'access arguments' => array(
          'administer breakpoints',
        ),
        'file' => 'breakpoints.admin.inc',
        'weight' => 15,
      );
      $items['admin/config/media/breakpoints/groups/' . $breakpoint_group->machine_name . '/edit'] = array(
        'title' => 'Edit ' . $breakpoint_group->name,
        'page arguments' => array(
          'breakpoints_admin_breakpoint_group_edit_form',
          $breakpoint_group->machine_name,
        ),
        'type' => MENU_CALLBACK,
        'access arguments' => array(
          'administer breakpoints',
        ),
        'file' => 'breakpoints.admin.inc',
        'weight' => 15,
      );
      $items['admin/config/media/breakpoints/groups/' . $breakpoint_group->machine_name . '/delete'] = array(
        'title' => 'Delete ' . $breakpoint_group->name,
        'page arguments' => array(
          'breakpoints_admin_breakpoint_group_delete_form',
          $breakpoint_group->machine_name,
        ),
        'type' => MENU_CALLBACK,
        'access arguments' => array(
          'administer breakpoints',
        ),
        'file' => 'breakpoints.admin.inc',
        'weight' => 15,
      );
      $items['admin/config/media/breakpoints/groups/' . $breakpoint_group->machine_name . '/export'] = array(
        'title' => 'Export ' . $breakpoint_group->name,
        'page arguments' => array(
          'breakpoints_admin_breakpoint_group_export_form',
          $breakpoint_group->machine_name,
        ),
        'type' => MENU_LOCAL_ACTION,
        'access arguments' => array(
          'administer breakpoints',
        ),
        'file' => 'breakpoints.admin.inc',
        'weight' => 15,
      );
      $items['admin/config/media/breakpoints/groups/' . $breakpoint_group->machine_name . '/duplicate'] = array(
        'title' => 'Duplicate ' . $breakpoint_group->name,
        'page arguments' => array(
          'breakpoints_admin_breakpoint_group_duplicate_form',
          $breakpoint_group->machine_name,
        ),
        'type' => MENU_CALLBACK,
        'access arguments' => array(
          'administer breakpoints',
        ),
        'file' => 'breakpoints.admin.inc',
        'weight' => 15,
      );
      $items['admin/config/media/breakpoints/groups/' . $breakpoint_group->machine_name . '/%/%'] = array(
        'title' => '',
        'page arguments' => array(
          'breakpoints_admin_breakpoint_actions_form',
          $breakpoint_group->machine_name,
          6,
          7,
        ),
        'type' => MENU_CALLBACK,
        'access arguments' => array(
          'administer breakpoints',
        ),
        'file' => 'breakpoints.admin.inc',
        'weight' => 15,
      );
    }
  }
  return $items;
}

/**
 * Load general settings.
 */
function breakpoints_settings() {
  $config = new StdClass();
  $config->multipliers = variable_get('breakpoints_multipliers', array(
    '1x',
    '1.5x',
    '2x',
  ));
  return $config;
}

/**
 * Save general settings.
 */
function breakpoints_settings_save($multipliers) {
  variable_set('breakpoints_multipliers', $multipliers);
}

/**
 * Sort breakpoints by weight.
 */
function _breakpoints_sort_by_weight($a, $b) {
  if (isset($a->weight) && isset($b->weight)) {
    if ($a->weight == $b->weight) {
      if (isset($a->source_type) && $a->source_type == BREAKPOINTS_SOURCE_TYPE_CUSTOM) {
        return -1;
      }
      if (isset($b->source_type) && $b->source_type == BREAKPOINTS_SOURCE_TYPE_CUSTOM) {
        return 1;
      }
      return 0;
    }
    return $a->weight < $b->weight ? -1 : 1;
  }
  return 0;
}

/**
 * Sort breakpoints by weight.
 */
function _breakpoints_sort_by_weight_array($a, $b) {
  return _breakpoints_sort_by_weight((object) $a, (object) $b);
}

/**
 * Construct config name.
 */
function breakpoints_breakpoint_config_name($breakpoints_breakpoint) {
  if (is_string($breakpoints_breakpoint)) {
    return $breakpoints_breakpoint;
  }
  else {
    return drupal_strtolower('breakpoints' . '.' . $breakpoints_breakpoint->source_type . '.' . $breakpoints_breakpoint->source . '.' . $breakpoints_breakpoint->name);
  }
}

/**
 * Load a single breakpoint.
 */
function breakpoints_breakpoint_load($name, $source, $source_type) {
  $key = drupal_strtolower('breakpoints.' . $source_type . '.' . $source . '.' . $name);
  return breakpoints_breakpoint_load_by_fullkey($key);
}

/**
 * Load a single breakpoint using the full config key.
 */
function breakpoints_breakpoint_load_by_fullkey($machine_name = NULL) {
  $breakpoints =& drupal_static(__FUNCTION__);
  if (!isset($breakpoints)) {
    $breakpoints = _breakpoints_breakpoint_load_all_callback();
  }
  if ($machine_name) {
    $breakpoint = isset($breakpoints[$machine_name]) ? $breakpoints[$machine_name] : FALSE;
    return $breakpoint;
  }
  else {
    return $breakpoints;
  }
}

/**
 * CTools export 'load all callback' CRUD callback for breakpoints.
 */
function _breakpoints_breakpoint_load_all_callback($reset = FALSE) {
  if (!$reset && ($cache = cache_get('breakpoints:breakpoints'))) {
    return $cache->data;
  }
  else {
    ctools_include('export');
    $breakpoints = ctools_export_load_object('breakpoints', 'all');
    cache_set('breakpoints:breakpoints', $breakpoints);
    return $breakpoints;
  }
}

/**
 * Load all breakpoints.
 */
function breakpoints_breakpoint_load_all($theme_key = '') {
  $breakpoints_user = breakpoints_breakpoint_load_all_custom();
  $breakpoints_module = breakpoints_breakpoint_load_all_module();
  $breakpoints_theme = breakpoints_breakpoint_load_all_theme($theme_key);
  $breakpoints = array_merge($breakpoints_theme, $breakpoints_module, $breakpoints_user);
  uasort($breakpoints, '_breakpoints_sort_by_weight');
  return $breakpoints;
}

/**
 * Load all enabled breakpoints.
 */
function breakpoints_breakpoint_load_all_active($theme_key = '') {
  $breakpoints = breakpoints_breakpoint_load_all($theme_key);
  $enabled = array();
  if (!empty($breakpoints)) {
    foreach ($breakpoints as $breakpoint_name => $breakpoint) {
      if ($breakpoint->status) {
        $enabled[$breakpoint_name] = $breakpoint;
      }
    }
  }
  return $enabled;
}

/**
 * Load all breakpoints by source type.
 */
function _breakpoints_breakpoint_load_all_by_type($source_type, $source = '') {
  $breakpoints = breakpoints_breakpoint_load_by_fullkey();
  foreach ($breakpoints as $machine_name => $breakpoint) {
    if ($breakpoint->source_type != $source_type) {
      unset($breakpoints[$machine_name]);
      continue;
    }
    if ($source != '' && $breakpoint->source != $source) {
      unset($breakpoints[$machine_name]);
    }
  }
  return $breakpoints;
}

/**
 * Load all custom breakpoints.
 */
function breakpoints_breakpoint_load_all_custom() {
  $breakpoints = _breakpoints_breakpoint_load_all_by_type(BREAKPOINTS_SOURCE_TYPE_CUSTOM);
  return $breakpoints;
}

/**
 * Load all user defined breakpoints.
 */
function breakpoints_breakpoint_load_all_module() {
  return _breakpoints_breakpoint_load_all_by_type(BREAKPOINTS_SOURCE_TYPE_MODULE);
}

/**
 * Load all breakpoints from the theme.
 */
function breakpoints_breakpoint_load_all_theme($theme_key = '') {
  return _breakpoints_breakpoint_load_all_by_type(BREAKPOINTS_SOURCE_TYPE_THEME, $theme_key);
}

/**
 * Empty breakpoint object.
 */
function breakpoints_breakpoint_empty_object() {
  return (object) breakpoints_breakpoint_empty_array();
}

/**
 * Empty breakpoint array.
 */
function breakpoints_breakpoint_empty_array() {
  return array(
    'name' => '',
    'machine_name' => '',
    'breakpoint' => '',
    'source' => '',
    'source_type' => '',
    'status' => TRUE,
    'weight' => 0,
    'multipliers' => array(),
  );
}

/**
 * Save a single breakpoint.
 */
function breakpoints_breakpoint_save(&$breakpoint) {
  ctools_include('export');
  if (!isset($breakpoint->machine_name) || empty($breakpoint->machine_name)) {
    $breakpoint->machine_name = breakpoints_breakpoint_config_name($breakpoint);
  }
  $update = isset($breakpoint->id) && is_numeric($breakpoint->id) ? array(
    'id',
  ) : array();

  // Remove unused multipliers.
  $breakpoint->multipliers = array_filter($breakpoint->multipliers);
  if (is_null($breakpoint->multipliers)) {
    $breakpoint->multipliers = array();
  }

  // Add the '1x' multiplier.
  $breakpoint->multipliers = array_merge($breakpoint->multipliers, array(
    '1x' => '1x',
  ));
  $result = drupal_write_record('breakpoints', $breakpoint, $update);
  breakpoints_breakpoint_reset();
  return $result;
}

/**
 * Delete a single breakpoint.
 */
function breakpoints_breakpoint_delete($breakpoint) {
  $name = breakpoints_breakpoint_config_name($breakpoint);
  return breakpoints_breakpoint_delete_by_fullkey($name);
}

/**
 * Delete a single breakpoint.
 */
function breakpoints_breakpoint_delete_by_fullkey($key) {
  if (!empty($key)) {
    $sql = "DELETE FROM {breakpoints} where machine_name = :key";
    db_query($sql, array(
      ':key' => $key,
    ));
  }
  breakpoints_breakpoint_reset();
}

/**
 * Clears the breakpoint caches.
 */
function breakpoints_breakpoint_reset() {
  ctools_include('export');
  ctools_export_load_object_reset('breakpoints');
  drupal_static_reset('breakpoints_breakpoint_load_by_fullkey');
  cache_clear_all('breakpoints:breakpoints', 'cache');
}

/**
 * Toggle status of a single breakpoint.
 */
function breakpoints_breakpoint_toggle_status($machine_name) {
  $breakpoint = breakpoints_breakpoint_load_by_fullkey($machine_name);
  if ($breakpoint) {
    $breakpoint->status = !$breakpoint->status;
    breakpoints_breakpoint_save($breakpoint);
  }
}

/**
 * Check if a breakpoint name already exists.
 */
function breakpoints_breakpoint_name_exists($machine_name) {
  $breakpoints = breakpoints_breakpoint_load_all_custom();
  $fullkey = 'custom.user.' . $machine_name;
  return array_key_exists($fullkey, $breakpoints);
}

/**
 * Check if a breakpoint machine name already exists.
 */
function breakpoints_breakpoint_machine_name_exists($machine_name) {

  // Just try to load the breakpoint object, we profit from ctool's cache mechanism,
  // better that doing a query to the db every time this function is called.
  return (bool) breakpoints_breakpoint_load_by_fullkey($machine_name);
}

/**
 * Empty breakpoint group object.
 */
function breakpoints_breakpoint_group_empty_object() {
  return (object) breakpoints_breakpoint_group_empty_array();
}

/**
 * Empty breakpoint group array.
 */
function breakpoints_breakpoint_group_empty_array() {
  return array(
    'machine_name' => '',
    'name' => '',
    'breakpoints' => array(),
    'type' => 'custom',
  );
}

/**
 * Check if a group name already exists.
 */
function breakpoints_breakpoint_group_name_exists($machine_name) {

  // Check for reserved words.
  if ($machine_name == 'global' || $machine_name == 'add') {
    return TRUE;
  }

  // Check if group name is used before.
  $group_check = breakpoints_breakpoint_group_load($machine_name);
  if ($group_check && isset($group_check->machine_name) && !empty($group_check->machine_name)) {
    return TRUE;
  }
  return FALSE;
}

/**
 * Load all breakpoint groups.
 */
function breakpoints_breakpoint_group_load_all($reset = FALSE) {
  $groups =& drupal_static(__FUNCTION__);
  if (!isset($groups)) {
    if (!$reset && ($cache = cache_get('breakpoints:groups'))) {
      return $cache->data;
    }
    else {
      ctools_include('export');
      $groups = ctools_export_load_object('breakpoint_group', 'all');
      cache_set('breakpoints:groups', $groups);
    }
  }
  return $groups;
}

/**
 * Load a single breakpoint group.
 */
function breakpoints_breakpoint_group_load($name = NULL) {
  $groups = breakpoints_breakpoint_group_load_all();
  if ($name) {
    $group = isset($groups[$name]) ? $groups[$name] : FALSE;
    return $group;
  }
  else {
    return $groups;
  }
}

/**
 * Validate a single breakpoint group.
 */
function breakpoints_breakpoint_group_validate($group) {
  if (!is_object($group)) {
    return FALSE;
  }
  foreach (array(
    'machine_name',
    'name',
    'breakpoints',
    'type',
  ) as $property) {
    if (!property_exists($group, $property)) {
      return FALSE;
    }
  }
  return TRUE;
}

/**
 * Validate a single breakpoint.
 */
function breakpoints_breakpoint_validate($breakpoint) {
  if (!is_object($breakpoint)) {
    return FALSE;
  }
  foreach (array_keys(breakpoints_breakpoint_empty_array()) as $property) {
    if (!property_exists($breakpoint, $property)) {
      return FALSE;
    }
  }
  return TRUE;
}

/**
 * Save a single breakpoint group.
 */
function breakpoints_breakpoint_group_save(&$breakpoint_group) {
  ctools_include('export');
  $update = isset($breakpoint_group->id) && is_numeric($breakpoint_group->id) ? array(
    'id',
  ) : array();
  $result = drupal_write_record('breakpoint_group', $breakpoint_group, $update);

  // rebuild menu if we add a new group
  if (empty($update)) {
    variable_set('menu_rebuild_needed', TRUE);
  }
  breakpoints_breakpoint_group_reset();
  return $result;
}

/**
 * Delete a single breakpoint group.
 */
function breakpoints_breakpoint_group_delete($breakpoint_group) {
  $name = $breakpoint_group->machine_name;
  breakpoints_breakpoint_group_delete_by_fullkey($name);
}

/**
 * Delete a single breakpoint group by fullkey.
 */
function breakpoints_breakpoint_group_delete_by_name($machine_name) {
  $name = $machine_name;
  breakpoints_breakpoint_group_delete_by_fullkey($name);
}

/**
 * Delete a single breakpoint group by fullkey.
 */
function breakpoints_breakpoint_group_delete_by_fullkey($key) {
  if (!empty($key)) {
    $sql = "DELETE FROM {breakpoint_group} where machine_name = :key";
    db_query($sql, array(
      ':key' => $key,
    ));
  }
  variable_set('menu_rebuild_needed', TRUE);
  breakpoints_breakpoint_group_reset();
}

/**
 * Clears the breakpoint group caches.
 */
function breakpoints_breakpoint_group_reset() {
  ctools_include('export');
  ctools_export_load_object_reset('breakpoint_group');
  drupal_static_reset('breakpoints_breakpoint_group_load_all');
  cache_clear_all('breakpoints:groups', 'cache');
}

/**
 * Implements hook_theme().
 */
function breakpoints_theme() {
  return array(
    'breakpoints_admin_breakpoints_table' => array(
      'render element' => 'form',
      'theme_key' => NULL,
    ),
    'breakpoints_multipliers_table_form' => array(
      'render element' => 'form',
      'theme_key' => NULL,
    ),
  );
}

/**
 * Export callback.
 * @see breakpoints_schema()
 */
function breakpoint_group_export_breakpoints($object, $field, $value, $indent) {
  ctools_include('export');
  $export = array();
  if (isset($object->breakpoints)) {
    foreach ($object->breakpoints as $breakpoint) {
      if (!is_array($breakpoint) && !is_object($breakpoint)) {
        $breakpoint = breakpoints_breakpoint_load_by_fullkey($breakpoint);
      }
      $export[] = $breakpoint->machine_name;
    }
  }
  return ctools_var_export($export, $indent);
}

/**
 * Reload the breakpoints as defined by the group.
 */
function breakpoints_breakpoints_group_reload(&$group, $force = TRUE) {
  switch ($group->type) {
    case BREAKPOINTS_SOURCE_TYPE_THEME:

      // delete all breakpoints defined by this theme.
      $breakpoints = breakpoints_breakpoint_load_all_theme($group->machine_name);
      foreach ($breakpoints as $breakpoint) {
        breakpoints_breakpoint_delete($breakpoint);
      }

      // Reload all breakpoints from theme.info.
      $reloaded_group = breakpoints_breakpoints_group_reload_from_theme($group->machine_name);

      // Reset the breakpoints for this group.
      if ($force) {
        $group->breakpoints = $reloaded_group->breakpoints;
        breakpoints_breakpoint_group_save($group);
      }
      break;
  }
}
function breakpoints_breakpoints_group_reload_from_theme($theme_key) {

  // Clear caches so theme.info is fresh.
  system_rebuild_theme_data();
  drupal_theme_rebuild();
  $themes = list_themes();
  if (isset($themes[$theme_key]->info['breakpoints'])) {
    $weight = 0;
    $theme_settings = $themes[$theme_key]->info['breakpoints'];
    $multipliers = isset($themes[$theme_key]->info['multipliers']) ? $themes[$theme_key]->info['multipliers'] : array();
    $settings = breakpoints_settings();
    $current_multipliers = drupal_map_assoc($settings->multipliers);

    // Build a group for each theme
    $breakpoint_group = breakpoints_breakpoint_group_empty_object();
    $breakpoint_group->machine_name = $theme_key;
    $breakpoint_group->name = $themes[$theme_key]->info['name'];
    $breakpoint_group->type = BREAKPOINTS_SOURCE_TYPE_THEME;
    foreach ($theme_settings as $name => $media_query) {
      $breakpoint = breakpoints_breakpoint_load($name, $theme_key, 'theme');
      if (!$breakpoint) {
        $breakpoint = breakpoints_breakpoint_empty_object();
        $breakpoint->name = $name;
        $breakpoint->source = $theme_key;
        $breakpoint->source_type = 'theme';
        $breakpoint->theme = '';
        $breakpoint->status = TRUE;
        $breakpoint->weight = $weight++;
        $breakpoint->machine_name = breakpoints_breakpoint_config_name($breakpoint);
      }
      $breakpoint->breakpoint = $media_query;
      $breakpoint->multipliers = isset($multipliers[$name]) ? drupal_map_assoc($multipliers[$name]) : array();
      $current_multipliers += drupal_map_assoc($breakpoint->multipliers);
      breakpoints_breakpoint_save($breakpoint);
      $breakpoint_group->breakpoints[] = $breakpoint->machine_name;
    }
    breakpoints_settings_save($current_multipliers);
    return $breakpoint_group;
  }
}

/**
 * Revert the breakpoints of a group.
 */
function breakpoints_breakpoints_group_revert(&$group) {
  breakpoints_breakpoints_group_reload($group);
  $group->overridden = 0;
  breakpoints_breakpoint_group_save($group);
}

/**
 * Duplicate a group.
 */
function breakpoints_breakpoints_group_duplicate($group, $new_name, $new_machine_name) {
  $new_group = breakpoints_breakpoint_group_empty_object();
  $new_group->machine_name = $new_machine_name;
  $new_group->name = $new_name;
  $new_group->type = BREAKPOINTS_SOURCE_TYPE_CUSTOM;
  $new_group->breakpoints = $group->breakpoints;
  breakpoints_breakpoint_group_save($new_group);
  return $new_group;
}

/**
 * Override the breakpoints of a group.
 */
function breakpoints_breakpoints_group_override($group) {
  foreach ($group->breakpoints as $key => $breakpoint) {
    $breakpoint = breakpoints_breakpoint_load_by_fullkey($breakpoint);
    $old_breakpoint = clone $breakpoint;
    if ($breakpoint->source_type == BREAKPOINTS_SOURCE_TYPE_THEME && $breakpoint->source == $group->machine_name) {
      unset($breakpoint->id);
      $breakpoint->machine_name = 'custom.' . $breakpoint->source . '.' . str_replace('-', '_', drupal_clean_css_identifier($breakpoint->name));
      $breakpoint->source_type = BREAKPOINTS_SOURCE_TYPE_CUSTOM;

      // make sure it doesn't already exists.
      if (breakpoints_breakpoint_load_by_fullkey($breakpoint->machine_name) === FALSE) {
        breakpoints_breakpoint_save($breakpoint);
      }

      // Add to the group and delete old breakpoint.
      $group->breakpoints[$key] = $breakpoint->machine_name;
      breakpoints_breakpoint_delete($old_breakpoint, $group->machine_name);
    }
  }
  $group->overridden = 1;
  breakpoints_breakpoint_group_save($group);
}

/**
 * Export breakpoints ready for theme.info inclusion.
 */
function breakpoints_breakpoints_group_exporttotheme(&$group) {
  $export = array();
  foreach ($group->breakpoints as $breakpoint_name) {
    $breakpoint = breakpoints_breakpoint_load_by_fullkey($breakpoint_name);
    if ($breakpoint && $breakpoint->status) {
      $export[$breakpoint->name] = $breakpoint->breakpoint;
    }
  }
  return $export;
}

/**
 * array_filter callback.
 */
function _breakpoints_filter_styles($var) {
  static $exists = NULL;
  if (is_null($exists)) {
    $exists = module_exists('resp_img') && defined('RESP_IMG_STYLE_PREFIX');
  }
  if (!$exists) {
    return TRUE;
  }
  return strpos(is_array($var) ? $var['name'] : $var, RESP_IMG_STYLE_PREFIX) !== 0;
}

/**
 * Implements hook_permission().
 */
function breakpoints_form_system_theme_settings_alter(&$form, &$form_state) {
  if (isset($form_state['build_info']['args'][0])) {
    $form['actions']['rescan_breakpoints'] = array(
      '#type' => 'submit',
      '#value' => t('Scan this theme for breakpoints'),
      '#submit' => array(
        'breakpoints_form_system_theme_settings_alter_submit',
      ),
    );
  }
}
function breakpoints_form_system_theme_settings_alter_submit(&$form, &$form_state) {
  $theme = $form_state['build_info']['args'][0];
  $group = breakpoints_breakpoint_group_load($theme);
  if ($group) {
    breakpoints_breakpoints_group_reload($group);
  }
  else {
    breakpoints_themes_enabled(array(
      $theme,
    ));
  }
}

/**
 * Implements hook_features_export().
 */
function breakpoint_group_features_export($data, &$export, $module_name = '') {
  features_include();
  $pipe = ctools_component_features_export('breakpoint_group', $data, $export, $module_name);
  foreach ($data as $group_name) {
    $group = breakpoints_breakpoint_group_load($group_name);
    foreach ($group->breakpoints as $breakpoint_name) {
      $breakpoint = breakpoints_breakpoint_load_by_fullkey($breakpoint_name);
      if ($breakpoint->source_type != BREAKPOINTS_SOURCE_TYPE_THEME) {
        $pipe['breakpoints'][] = $breakpoint_name;
      }
    }
  }
  return $pipe;
}

/**
 * Implements hook_flush_caches().
 */
function breakpoints_flush_caches() {
  if (variable_get('breakpoints_flush_caches_disabled', FALSE)) {
    return;
  }

  // hook_flush_caches gets invoked with both drupal_flush_all_caches and system_cron
  // To avoid frequent menu/theme flushes, we must backtrace caller.
  $backtrace = debug_backtrace();
  if (isset($backtrace[3]) && $backtrace[3]['function'] == 'drupal_flush_all_caches' && empty($backtrace[3]['args'])) {
    $themes = list_themes();
    foreach ($themes as $theme_key => $theme) {
      if ($theme->status) {
        $group = breakpoints_breakpoint_group_load($theme_key);
        if ($group) {
          breakpoints_breakpoints_group_reload($group, FALSE);
        }
        else {
          breakpoints_themes_enabled(array(
            $theme_key,
          ), FALSE);
        }
      }
    }
  }
}

Functions

Namesort descending Description
breakpoints_breakpoints_group_duplicate Duplicate a group.
breakpoints_breakpoints_group_exporttotheme Export breakpoints ready for theme.info inclusion.
breakpoints_breakpoints_group_override Override the breakpoints of a group.
breakpoints_breakpoints_group_reload Reload the breakpoints as defined by the group.
breakpoints_breakpoints_group_reload_from_theme
breakpoints_breakpoints_group_revert Revert the breakpoints of a group.
breakpoints_breakpoint_config_name Construct config name.
breakpoints_breakpoint_delete Delete a single breakpoint.
breakpoints_breakpoint_delete_by_fullkey Delete a single breakpoint.
breakpoints_breakpoint_empty_array Empty breakpoint array.
breakpoints_breakpoint_empty_object Empty breakpoint object.
breakpoints_breakpoint_group_delete Delete a single breakpoint group.
breakpoints_breakpoint_group_delete_by_fullkey Delete a single breakpoint group by fullkey.
breakpoints_breakpoint_group_delete_by_name Delete a single breakpoint group by fullkey.
breakpoints_breakpoint_group_empty_array Empty breakpoint group array.
breakpoints_breakpoint_group_empty_object Empty breakpoint group object.
breakpoints_breakpoint_group_load Load a single breakpoint group.
breakpoints_breakpoint_group_load_all Load all breakpoint groups.
breakpoints_breakpoint_group_name_exists Check if a group name already exists.
breakpoints_breakpoint_group_reset Clears the breakpoint group caches.
breakpoints_breakpoint_group_save Save a single breakpoint group.
breakpoints_breakpoint_group_validate Validate a single breakpoint group.
breakpoints_breakpoint_load Load a single breakpoint.
breakpoints_breakpoint_load_all Load all breakpoints.
breakpoints_breakpoint_load_all_active Load all enabled breakpoints.
breakpoints_breakpoint_load_all_custom Load all custom breakpoints.
breakpoints_breakpoint_load_all_module Load all user defined breakpoints.
breakpoints_breakpoint_load_all_theme Load all breakpoints from the theme.
breakpoints_breakpoint_load_by_fullkey Load a single breakpoint using the full config key.
breakpoints_breakpoint_machine_name_exists Check if a breakpoint machine name already exists.
breakpoints_breakpoint_name_exists Check if a breakpoint name already exists.
breakpoints_breakpoint_reset Clears the breakpoint caches.
breakpoints_breakpoint_save Save a single breakpoint.
breakpoints_breakpoint_toggle_status Toggle status of a single breakpoint.
breakpoints_breakpoint_validate Validate a single breakpoint.
breakpoints_ctools_plugin_api Implements hook_ctools_plugin_api().
breakpoints_ctools_plugin_directory Implements hook_ctools_plugin_directory().
breakpoints_enable Implements hook_enable(). Import breakpoints from all enabled themes.
breakpoints_flush_caches Implements hook_flush_caches().
breakpoints_form_system_theme_settings_alter Implements hook_permission().
breakpoints_form_system_theme_settings_alter_submit
breakpoints_menu Implements hook_menu().
breakpoints_permission Implements hook_permission().
breakpoints_settings Load general settings.
breakpoints_settings_save Save general settings.
breakpoints_theme Implements hook_theme().
breakpoints_themes_disabled Implements hook_themes_disabled(); Remove breakpoints from all disabled themes.
breakpoints_themes_enabled Implements hook_themes_enabled(); Import breakpoints from all new enabled themes. Do not use breakpoints_breakpoints_group_reload_from_theme as is clears the cache.
breakpoint_group_export_breakpoints Export callback.
breakpoint_group_features_export Implements hook_features_export().
_breakpoints_breakpoint_load_all_by_type Load all breakpoints by source type.
_breakpoints_breakpoint_load_all_callback CTools export 'load all callback' CRUD callback for breakpoints.
_breakpoints_filter_styles array_filter callback.
_breakpoints_sort_by_weight Sort breakpoints by weight.
_breakpoints_sort_by_weight_array Sort breakpoints by weight.

Constants

Namesort descending Description
BREAKPOINTS_GROUP
BREAKPOINTS_SOURCE_TYPE_CUSTOM
BREAKPOINTS_SOURCE_TYPE_MODULE
BREAKPOINTS_SOURCE_TYPE_THEME @file Breakpoints @todo: provide button to reload breakpoints from theme