bootstrap_theme_toggler-2.0.0/src/Plugin/Block/themeToggler.php
src/Plugin/Block/themeToggler.php
<?php
namespace Drupal\bootstrap_theme_toggler\Plugin\Block;
use Drupal\Core\Block\BlockBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Render\Markup;
/**
* Provides a 'Theme Toggler' Block.
*
* @Block(
* id = "theme_toggler",
* admin_label = @Translation("Theme Toggler"),
* category = @Translation("Theme Toggler Block"),
* )
*
* When place, the machine name of the block instance will be enforced to be
* the default name provided by Drupal, which should be the Block 'id' above,
* without the underscore, 'themetoggler', prefixed by the default theme name
* resulting in a machine name of 'loaded_default_theme_themetoggler'.
* This is used to enforce only 1 instance of this block is placed on the site.
*/
class ThemeToggler extends BlockBase {
/**
* {@inheritdoc}
*/
public function build() {
$config = $this->configuration;
if (!$config['custom_only']) {
// array of default bootstrap theme modes, use all or none.
$bm = array("auto"=>"auto", "light"=>"light", "dark"=>"dark");
} else {
$bm = array();
}
// Need to gaurd against null, color modes, may not exist.
if (!empty($config['color_modes'])) {
if (!empty($bm)) {
$themeModes = array_merge($bm, $config['color_modes']);
} else {
$themeModes = $config['color_modes'];
}
} else {
$themeModes = $bm;
}
return [
'#theme' => 'block__toggler',
'#attached' => [
'library' => ['bootstrap_theme_toggler/theme-toggler'],
],
'#toggler_label' => $config['toggler_label'],
'#show_toggler_label' => $config['show_toggler_label'],
'#show_option_labels' => $config['show_option_labels'],
'#show_icons' => $config['show_icons'],
'#show_checkmark' => $config['show_checkmark'],
'#theme_modes' => $themeModes,
// '#custom_only' => $config['custom_only'],
];
} // END of build()
/**
* Returns generic default configuration for block plugins.
*
* @return array
* An associative array with the default configuration.
*/
protected function baseConfigurationDefaults() {
return [
'label' => 'Bootstrap Theme Toggler',
'label_display' => 0,
'provider' => $this->pluginDefinition['provider'],
// '#default_value' => false,
// '#return_value' => false,
];
}
/**
* {@inheritdoc}
*/
public function blockForm($form, FormStateInterface $form_state) {
$config = $this->configuration;
// Message template to add a close button to drupal messenger messages.
// The close button requires javascript `js/messenger-close.js`
$message_html = '
<div style="display: flex; flex-direction: row; align-items: center">
<div id="messenger-close" style="width:2em; text-align: center">
<button style="background-color:yellow; border:0; border-radius:1em; cursor:pointer" >
X
</button>
</div>
<div style="align-self: stretch; background-color: blue; width:5px">
</div>
<div style="margin:10px">
message
</div>
</div>
';
$form['toggler_label'] = [
'#type' => 'textfield',
'#title' => $this->t('Toggler Label'),
'#description' => $this->t('Text to display on the toggler dropdown button.'),
'#default_value' => $config['toggler_label'] ?? 'Theme',
];
$form['show_toggler_label'] = [
'#type' => 'checkbox',
'#title' => $this->t('Show toggler label'),
// '#description' => $this->t('Check to make button label visible, on Toggler.'),
'#default_value' => $config['show_toggler_label'] ?? true,
];
$form['show_option_labels'] = [
'#type' => 'checkbox',
'#title' => $this->t('Show theme mode option labels in dropdown list.'),
// '#description' => $this->t('Check to make drop-down option labels visible, on Toggler.'),
'#default_value' => $config['show_option_labels'] ?? true,
];
$form['show_icons'] = [
'#type' => 'checkbox',
'#title' => $this->t('Show toggler color mode icons'),
'#description' => $this->t("To change icons being displayed, edit/replace the appropriate svg with the name of the theme mode to update. The svg element inside must be defined by a <sybmol> element, with an id matching the theme name. The filename should be the theme name prefixed by 'icon_'. <br>A replacement icon for the 'light' theme mode should have the tag, <code><xmp><symbol id='light'><path>...</path></symbol></xmp></code>and have the filename and location of <b>`bootstrap_theme_toggler/svg/icon_light.svg`</b>."),
'#default_value' => $config['show_icons'] ?? true,
];
$form['show_checkmark'] = [
'#type' => 'checkbox',
'#title' => $this->t('Show a checkmark next to active theme'),
// '#description' => $this->t('Check to show a checkmark next to active theme.'),
'#default_value' => $config['show_checkmark'] ?? true,
];
// Get the the loaded 'default' theme, not the 'active' theme.
$themeRoot = \Drupal::config('system.theme')->getOriginal('default');
// To use custom color modes a theme must be compatible.
// By default only Bootstrap Bario SASS themes are assumed compatible.
// Existence of `gulpfile.js` is taken as indication of Barrio SASS theme.
$themeGulpfileExists = file_exists(\Drupal::service('extension.list.theme')->getPath($themeRoot).'/gulpfile.js');
// Get the global Bootstrap Theme Toggler settings
$globalConfig = \Drupal::service('config.factory')->getEditable('bootstrap_theme_toggler.settings');
// A theme can also be manually indicatad as compatible with color modes
// by checking the `add custom color modes` global configuration setting.
// Only load and show custom color modes if theme is indicated compatible.
if ($themeGulpfileExists || $globalConfig->get('add_custom_color_modes')) {
// Check if alternate color mode path has been set in global config.
$colorModeDefs = $globalConfig->get('color_mode_sass_directory');
if ($colorModeDefs) {
// Notify the user that a custom color mode path has been set.
$messageText = 'The default custom color mode folder has been changed to: <b>'.
$colorModeDefs .'</b><br>To reset to default, or edit, go to <a href="'.
\Drupal::request()->getSchemeAndHttpHost().
'/admin/config/bootstrap-theme-toggler">Bootstrap Theme Toggler Global config</a>.';
$message = [
'#type' => 'markup',
'#attached' => [
'library' => array('bootstrap_theme_toggler/messenger-close'),
],
'#markup' => Markup::create(str_replace('message', $messageText, $message_html)),
];
\Drupal::messenger()->addMessage($message, 'toggler');
} else {
// If alternate path has not been set, use module's scss folder.
$colorModeDefs = \Drupal::service('extension.list.module')->getPath('bootstrap_theme_toggler').'/scss/';
}
$prefix = '_';
$result = array();
$defaultValues = array();
// Look for color mode scss files, indicated by a leading '_',
// inside specified custom color modes folder.
$handle = @opendir($colorModeDefs);
if (!empty($handle)) {
while ($entry = @readdir($handle)) {
// If item is a file and has matching prefix, process as a theme mode.
if(is_file($colorModeDefs.$entry) && (mb_substr($entry, 0, 1) == $prefix)) {
$result[str_replace($prefix, '', pathinfo($entry, PATHINFO_FILENAME))] = str_replace($prefix, '', pathinfo($entry, PATHINFO_FILENAME));
// Building array of values only, for use in setting default_value.
$defaultValues[] = str_replace($prefix, '', pathinfo($entry, PATHINFO_FILENAME));
}
}
closedir($handle);
}
} // END of if SASS custom color mode exist
// Creates checkbox to enable/disable each custom scss theme modes found.
if (!empty($result)){
$config = $this->configuration['color_modes'] ?? ($defaultValues ?? null);
// For checkboxes, the array keys are used to set the checkbox values
// and the array values are used to set the checkbox labels.
$form['color_modes'] = array(
'#type' => 'checkboxes',
'#title' => $this->t('Custom Theme Modes Available'),
'#options' => $result,
'#description' => $this->t('Select custom theme modes to include on toggler toggler.'),
'#default_value' => $config,
);
$form['custom_only'] = [
'#type' => 'checkbox',
'#title' => $this->t('Use only custom theme modes'),
'#description' => $this->t("Checking this will disable 'light', 'dark' and 'auto' themes."),
'#default_value' => $this->configuration['custom_only'] ?? false,
];
} else {
// Notify users that custom color modes don't exist, or are not enabled
$form['text_no_colors'] = array(
'#type' => 'item',
'#title' => $this->t('No Custom Theme Modes Found'),
'#description' => $this->t("
Custom Theme Modes are only assumed compatible for Bootstrap Barrio SASS based themes.<br>
Theme's can also be manually indicated as compatible in the Theme Toggler global settings.
"),
);
}
return $form;
} // END blockForm
/**
* {@inheritdoc}
*/
public function blockValidate ($form, FormStateInterface $form_state) {
// Check that the machine name matches the required default name.
// Used to prevent more than one instance of this block being placed.
// Get default theme name used to determine the block's machine name.
$defaultTheme = \Drupal::config('system.theme')->getOriginal('default');
// Get the actual machine name set for current block instance.
$machine_name = $form_state->get('machine_name.initial_values');
$defaultName = $machine_name['id'] == $defaultTheme.'_themetoggler';
if (!$defaultName) {
$form_state->setErrorByName('machine_name', $this->
t("Another instance of this block already exists, or the default machine name has been changed. <br> Make sure toggler machine name is 'DEFAULT_THEME_themetoggler', and that it has not already been placed into your site."));
}
$values = $form_state->getValues();
if (!empty($values['custom_only'])) {
if (empty(array_filter( $values['color_modes'] ?? [0] ))){
$form_state->setErrorByName('color_modes', $this->
t("Cannot select 'Custom Only' and have no custom themes enabled."));
}
}
}
/**
* {@inheritdoc}
*/
public function blockSubmit($form, FormStateInterface $form_state) {
$values = $form_state->getValues();
$this->configuration['toggler_label'] = $values['toggler_label'];
$this->configuration['show_toggler_label'] = $values['show_toggler_label'];
$this->configuration['show_option_labels'] = $values['show_option_labels'];
$this->configuration['show_icons'] = $values['show_icons'];
$this->configuration['show_checkmark'] = $values['show_checkmark'];
$this->configuration['custom_only'] = $values['custom_only'] ?? null;
$this->configuration['color_modes'] = $values['color_modes'] ?? false;
// Need to remove messages set by config form.
// Even if closed by user, they will re-appear if not removed.
\Drupal::messenger()->deleteByType('toggler');
}
} // END ThemeToggler class
