You are here

block_class_styles.module in Block Class Styles 7.2

Same filename and directory in other branches
  1. 7 block_class_styles.module

Base module file for block_class_styles

block_class_styles Block Class Presets

File

block_class_styles.module
View source
<?php

/**
 * @file
 * Base module file for block_class_styles
 *
 * @defgroup block_class_styles Block Class Presets
 * @{
 */

/**
 * @var BLOCK_CLASS_STYLES_PATH_SETTINGS
 *
 * Path to the settings page
 */
define('BLOCK_CLASS_STYLES_PATH_SETTINGS', 'admin/structure/block/styles');

/**
 * @var BLOCK_CLASS_STYLES_ENTITY_SETTING_URL
 *
 * This is the path that will be used to toggle a bundle's support
 */
define('BLOCK_CLASS_STYLES_ENTITY_SETTING_URL', 'block-class-styles/setting');

/**
 * @var BLOCK_CLASS_STYLES_TITLE_FORMAT
 *
 * Default format for titles, leave NULL to use drupal core sanitization
 */
define('BLOCK_CLASS_STYLES_TITLE_FORMAT', NULL);

/**
 * @var BLOCK_CLASS_STYLES_HIDE_CLASSES
 *
 * Default value for hiding the block_class textfield
 */
define('BLOCK_CLASS_STYLES_HIDE_CLASSES', TRUE);

/**
 * @var BLOCK_CLASS_STYLES_FS_TITLE
 *
 * Default fieldset title
 */
define('BLOCK_CLASS_STYLES_FS_TITLE', 'Theme/Style');

/**
 * @var BLOCK_CLASS_STYLES_FS_DESCRIPTION
 *
 * Default fieldset description
 */
define('BLOCK_CLASS_STYLES_FS_DESCRIPTION', 'Control the appearance of this block by choosing a style for it.');

/**
 * @var BLOCK_CLASS_STYLES_DESCRIPTION
 *
 * The default description that appears under the select element
 */
define('BLOCK_CLASS_STYLES_DESCRIPTION', '');

/**
 * @var BLOCK_CLASS_STYLES_TITLE
 *
 * The default select title
 */
define('BLOCK_CLASS_STYLES_TITLE', 'Block Style');

/**
 * @var BLOCK_CLASS_STYLES_ALLOW_MULTIPLE
 *
 * True/False Should we allow more than one class?
 */
define('BLOCK_CLASS_STYLES_ALLOW_MULTIPLE', FALSE);

/**
 * Implements hook_help().
 *
 * http://api.drupal.org/api/function/hook_help
 *
 * @param string $path
 *   The router menu path, as defined in hook_menu(), for the help that is
 *   being requested; e.g., 'admin/node' or 'user/edit'. If the router path
 *   includes a % wildcard, then this will appear in $path; for example, node
 *   pages would have $path equal to 'node/%' or 'node/%/view'. Your hook
 *   implementation may also be called with special descriptors after a "#"
 *   sign.
 * @param array  $arg
 *   An array that corresponds to the return value of the arg() function, for
 *   modules that want to provide help that is specific to certain values of
 *   wildcards in $path. For example, you could provide help for the path
 *   'user/1' by looking for the path 'user/%' and $arg[1] == '1'. This array
 *   should always be used rather than directly invoking arg(), because your
 *   hook implementation may be called for other purposes besides building the
 *   current page's help. Note that depending on which module is invoking
 *   hook_help, $arg may contain only empty strings. Regardless, $arg[0] to
 *   $arg[11] will always be set.
 */
