styleswitcher.module in Style Switcher 6.2
Same filename and directory in other branches
Module's hooks implementations and helper functions.
File
styleswitcher.moduleView source
<?php
/**
* @file
* Module's hooks implementations and helper functions.
*/
/**
* Indicates that the cookie must live 365 days more.
*/
define('STYLESWITCHER_COOKIE_EXPIRE', 31536000);
/**
* Implements hook_block().
*/
function styleswitcher_block($op = 'list', $delta = 0, $edit = array()) {
switch ($op) {
case 'list':
return styleswitcher_block_info();
case 'view':
return styleswitcher_block_view($delta);
}
}
/**
* Returns info about provided blocks and their initial configuration settings.
*
* @return array
* An array of block descriptions.
*
* @see styleswitcher_block()
* @see styleswitcher_block_view()
*/
function styleswitcher_block_info() {
$blocks[0] = array(
'info' => t('Style Switcher'),
// We cannot cache globally, because we use drupal_get_destination() with
// links in block, which is different from page to page. And we cannot avoid
// using destination, because in this case site users with JS-disabled
// browsers won't go back to the same page they were at, but will go to the
// front page each time. We also cannot rely on $_SERVER['HTTP_REFERER'],
// because it can be empty.
'cache' => BLOCK_CACHE_PER_PAGE,
);
return $blocks;
}
/**
* Returns a renderable view of a block.
*
* @param string|int $delta
* Which block to render.
*
* @return array
* An array of block subject and content.
*
* @see styleswitcher_block()
* @see styleswitcher_block_info()
*/
function styleswitcher_block_view($delta) {
global $theme;
switch ($delta) {
// List of styles a user can switch between.
case 0:
$styles = styleswitcher_style_load_multiple($theme, array(
'status' => TRUE,
));
// Do not display block if there is only one style (no alternatives).
if (count($styles) > 1) {
uasort($styles, 'styleswitcher_sort');
$links = array();
$destination = drupal_get_destination();
foreach ($styles as $name => $style) {
$name_hyphenated = strtr($name, '_', '-');
$name_parts = explode('/', $name_hyphenated);
$class = 'style-switcher ' . $name_parts[0] . '-style style-' . $name_parts[1];
$links[] = l($style['label'], 'styleswitcher/switch/' . $theme . '/' . $name_hyphenated, array(
'attributes' => array(
'class' => $class,
'data-rel' => $name,
'rel' => 'nofollow',
),
'query' => $destination,
));
// Make paths absolute for JS.
if (isset($style['path'])) {
$styles[$name]['path'] = _styleswitcher_file_create_url($style['path']);
}
else {
$styles[$name]['path'] = url('styleswitcher/css/' . $theme, array(
'absolute' => TRUE,
));
}
}
$path_to_module = drupal_get_path('module', 'styleswitcher');
$js_settings = array(
'styleSwitcher' => array(
'styles' => $styles,
'default' => styleswitcher_default_style_key($theme),
'enableOverlay' => variable_get('styleswitcher_enable_overlay', 1),
'cookieExpire' => STYLESWITCHER_COOKIE_EXPIRE,
'theme' => $theme,
),
);
drupal_add_css($path_to_module . '/styleswitcher.overlay.css');
drupal_add_js($path_to_module . '/styleswitcher.js');
drupal_add_js($js_settings, 'setting');
$block['subject'] = t('Style Switcher');
$block['content'] = theme('item_list', $links);
return $block;
}
break;
}
}
/**
* Prepares variables for page templates: Adds the dynamic CSS to every page.
*
* Default template: page.tpl.php.
*
* @param array $variables
* An associative array with page variables, including but not limited to:
* - styles: A themed representation of all stylesheets that should be
* attached to the page as returned from drupal_get_css(). This variable is
* created in template_preprocess_page().
*
* @see drupal_get_css()
* @see template_preprocess_page()
*/
function styleswitcher_preprocess_page(array &$variables) {
global $theme;
// Construct absolute URL explicitly to work out disabled clean URLs.
$url = url('styleswitcher/css/' . $theme, array(
'absolute' => TRUE,
));
// Function drupal_get_css() processes only really existing CSS files and not
// dynamic links so it can't be used. Add link tag directly to the end of all
// styles - they are already rendered to corresponding variable.
$variables['styles'] .= '<link type="text/css" rel="stylesheet" media="all" href="' . $url . '" id="styleswitcher-css" />' . "\n";
}
/**
* Implements hook_perm().
*/
function styleswitcher_perm() {
return array(
'administer styleswitcher',
);
}
/**
* Implements hook_menu().
*/
function styleswitcher_menu() {
$items['admin/settings/styleswitcher'] = array(
'title' => 'Styleswitcher',
'description' => 'Configure Styleswitcher module.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'styleswitcher_admin',
),
'access arguments' => array(
'administer styleswitcher',
),
'file' => 'styleswitcher.admin.inc',
);
$items['admin/settings/styleswitcher/global'] = array(
'title' => 'Global settings',
'type' => MENU_DEFAULT_LOCAL_TASK,
'weight' => -1,
);
foreach (list_themes() as $theme) {
$items['admin/settings/styleswitcher/settings/' . $theme->name] = array(
'title' => $theme->info['name'],
'description' => 'Configure theme-specific styles settings.',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'styleswitcher_config_theme',
4,
),
'access callback' => '_styleswitcher_config_theme_access',
'access arguments' => array(
$theme,
),
'type' => MENU_LOCAL_TASK,
'file' => 'styleswitcher.admin.inc',
);
}
$items['admin/settings/styleswitcher/add'] = array(
'title' => 'Add style',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'styleswitcher_style_form',
),
'access arguments' => array(
'administer styleswitcher',
),
'type' => MENU_LOCAL_TASK,
'file' => 'styleswitcher.admin.inc',
);
$items['admin/settings/styleswitcher/custom/%styleswitcher_style'] = array(
'title' => 'Edit',
'title callback' => 'styleswitcher_style_title',
'title arguments' => array(
4,
),
'page callback' => 'drupal_get_form',
'page arguments' => array(
'styleswitcher_style_form',
4,
),
'load arguments' => array(
'',
'custom',
),
'access arguments' => array(
'administer styleswitcher',
),
'file' => 'styleswitcher.admin.inc',
);
$items['admin/settings/styleswitcher/custom/%styleswitcher_style/edit'] = array(
'title' => 'Edit',
'type' => MENU_DEFAULT_LOCAL_TASK,
// D6 needs load arguments here too.
'load arguments' => array(
'',
'custom',
),
);
$items['admin/settings/styleswitcher/custom/%styleswitcher_style/delete'] = array(
'title' => 'Delete',
'page callback' => 'drupal_get_form',
'page arguments' => array(
'styleswitcher_style_delete_form',
4,
),
'load arguments' => array(
'',
'custom',
),
'access arguments' => array(
'administer styleswitcher',
),
'file' => 'styleswitcher.admin.inc',
);
// The theme argument must be set for next routes to know what the page user
// came from and what theme was used there.
$items['styleswitcher/switch/%/%/%styleswitcher_style'] = array(
'title' => 'Styleswitcher',
'page callback' => 'styleswitcher_switch',
'page arguments' => array(
4,
),
'load arguments' => array(
2,
3,
),
'access callback' => '_styleswitcher_theme_access',
'access arguments' => array(
2,
),
'type' => MENU_CALLBACK,
);
$items['styleswitcher/css/%'] = array(
'title' => 'Styleswitcher',
'page callback' => 'styleswitcher_css',
'page arguments' => array(
2,
),
'access callback' => '_styleswitcher_theme_access',
'access arguments' => array(
2,
),
'type' => MENU_CALLBACK,
);
return $items;
}
/**
* Access callback: Allows only for enabled themes.
*
* @param string|object $theme
* Either the name of a theme or a full theme object.
*
* @see styleswitcher_menu()
*/
function _styleswitcher_theme_access($theme) {
if (is_string($theme)) {
$themes = list_themes();
if (!isset($themes[$theme])) {
return FALSE;
}
$theme = $themes[$theme];
}
return $theme->status || $theme->name == variable_get('admin_theme', '0');
}
/**
* Access callback: Allows only admin and only for enabled themes.
*
* @param string|object $theme
* Either the name of a theme or a full theme object.
*
* @see styleswitcher_menu()
*/
function _styleswitcher_config_theme_access($theme) {
return user_access('administer styleswitcher') && _styleswitcher_theme_access($theme);
}
/**
* Page callback: Switches style when JS is disabled.
*
* @param array $style
* New active style. The structure of an array is the same as returned from
* styleswitcher_style_load().
*
* @see styleswitcher_style_load()
* @see styleswitcher_menu()
*/
function styleswitcher_switch(array $style) {
if ($style['status']) {
styleswitcher_save_user_preference($style['theme'], $style['name']);
}
drupal_goto();
}
/**
* Page callback: Redirects to CSS file of currently active style.
*
* @param string $theme
* Name of the theme to find the active style for.
*
* @see styleswitcher_menu()
*/
function styleswitcher_css($theme) {
// Prevent resource incorrect interpretation.
drupal_set_header('Content-Type: text/css');
// Prevent browser caching of the final style and always show the right one.
// This is D6 only, D7 already sets ETag in core.
drupal_set_header('ETag: "' . time() . '"');
$path = styleswitcher_active_style_path($theme);
if (isset($path)) {
drupal_goto(_styleswitcher_file_create_url($path));
}
}
/**
* Loads a style array by its machine name and a theme name.
*
* @param string $name
* Machine name of the style to load.
* @param string $theme
* Machine name of the theme to get the style for.
* @param string $type
* (optional) Style type: 'theme' or 'custom'. If the type is specified then
* it will be prefixed with a slash to the $name argument.
*
* @return array|false
* Style array on success or FALSE otherwise. Style is an associative array
* containing:
* - name: Machine name.
* - label: Human-readable label.
* - path: System or external path to the CSS file.
* - weight: Weight of style link in the switch list.
* - status: Indicates whether the style is enabled or not.
* - is_default: Indicates that this style is the default one. This element
* may not always show the truth. It is recommended to use
* styleswitcher_default_style_key() to get the default style key.
* - _i: Index number of the style. It is used for sorting of styles with
* equal weights.
* - theme: Name of the theme the style is loaded for.
*
* @see styleswitcher_default_style_key()
*/
function styleswitcher_style_load($name, $theme, $type = '') {
if ($type) {
$name = $type . '/' . $name;
// The next conversion is only rationale for auto-loader wildcards in paths
// and there are $type arguments always set in menu items so if this
// function is called with only one argument this conversion is redundant.
$name = strtr($name, '-', '_');
}
$styles = styleswitcher_style_load_multiple($theme, array(
'name' => $name,
));
return reset($styles);
}
/**
* Returns style's label.
*
* This function is assigned as a title callback in styleswitcher_menu().
*
* @param array $style
* Style array as returned from styleswitcher_style_load().
*
* @return string
* Label of the style.
*
* @see styleswitcher_style_load()
*/
function styleswitcher_style_title(array $style) {
return $style['label'];
}
/**
* Returns a list of styles.
*
* @param string $theme
* Name of the theme to get styles for.
* @param array $filter
* Style properties to filter by. Each key is a property name, and value is
* a corresponding filter value.
*
* @return array
* Array of styles - all or just filtered by conditions from the $filter
* argument. Keys are machine names and each element is a corresponding style
* array, which structure is the same as returned from
* styleswitcher_style_load().
*
* @see styleswitcher_style_load()
*/
function styleswitcher_style_load_multiple($theme, array $filter = array()) {
static $styles = array();
if (!isset($styles[$theme])) {
$theme_styles = styleswitcher_custom_styles() + styleswitcher_theme_styles($theme);
$settings = styleswitcher_styles_settings($theme);
foreach (array_keys($theme_styles) as $i => $key) {
if (isset($settings[$key])) {
$theme_styles[$key] += $settings[$key];
}
// Default settings.
$theme_styles[$key] += array(
'is_default' => FALSE,
'status' => TRUE,
'weight' => 0,
'_i' => $i,
'theme' => $theme,
);
}
$styles[$theme] = $theme_styles;
}
if (empty($filter)) {
return $styles[$theme];
}
$return = array();
foreach ($styles[$theme] as $key => $style) {
// Check the requested conditions.
foreach ($filter as $property => $value) {
if ($style[$property] != $value) {
continue 2;
}
}
$return[$key] = $style;
}
return $return;
}
/**
* Returns a list of styles with theme-specific settings.
*
* @param string $theme
* Name of the theme to get styles settings for.
*
* @return array
* Array which keys are styles machine names and each element is a
* corresponding array with settings: weight, status and is_default. All
* settings are optional. See styleswitcher_style_load() for their
* descriptions.
*
* @see styleswitcher_style_load()
*/
function styleswitcher_styles_settings($theme) {
$settings = variable_get('styleswitcher_styles_settings', array());
if (empty($settings[$theme])) {
$settings[$theme] = array();
styleswitcher_theme_styles($theme);
// Disable the blank style if theme has its own default one.
if (styleswitcher_theme_default_style_key($theme)) {
$settings[$theme]['custom/default']['status'] = FALSE;
}
}
return $settings[$theme];
}
/**
* Returns a list of custom styles.
*
* @return array
* Array which keys are styles machine names and each element is a
* corresponding array with properties: name, label and path. All properties
* are mandatory. See styleswitcher_style_load() for their descriptions.
*
* @see styleswitcher_style_load()
*/
function styleswitcher_custom_styles() {
$defaults['custom/default'] = array(
'name' => 'custom/default',
'label' => 'Default',
'path' => NULL,
);
return variable_get('styleswitcher_custom_styles', $defaults);
}
/**
* Returns a list of styles provided by a theme.
*
* @param string $theme
* Name of the theme to retrieve styles of.
* @param string|null $original_theme
* (optional) Name of the theme which the function was originally called with.
* While iterating over base themes the $theme argument changes but
* $original_theme keeps the same value.
*
* @return array
* Array of styles. Keys are machine names and each element is a corresponding
* array of style properties: name, label and path. All properties are
* mandatory. See styleswitcher_style_load() for their descriptions.
*
* @see styleswitcher_style_load()
*/
function styleswitcher_theme_styles($theme, $original_theme = NULL) {
static $styles = array();
// Theme can be an empty string if custom style is loading.
if (!$theme) {
return array();
}
if (isset($styles[$theme])) {
return $styles[$theme];
}
$theme_styles = array();
$theme_path = drupal_get_path('theme', $theme);
// Do not use system_get_info() because it skips disabled base themes.
$themes = list_themes();
$theme_info = $themes[$theme]->info;
if (!isset($original_theme)) {
$original_theme = $theme;
}
// Search base themes for styleswitcher info.
if (isset($theme_info['base theme'])) {
$theme_styles = styleswitcher_theme_styles($theme_info['base theme'], $original_theme);
}
if (!empty($theme_info['styleswitcher'])) {
$info = $theme_info['styleswitcher'];
// Array of alternatives.
if (!empty($info['css'])) {
foreach ($info['css'] as $label => $path) {
$name = 'theme/' . _styleswitcher_style_name($label);
$theme_styles[$name] = array(
'name' => $name,
'label' => $label,
'path' => menu_path_is_external($path) ? $path : $theme_path . '/' . $path,
);
}
}
// Default style.
if (isset($info['default'])) {
$default = $info['default'];
}
elseif (isset($info['css']['default'])) {
$default = $info['css']['default'];
unset($theme_styles['theme/default']);
}
if (isset($default)) {
$default_in_existing = FALSE;
// Check if Default points to one of existing alternatives.
foreach ($theme_styles as $name => $style) {
if ($default == $style['label'] || $default == $style['path'] || $theme_path . '/' . $default == $style['path']) {
styleswitcher_theme_default_style_key($original_theme, $name);
$default_in_existing = TRUE;
break;
}
}
// Default is a path not mentioned in css array.
if (!$default_in_existing) {
$defaults['theme/default'] = array(
'name' => 'theme/default',
'label' => 'Default',
'path' => menu_path_is_external($default) ? $default : $theme_path . '/' . $default,
);
// Place default style above others.
$theme_styles = $defaults + $theme_styles;
styleswitcher_theme_default_style_key($original_theme, 'theme/default');
}
}
}
// Do not inflate the memory.
if ($theme == $original_theme) {
$styles[$theme] = $theme_styles;
}
return $theme_styles;
}
/**
* Transliterates a human-readable name to a machine name.
*
* @param string $display_name
* Style label.
*
* @return string
* Transliterated name.
*/
function _styleswitcher_style_name($display_name) {
$name = drupal_strtolower($display_name);
$name = strtr($name, array(
' ' => '_',
'-' => '_',
));
$name = preg_replace('/[^a-z0-9_]/', '', $name);
return $name;
}
/**
* Saves/returns the key of default style provided by a theme.
*
* When theme's .info file is scanned for styles to switch this function is
* called with argument to statically save a style key for further use. And
* after, when this function is called it returns the key saved earlier.
*
* @param string $theme
* Name of the theme which default style is being saved/requested.
* @param string|null $key
* The key of theme's default style.
*
* @return string|null
* The key of theme's default style.
*/
function styleswitcher_theme_default_style_key($theme, $key = NULL) {
static $default_key = array();
if (isset($key)) {
$default_key[$theme] = $key;
}
return isset($default_key[$theme]) ? $default_key[$theme] : NULL;
}
/**
* Finds the default style and returns its key.
*
* @param string $theme
* Name of the theme to find the default style for.
*
* @return string
* The key of the default style.
*/
function styleswitcher_default_style_key($theme) {
static $default_key = array();
// Search the default style explicitly set by admin.
if (!isset($default_key[$theme])) {
$styles = styleswitcher_style_load_multiple($theme, array(
'is_default' => TRUE,
));
$default_key[$theme] = key($styles);
}
// Plan B. If default style is not set in styles configuration form by admin
// then find out initial default style defined by theme.
if (!isset($default_key[$theme])) {
styleswitcher_theme_styles($theme);
$default_key[$theme] = styleswitcher_theme_default_style_key($theme);
}
// Fallback to the blank style.
if (!isset($default_key[$theme])) {
$styles = styleswitcher_style_load_multiple($theme, array(
'path' => NULL,
));
$default_key[$theme] = key($styles);
}
return $default_key[$theme];
}
/**
* Finds the style active for current user and returns its path.
*
* This function is called at every page request before styleswitcher_switch()
* or JS' Drupal.styleSwitcher.switchStyle() so we can update old user cookies
* here once and not bother about it in other places.
*
* @param string $theme
* Name of the theme to find the active style for.
*
* @return string|null
* The path property of active style. It can be NULL if active style is the
* blank one.
*
* @see styleswitcher_switch()
* @see Drupal.styleSwitcher.switchStyle()
*/
function styleswitcher_active_style_path($theme) {
if (isset($_COOKIE['styleswitcher'])) {
$cookie = $_COOKIE['styleswitcher'];
if (isset($cookie[$theme])) {
$active = styleswitcher_style_load($cookie[$theme], $theme);
}
}
elseif (isset($_COOKIE['styleSwitcher'])) {
$name = 'theme/' . _styleswitcher_style_name($_COOKIE['styleSwitcher']);
// Remove this old cookie.
setcookie('styleSwitcher', '', 0, base_path());
// We actually do not know what theme was used (it was a global $theme) when
// user switched to this style. So let us just set this style as active for
// every theme which has a style with this name.
foreach (array_keys(list_themes()) as $style_theme) {
if ($style = styleswitcher_style_load($name, $style_theme)) {
styleswitcher_save_user_preference($style_theme, $name);
if ($theme == $style_theme) {
$active = $style;
}
}
}
}
if (empty($active)) {
$active = styleswitcher_style_load(styleswitcher_default_style_key($theme), $theme);
}
return $active['path'];
}
/**
* Implements hook_theme().
*/
function styleswitcher_theme() {
return array(
'styleswitcher_admin_styles_table' => array(
'arguments' => array(
'form' => array(),
),
'file' => 'styleswitcher.admin.inc',
),
'styleswitcher_admin_style_overview' => array(
'arguments' => array(
'style' => array(),
),
'file' => 'styleswitcher.admin.inc',
),
);
}
/**
* Sorts styles by weight and index.
*
* This function first compares style weights, and then - if weights are equal -
* style index numbers.
*
* The compared items (function parameters) should be associative arrays that
* include a 'weight' and an '_i' elements.
*
* Callback for uasort() within styleswitcher_block_view() and
* styleswitcher_admin().
*
* @see styleswitcher_admin()
* @see styleswitcher_block_view()
*/
function styleswitcher_sort(array $a, array $b) {
$property = $a['weight'] != $b['weight'] ? 'weight' : '_i';
return $a[$property] - $b[$property];
}
/**
* Saves the style key to the cookie.
*
* @param string $theme_key
* Name of the theme to save the style for.
* @param string $style_key
* Style key to save.
*/
function styleswitcher_save_user_preference($theme_key, $style_key) {
setcookie('styleswitcher[' . $theme_key . ']', $style_key, time() + STYLESWITCHER_COOKIE_EXPIRE, base_path());
}
/**
* Creates a web-accessible URL for a "shipped" file.
*
* This function imitates D7's file_create_url() because D6's one does not work
* with files, which ship as part of modules or themes. Also this is needed to
* avoid breaking path in url() when clean urls are turned off.
*
* @param string $path
* The path to a shipped file or an external URL.
*
* @return string
* A string containing a URL that may be used to access the file. If the
* provided string is already an external path, nothing is done and the same
* string is returned.
*/
function _styleswitcher_file_create_url($path) {
if (!menu_path_is_external($path)) {
$path = $GLOBALS['base_url'] . '/' . drupal_urlencode($path);
}
return $path;
}
Functions
Name | Description |
---|---|
styleswitcher_active_style_path | Finds the style active for current user and returns its path. |
styleswitcher_block | Implements hook_block(). |
styleswitcher_block_info | Returns info about provided blocks and their initial configuration settings. |
styleswitcher_block_view | Returns a renderable view of a block. |
styleswitcher_css | Page callback: Redirects to CSS file of currently active style. |
styleswitcher_custom_styles | Returns a list of custom styles. |
styleswitcher_default_style_key | Finds the default style and returns its key. |
styleswitcher_menu | Implements hook_menu(). |
styleswitcher_perm | Implements hook_perm(). |
styleswitcher_preprocess_page | Prepares variables for page templates: Adds the dynamic CSS to every page. |
styleswitcher_save_user_preference | Saves the style key to the cookie. |
styleswitcher_sort | Sorts styles by weight and index. |
styleswitcher_styles_settings | Returns a list of styles with theme-specific settings. |
styleswitcher_style_load | Loads a style array by its machine name and a theme name. |
styleswitcher_style_load_multiple | Returns a list of styles. |
styleswitcher_style_title | Returns style's label. |
styleswitcher_switch | Page callback: Switches style when JS is disabled. |
styleswitcher_theme | Implements hook_theme(). |
styleswitcher_theme_default_style_key | Saves/returns the key of default style provided by a theme. |
styleswitcher_theme_styles | Returns a list of styles provided by a theme. |
_styleswitcher_config_theme_access | Access callback: Allows only admin and only for enabled themes. |
_styleswitcher_file_create_url | Creates a web-accessible URL for a "shipped" file. |
_styleswitcher_style_name | Transliterates a human-readable name to a machine name. |
_styleswitcher_theme_access | Access callback: Allows only for enabled themes. |
Constants
Name | Description |
---|---|
STYLESWITCHER_COOKIE_EXPIRE | Indicates that the cookie must live 365 days more. |