You are here

css_editor.module in CSS Editor 8

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

Allows users to apply customized CSS to themes.

File

css_editor.module
View source
<?php

/**
 * @file
 * Allows users to apply customized CSS to themes.
 */
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Url;

/**
 * Implements hook_library_info_alter().
 */
function css_editor_library_info_alter(&$libraries, $extension) {
  $theme = \Drupal::theme()
    ->getActiveTheme()
    ->getName();
  if ($extension == $theme) {
    if ($file = _css_editor_get_stylesheet($theme)) {

      // Append custom style sheet to theme libraries.
      $libraries['css_editor']['css']['theme'][$file]['weight'] = 9999;
    }
  }
}

/**
 * Implements hook_page_attachments().
 */
function css_editor_page_attachments(array &$page) {
  $theme = \Drupal::theme()
    ->getActiveTheme()
    ->getName();
  if (_css_editor_get_stylesheet($theme)) {
    $page['#attached']['library'][] = $theme . '/css_editor';
  }
}

/**
 * Implements hook_form_FORM_ID_alter() for `system_theme_settings`.
 */
function css_editor_form_system_theme_settings_alter(&$form, FormStateInterface $form_state, $form_id) {
  $theme = _css_editor_get_edited_theme($form_state);
  if ($theme) {
    $config = \Drupal::config('css_editor.theme.' . $theme);

    // Add CSS customization fieldset.
    $form['css_editor'] = array(
      '#type' => 'details',
      '#title' => t('Custom CSS'),
      '#open' => TRUE,
      '#tree' => TRUE,
    );

    // Switch to enable/disable customization.
    $form['css_editor']['css_enabled'] = array(
      '#title' => t('Enable or disable custom CSS:'),
      '#type' => 'checkbox',
      '#default_value' => $config
        ->get('enabled'),
    );

    // Editor box.
    $form['css_editor']['css'] = array(
      '#type' => 'textarea',
      '#prefix' => '<div id="css-editor-field">',
      '#description' => t('Type or paste custom CSS code for this theme.'),
      '#default_value' => $config
        ->get('css'),
      '#attributes' => array(
        'id' => 'css-editor-textarea',
      ),
      '#suffix' => '</div>',
    );

    // Switch to enable/disable the plain text editor.
    $form['css_editor']['plaintext_enabled'] = array(
      '#title' => t('Use plain text editor'),
      '#type' => 'checkbox',
      '#default_value' => $config
        ->get('plaintext_enabled'),
    );

    // Switch to enable/disable autopreview.
    $form['css_editor']['autopreview_enabled'] = array(
      '#title' => t('Enable auto preview'),
      '#type' => 'checkbox',
      '#default_value' => $config
        ->get('autopreview_enabled'),
    );

    // Preview path.
    $form['css_editor']['preview_path'] = array(
      '#title' => t('Preview path:'),
      '#type' => 'textfield',
      '#size' => 60,
    );

    // Preview box.
    $preview_url = Url::fromRoute('<front>', array(), array(
      'absolute' => TRUE,
      'query' => array(
        'theme' => $theme,
      ),
    ))
      ->toString();
    $form['css_editor']['css_preview'] = array(
      '#type' => 'inline_template',
      '#template' => '<iframe src="{{ url }}" id="css-editor-preview">' . t('Frames are not supported.') . '</iframe>',
      '#context' => array(
        'url' => $preview_url,
      ),
    );

    // Attach CSS and Javascript libraries.
    $form['#attached']['library'][] = 'css_editor/codemirror';
    $form['#attached']['library'][] = 'css_editor/css_editor';
    $form['#attached']['drupalSettings']['CSSEditor']['frontPage'] = $preview_url;
    array_unshift($form['#submit'], '_css_editor_theme_settings_form_submit');
  }
}

/**
 * Form submission handler for hook_form_system_theme_settings_alter().
 */
function _css_editor_theme_settings_form_submit($form, FormStateInterface $form_state) {
  $theme = _css_editor_get_edited_theme($form_state);
  if ($theme) {

    // Save file.
    $path = 'public://css_editor';
    $file = $path . DIRECTORY_SEPARATOR . $theme . '.css';
    if (\Drupal::service('file_system')
      ->prepareDirectory($path, FileSystemInterface::CREATE_DIRECTORY | FileSystemInterface::MODIFY_PERMISSIONS)) {
      \Drupal::service('file_system')
        ->saveData($form_state
        ->getValue([
        'css_editor',
        'css',
      ]), $file, FileSystemInterface::EXISTS_REPLACE);
      \Drupal::service('file_system')
        ->chmod($file);
    }

    // Save settings.
    \Drupal::configFactory()
      ->getEditable('css_editor.theme.' . $theme)
      ->set('enabled', $form_state
      ->getValue([
      'css_editor',
      'enabled',
    ]))
      ->set('plaintext_enabled', $form_state
      ->getValue([
      'css_editor',
      'plaintext_enabled',
    ]))
      ->set('autopreview_enabled', $form_state
      ->getValue([
      'css_editor',
      'autopreview_enabled',
    ]))
      ->set('css', $form_state
      ->getValue([
      'css_editor',
      'css',
    ]))
      ->set('path', $file)
      ->save();

    // Clear cache.
    drupal_flush_all_caches();
  }

  // Remove the settings from the form state so the values are not saved in the
  // theme settings.
  $form_state
    ->unsetValue('css_editor');
}

/**
 * Form helper.
 */
function _css_editor_get_edited_theme(FormStateInterface $form_state) {

  // Return theme being currently edited.
  $build_info = $form_state
    ->getBuildInfo();
  return isset($build_info['args'][0]) ? $build_info['args'][0] : FALSE;
}

/**
 * Get the Custom CSS generated file for a theme.
 *
 * @param $theme
 *   The machine name of the current theme.
 *
 * @return string|bool
 */
function _css_editor_get_stylesheet($theme) {
  $config = \Drupal::config('css_editor.theme.' . $theme);
  $file = $config
    ->get('path');
  if ($config
    ->get('enabled') && file_exists($file)) {
    return $file;
  }
  else {
    return FALSE;
  }
}