function block_class_styles_help($path, $arg) {
  $output = '';
  if ($path === BLOCK_CLASS_STYLES_PATH_SETTINGS) {
    $output .= <<<EOD
<p>Use this page to edit the block styles.</p>
<p>When you edit the css for a style definition and save this form, all blocks with that style will receive the new css. <strong>When editing <em>Style definitions</em> you may change the style name <em>OR</em> the css for the style, per form submission.  To change both css and style name of a single Style definition, you need to do the css first, save the form, then do the style name and save the form.</strong></p>
<p>Each style generates a <a href="http://drupal.org/node/1089656" onclick="window.open(this.href); return false;">theme hook suggestion</a>, so you can override <code>block.tpl.php</code> for each style with the appropriate tpl file.  See <em>Template suggestions list</em> for the template filenames that correspond to each style. This list will only appear after you have created one or more styles and saved this form.</p>
<p>Other things to note:</p>
<ul>
  <li>The list of style definitions is defined by all the block classes/styles that have been previously assigned to blocks as well as any definitions made here that have not yet been assigned.</li>
  <li>The only way to make all <em>Style definitions</em> disappear (from the box below) is to remove all classes/styles from each and every block.</li>
  <li>However, you may hide a style from appearing in the styles list on block edit forms by unchecking it from the select list options below.</li>
  <li><strong>Unchecking a style from the select list options does not affect a block with that style assigned to it.</strong>  To affect the block you need to edit the block itself and unassign the style.</li>
  <li>An unchecked style will still appear on a block's edit form if it has been selected for that block. The style name will be appended with "***" to designate it's been hidden.</li>
</ul>
EOD;
  }
  return $output;
}

/**
 * Implements hook_permission().
 */
function block_class_styles_permission() {
  return array(
    'administer block_class_styles' => array(
      'title' => t('Administer Block Styles'),
      'description' => t('Define styles and other settings for the module.'),
      'restrict access' => TRUE,
    ),
    'block_class_styles:use' => array(
      'title' => t('Use Block Styles'),
      'description' => t("See/change a given block's style when editing it."),
    ),
  );
}

/**
 * Implements hook_menu().
 */
function block_class_styles_menu() {
  $items = array();
  $items[BLOCK_CLASS_STYLES_PATH_SETTINGS] = array(
    'title' => 'Block styles',
    'description' => 'Define preset classes and styles.',
    'page callback' => 'drupal_get_form',
    'page arguments' => array(
      'block_class_styles_admin_settings',
    ),
    'file' => 'block_class_styles.admin.inc',
    'access arguments' => array(
      'administer block_class_styles',
    ),
    'type' => MENU_LOCAL_TASK,
    'weight' => 50,
  );
  $items[BLOCK_CLASS_STYLES_ENTITY_SETTING_URL] = array(
    'title' => 'Update setting',
    'page callback' => '_block_class_styles_update_entity_setting',
    'access arguments' => array(
      'administer block_class_styles',
    ),
    'type' => MENU_CALLBACK,
    'file' => 'block_class_styles.admin.inc',
  );
  return $items;
}

/**
 * Returns an array of css classes for a given style name.
 *
 * @param $style  The human readable declaration of a style.
 *
 * @return null|array
 */
function block_class_styles_get_css_by_style($style) {
  $info = block_class_styles_info();
  $classes = array_search($style, $info);
  return empty($classes) ? NULL : explode(' ', $classes);
}

/**
 * Return an array of style presets
 *
 * @param  boolean $include_hidden Include hiden styles
 *
 * @return array               Keys are classes, values are styles
 */
function block_class_styles_info($include_hidden = FALSE) {
  static $drupal_static_fast;
  if (!isset($drupal_static_fast)) {
    $drupal_static_fast['presets'] =& drupal_static(__FUNCTION__, NULL);
  }
  $presets =& $drupal_static_fast['presets'];
  if (!isset($presets)) {
    $presets = array();

    // Load distinct classes and groupings of classes from blocks table; this
    // makes sure that we have a style for every class or class group that is
    // currently assigned to a block.
    $classes = db_select(_block_class_tablename(), 'b')
      ->fields('b', array(
      'css_class',
    ))
      ->condition('css_class', '', '!=')
      ->distinct()
      ->execute()
      ->fetchCol();
    foreach ($classes as $class) {
      $presets[$class] = ucwords(preg_replace('/[_-]/', ' ', $class));
    }

    // Now match to our presets if possible; this will overwrite the automatic
    // naming convention from above and add any styles that have been defined
    // but not yet assigned.
    $presets = variable_get('block_class_styles_presets', array()) + $presets;

    // Remove any hidden styles if asked.
    $hidden = variable_get('block_class_styles_hidden', array());
    if (!$include_hidden) {
      $presets = array_diff_key($presets, $hidden);
    }

    // Let other modules alter this list
    drupal_alter('block_class_styles_info', $presets);
    $presets = (array) $presets;
  }
  return $presets;
}

/**
 * Implements hook_flush_caches().
 *
 * Scans theme info files for presets and modifies our variable
 */
function block_class_styles_flush_caches() {
  $presets = variable_get('block_class_styles_presets', array());

  // Scan the theme info files
  $include_from_themes = array();
  $info = array();
  foreach (list_themes() as $name => $data) {

    // Check for the parent themes because we'll need to include that info
    if ($data->status && isset($data->base_themes)) {
      $include_from_themes += $data->base_themes;
    }
    if (isset($data->info['block_class_styles'])) {
      $include_from_themes[$name] = $data->info['name'];
      $info[$name] = $data->info['block_class_styles'];
    }
  }
  $info = array_intersect_key($info, $include_from_themes);
  foreach ($info as $array) {
    $presets = array_merge($presets, $array);
  }
  variable_set('block_class_styles_presets', $presets);
}

/**
 * Return a style by it's css
 *
 * @param string $css
 *
 * @return string or FALSE
 */
function block_class_styles_get_style($css) {
  $presets = block_class_styles_info();
  return $css && array_key_exists($css, $presets) ? $presets[$css] : FALSE;
}

/**
 * Return the name of the table to use based on module version
 *
 * @return string The name of the table.
 */
function _block_class_tablename() {
  return db_field_exists('block', 'css_class') ? 'block' : 'block_class';
}

/**
 * Implements hook_form_alter().
 */
function block_class_styles_form_alter(&$form, $form_state, $form_id) {
  $stored_css_class = '';
  if ($form_id === 'bean_form') {
    $bean = $form['#entity'];
    $pform = $form;
    $pform['module'] = array(
      '#value' => 'bean',
    );
    $pform['delta'] = array(
      '#value' => $bean->delta,
    );
    $pform_id = 'block_admin_configure';
    block_class_form_alter($pform, $form_state, $pform_id);
    $stored_css_class = $pform['settings']['css_class']['#default_value'];
  }
  if (in_array($form_id, array(
    'block_admin_configure',
    'block_add_block_form',
  ))) {

    ////    $block->module = $form['module']['#value'];

    ////    $block->delta = $form['delta']['#value'];
    if (!empty($form['settings']['css_class']['#default_value'])) {
      $stored_css_class = $form['settings']['css_class']['#default_value'];
    }
  }

  //
  //
  // Generate the form element to be shared in different forms.
  if (in_array($form_id, array(
    'block_admin_configure',
    'block_add_block_form',
    'bean_form',
  ))) {
    $multiple = FALSE;

    //@todo See admin.inc for explanation

    //$multiple = current(variable_get('block_class_styles_allow_multiple', BLOCK_CLASS_STYLES_ALLOW_MULTIPLE));
    $options = block_class_styles_info();
    $default = array(
      $stored_css_class,
    );

    // If the default is hidden we need to grab it
    if ($stored_css_class && !array_key_exists($stored_css_class, $options)) {

      //      $default_is_hidden = TRUE;
      $hidden = block_class_styles_info(TRUE);
      $options += array_intersect_key($hidden, array_flip($default));
      $options[$stored_css_class] .= ' ***';
    }
    if (!$multiple) {
      $options = array(
        NULL => t('-None-'),
      ) + $options;
      $default = $stored_css_class;
    }
    $element = array(
      '#type' => 'fieldset',
      '#title' => variable_get('block_class_styles_fs_title', BLOCK_CLASS_STYLES_FS_TITLE),
      '#description' => variable_get('block_class_styles_fs_description', BLOCK_CLASS_STYLES_FS_DESCRIPTION),
      '#collapsible' => TRUE,
      '#collapsed' => !variable_get('block_class_styles_form_collapsed', FALSE),
    );
    $element['css_class'] = array(
      '#type' => $multiple ? 'checkboxes' : 'select',
      '#title' => variable_get('block_class_styles_title', BLOCK_CLASS_STYLES_TITLE),
      '#options' => $options,
      '#default_value' => $default,
      '#description' => variable_get('block_class_styles_description', BLOCK_CLASS_STYLES_DESCRIPTION),
      '#maxlength' => 255,
    );
    $element['admin'] = array(
      '#markup' => t('To edit styles <a href="!url">click here</a>.', array(
        '!url' => url(BLOCK_CLASS_STYLES_PATH_SETTINGS, array(
          'query' => drupal_get_destination(),
        )),
      )),
      '#access' => user_access('administer block_class_styles'),
    );
  }

  //
  //
  // Support for normal blocks
  if (in_array($form_id, array(
    'block_admin_configure',
    'block_add_block_form',
  ))) {
    $form['block_class']['#access'] = user_access('block_class_styles:use');
    $form['block_class']['#title'] = variable_get('block_class_styles_fs_title', BLOCK_CLASS_STYLES_FS_TITLE);
    $form['block_class']['#description'] = variable_get('block_class_styles_fs_description', BLOCK_CLASS_STYLES_FS_DESCRIPTION);
    $element['#access'] = $form['block_class']['#access'];
    $element['#weight'] = variable_get('block_class_styles_form_weight', 0);
    $form['block_class_styles'] = $element;

    // This field needs to be hidden because we show it in our own way in our
    // fieldset, and... we can't set #access to FALSE because our variable name
    // is the same, so we have turn it into a non-displaying type = 'value'
    $form['settings']['css_class']['#type'] = 'value';
  }
  elseif ($form_id === 'bean_form') {
    $form['block_class_styles_css_class'] = $element;
    $form['#submit'][] = '_block_class_styles_form_submit';
  }
}

/**
 * Form submission handler
 */
function _block_class_styles_form_submit($form, &$form_state) {

  // We create a pseudo form situation and leverage block_class submitter.
  $pform = $form;
  $pform['settings']['css_class']['#default_value'] = $form['block_class_styles_css_class']['css_class']['#default_value'];
  $pform_state = $form_state;
  $pform_state['values']['form_id'] = 'block_admin_configure';
  $pform_state['values']['module'] = 'bean';
  $pform_state['values']['delta'] = $form_state['values']['bean']->delta;
  block_class_form_submit($pform, $pform_state);
}

/**
 * Implements hook_block_view().
 */
function block_class_styles_block_view_alter(&$data, $block) {
  if (empty($block->css_class)) {
    return;
  }
  $name = preg_replace('/[ -]/', '_', strtolower($block->css_class));
  $name = preg_replace('/[^a-z0-1_]/', '', $name);
  $data['block_class_styles'] = (object) array(
    'name' => $name,
    'css' => drupal_html_class($name),
    'title' => block_class_styles_get_style($block->css_class),
    'classes_array' => array(
      explode(' ', $block->css_class),
    ),
  );
}

/**
 * Implements hook_preprocess_block().
 *
 * @param &$vars
 *
 * @return NULL
 */
function block_class_styles_preprocess_block(&$vars) {
  if (isset($vars['block']->css_class) && ($css = $vars['block']->css_class) && ($style = block_class_styles_get_style($css)) && ($suggestions = _block_class_styles_theme_hook_suggestion($style))) {
    if ($insert_after = array_search('block__block', $vars['theme_hook_suggestions'])) {
      array_splice($vars['theme_hook_suggestions'], $insert_after + 1, 0, $suggestions);
    }
    else {
      $vars['theme_hook_suggestions'] = array_merge($vars['theme_hook_suggestions'], $suggestions);
    }
  }
  if ($vars['block']->title && $vars['block']->title != '<none>' && ($format = variable_get('block_class_styles_title_format', BLOCK_CLASS_STYLES_TITLE_FORMAT))) {
    $vars['block']->subject = check_markup($vars['block']->title, $format);

    // Now strip the outermost <p> which could show up from check_markup
    preg_match('/^\\s*<p>(.*)<\\/p>\\s*$/is', $vars['block']->subject, $found);
    $vars['block']->subject = isset($found[1]) ? $found[1] : $vars['block']->subject;
  }
}

/**
 * Return the theme_hook_suggestion for a style
 *
 * @param string $style
 *
 * @return string
 */
function _block_class_styles_theme_hook_suggestion($style) {
  static $drupal_static_fast;
  if (!isset($drupal_static_fast)) {
    $drupal_static_fast['hooks'] =& drupal_static(__FUNCTION__, NULL);
  }
  $hooks =& $drupal_static_fast['hooks'];
  if (!isset($hooks[$style])) {
    $suggestions = array();
    $suggestions[] = 'block__' . strtolower(str_replace('-', '_', drupal_clean_css_identifier($style)));
    if ($classes = block_class_styles_get_css_by_style($style)) {
      do {
        $hook = implode('__', $classes);
        $suggestions[] = 'block__' . strtolower(str_replace('-', '_', drupal_html_class($hook)));
      } while (array_pop($classes) && $classes);
    }
    $hooks[$style] = array_unique($suggestions);
  }
  return $hooks[$style];
}

//function block_class_menu_contextual_links_alter(&$links, $router_item, $root_path) {

//  if ($root_path === 'admin/structure/block/manage/%/%') {
//    $presets = block_class_styles_info();
//    foreach ($presets as $key => $preset) {
//      $links[] = array(
//        'title' => check_plain($preset),
//        'href' => "block_class_styles/$key",
//        'localized_options' => array(
//          'query' => drupal_get_destination() + array(
//            'token' => drupal_get_token('block_class'),
//          ),
//        ),
//      );
//    }
//  }
//
//  $links = $links;

//}

/**
 * Implements hook_field_extra_fields().
 */
function block_class_styles_field_extra_fields() {
  if (module_exists('bean') && ($bundles = _block_class_styles_bean_bundles())) {
    foreach ($bundles as $bundle_type) {
      $extra['bean'][$bundle_type]['form'] = array(
        'block_class_styles_css_class' => array(
          'weight' => 0,
          'label' => variable_get('block_class_styles_title', BLOCK_CLASS_STYLES_TITLE),
          'description' => variable_get('block_class_styles_description', BLOCK_CLASS_STYLES_DESCRIPTION),
          'edit' => l('edit', BLOCK_CLASS_STYLES_PATH_SETTINGS, array(
            'query' => drupal_get_destination(),
          )),
          'delete' => l('delete', BLOCK_CLASS_STYLES_ENTITY_SETTING_URL . "/bean/{$bundle_type}/0", array(
            'query' => drupal_get_destination(),
          )),
        ),
      );
    }
  }
  return $extra;
}

/**
 * @return array Values are the bundle types that should include styles.
 */
function _block_class_styles_bean_bundles() {
  $bundles = variable_get('block_class_styles_beans', NULL);
  if (is_null($bundles)) {
    $info = entity_get_info('bean');
    $bundles = array_keys($info['bundles']);
  }
  return $bundles;
}

Functions

Namesort descending Description
block_class_styles_block_view_alter Implements hook_block_view().
block_class_styles_field_extra_fields Implements hook_field_extra_fields().
block_class_styles_flush_caches Implements hook_flush_caches().
block_class_styles_form_alter Implements hook_form_alter().
block_class_styles_get_css_by_style Returns an array of css classes for a given style name.
block_class_styles_get_style Return a style by it's css
block_class_styles_help Implements hook_help().
block_class_styles_info Return an array of style presets
block_class_styles_menu Implements hook_menu().
block_class_styles_permission Implements hook_permission().
block_class_styles_preprocess_block Implements hook_preprocess_block().
_block_class_styles_bean_bundles
_block_class_styles_form_submit Form submission handler
_block_class_styles_theme_hook_suggestion Return the theme_hook_suggestion for a style
_block_class_tablename Return the name of the table to use based on module version

Constants

Namesort descending Description
BLOCK_CLASS_STYLES_ALLOW_MULTIPLE True/False Should we allow more than one class?
BLOCK_CLASS_STYLES_DESCRIPTION The default description that appears under the select element
BLOCK_CLASS_STYLES_ENTITY_SETTING_URL This is the path that will be used to toggle a bundle's support
BLOCK_CLASS_STYLES_FS_DESCRIPTION Default fieldset description
BLOCK_CLASS_STYLES_FS_TITLE Default fieldset title
BLOCK_CLASS_STYLES_HIDE_CLASSES Default value for hiding the block_class textfield
BLOCK_CLASS_STYLES_PATH_SETTINGS Path to the settings page
BLOCK_CLASS_STYLES_TITLE The default select title
BLOCK_CLASS_STYLES_TITLE_FORMAT Default format for titles, leave NULL to use drupal core sanitization