You are here

touch_icons.module in Touch Icons 6

Same filename and directory in other branches
  1. 7.2 touch_icons.module
  2. 7 touch_icons.module

Adds a fieldset to theme settings form which allows site administrators to specify Apple Touch icons for Drupal websites. The Touch icon settings behave in a similar manner to the Site Logo and Favicon settings provided by Drupal core.

Also provides a simple means for theme developers to provide default Touch icons with their theme.

@todo implement hook_help()

@todo refactor fieldsets? do I want two top-level fieldsets? or one top-level/two-children? should children be collapsible? children not collapsible inside VTabs?

File

touch_icons.module
View source
<?php

/**
 * @file
 *
 * Adds a fieldset to theme settings form  which allows site administrators to
 * specify Apple Touch icons for Drupal websites. The Touch icon settings behave
 * in a similar manner to the Site Logo and Favicon settings provided by Drupal
 * core.
 *
 * Also provides a simple means for theme developers to provide default Touch
 * icons with their theme.
 *
 * @todo implement hook_help()
 * @todo refactor fieldsets?
 *   do I want two top-level fieldsets? or one top-level/two-children?
 *     should children be collapsible?
 *     children not collapsible inside VTabs?
 */

/**
 * helper function to get theme key for theme settings page.
 *
 * if we don't receive $key parameter like system_theme_settings()
 * we can get it from path, i.e. 'admin/build/themes/settings/THEMENAME'
 *
 * NOTE: this is NOT the active theme being used to display the page; it is the
 * theme currently being configured on the theme settings form.
 */
function _touch_icons_get_theme_settings_key() {
  $key = arg(4);
  if ($key == "global") {

    // undesirable side-effect of admin_menu.module
    $key = '';
  }
  return $key;
}

/**
 * Implementation of hook_form_FORM_ID_alter().
 * Implementation of hook_form_system_theme_settings_alter().
 *
 * Add Apple Touch icon customization settings to the theme settings form.
 *
 * @see system_theme_settings()
 */
function touch_icons_form_system_theme_settings_alter(&$form, $form_state) {

  // default values for touch_icons theme_settings
  $defaults = array(
    'toggle_touch_icon_plain' => 1,
    'default_touch_icon_plain' => 1,
    'toggle_touch_icon_precomp' => 1,
    'default_touch_icon_precomp' => 1,
  );

  // we don't receive $key parameter like system_theme_settings()
  $key = _touch_icons_get_theme_settings_key();

  // get theme_settings, using defaults if no touch_icons settings exist
  $settings = array_merge($defaults, theme_get_settings($key));

  // touch icons fieldset
  $form['touch_icons'] = array(
    '#type' => 'fieldset',
    '#title' => t('iOS touch icon settings'),
    '#description' => t('Touch icons are shown as bookmarks on the home-screen of an iOS device.'),
  );

  // plain touch icon fieldset
  $form['touch_icons']['plain'] = array(
    '#type' => 'fieldset',
    '#title' => t('iOS touch icon'),
    '#description' => t('Most iOS devices can display this kind of icon. Rounded corners and a glass-effect overlay are applied by the iOS device.'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );

  // precomposed touch icon fieldset
  $form['touch_icons']['precomp'] = array(
    '#type' => 'fieldset',
    '#title' => t('iOS touch icon (precomposed)'),
    '#description' => t('Using a &apos;precomposed&apos; touch icon allows more control over the icon&apos;s appearance. iOS devices do not apply any special effects to these icons. It is <em>highly recommended</em> that you also enable a plain version, as early iOS versions do not support precomposed icons.'),
    '#collapsible' => TRUE,
    '#collapsed' => FALSE,
  );

  // touch icon display settings
  if (!module_exists('themesettings_ui_extras')) {

    // core-style checkboxes
    _touch_icons_themesettings_checkbox($form, $form_state, $settings);
  }
  else {

    // integrate with themesettings_ui_extras.module
    _touch_icons_themesettings_radio($form, $form_state, $settings);
  }

  // custom plain touch icon settings
  $form['touch_icons']['plain']['touch_icon_plain_path'] = array(
    '#type' => 'textfield',
    '#title' => t('Path to custom icon'),
    '#default_value' => $settings['touch_icon_plain_path'],
    '#description' => t('The path to the file you would like to use as your touch icon instead of the default touch icon.'),
  );
  $form['touch_icons']['plain']['touch_icon_plain_upload'] = array(
    '#type' => 'file',
    '#title' => t('Upload icon'),
    '#description' => t("If you don't have direct file access to the server, use this field to upload your touch icon."),
    '#element_validate' => array(
      '_touch_icons_plain_upload_validate',
    ),
  );

  // custom precomposed touch icon settings
  $form['touch_icons']['precomp']['touch_icon_precomp_path'] = array(
    '#type' => 'textfield',
    '#title' => t('Path to custom precomposed icon'),
    '#default_value' => $settings['touch_icon_precomp_path'],
    '#description' => t('The path to the file you would like to use as your precomposed touch icon instead of the default precomposed touch icon.'),
  );
  $form['touch_icons']['precomp']['touch_icon_precomp_upload'] = array(
    '#type' => 'file',
    '#title' => t('Upload precomposed icon'),
    '#description' => t("If you don't have direct file access to the server, use this field to upload your precomposed touch icon."),
    '#element_validate' => array(
      '_touch_icons_precomp_upload_validate',
    ),
  );

  // adjust form element weights, keep things pretty
  // @todo review weights - do any other contrib modules alter this form?
  //   YES, designkit adds fieldsets too.
  if ($form['engine_specific']) {
    $form['engine_specific']['#weight'] = 8;
  }
  if ($form['theme_specific']) {
    $form['theme_specific']['#weight'] = 9;
  }
  $form['buttons']['#weight'] = 10;

  // same weight as designkit uses
}

/**
 * Helper function for touch icons theme settings form elements.
 *
 * Provides core-style checkboxes for touch icon theme settings.
 *
 * @see touch_icons_form_alter()
 */
function _touch_icons_themesettings_checkbox(&$form, &$form_state, &$settings) {

  // toggle-display checkboxes
  $form['theme_settings']['toggle_touch_icon_plain'] = array(
    '#type' => 'checkbox',
    '#title' => t('iOS touch icon'),
    '#default_value' => $settings['toggle_touch_icon_plain'],
  );
  $form['theme_settings']['toggle_touch_icon_precomp'] = array(
    '#type' => 'checkbox',
    '#title' => t('iOS touch icon (precomposed)'),
    '#default_value' => $settings['toggle_touch_icon_precomp'],
  );

  // use default icon checkboxes
  $form['touch_icons']['plain']['default_touch_icon_plain'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use the default iOS touch icon.'),
    '#default_value' => $settings['default_touch_icon_plain'],
    '#tree' => FALSE,
    '#description' => t('Check here if you want the theme to use the touch icon supplied with it.'),
  );
  $form['touch_icons']['precomp']['default_touch_icon_precomp'] = array(
    '#type' => 'checkbox',
    '#title' => t('Use the default precomposed iOS touch icon.'),
    '#default_value' => $settings['default_touch_icon_precomp'],
    '#tree' => FALSE,
    '#description' => t('Check here if you want the theme to use the precomposed touch icon supplied with it.'),
  );

  // integrate with themsettings_verticaltabs.module
  if (module_exists('themesettings_verticaltabs')) {
    $form['touch_icons']['#attached'] = array(
      'js' => array(
        'vertical-tabs' => drupal_get_path('module', 'touch_icons') . '/touch_icons_verticaltabs.js',
      ),
    );
  }
}

/**
 * Helper function for touch icons theme settings form elements.
 *
 * Integration with themesettings_ui_extras.module
 * Provides radio buttons for touch icon theme settings.
 *
 * @see touch_icons_form_alter()
 * @see themesettings_ui_extras_form_alter()
 */
function _touch_icons_themesettings_radio(&$form, &$form_state, &$settings) {

  // javascript behaviour to show/hide custom path and file upload elements
  drupal_add_js(drupal_get_path('module', 'touch_icons') . '/touch_icons_themesettings_ui_extras.js');

  // deduce which plain touch icon radio-button to pre-select
  if ($settings['toggle_touch_icon_plain'] == '0') {
    $touch_icon_plain_display_value = 'none';
  }
  elseif ($settings['toggle_touch_icon_plain'] == 1 && $settings['default_touch_icon_plain'] == 1) {
    $touch_icon_plain_display_value = 'default';
  }
  elseif ($settings['toggle_touch_icon_plain'] == 1 && $settings['default_touch_icon_plain'] == 0) {
    $touch_icon_plain_display_value = 'custom';
  }

  // plain touch icon radio-buttons
  $form['touch_icons']['plain']['touch_icon_plain_display'] = array(
    '#type' => 'radios',
    '#title' => t('Display touch icon'),
    '#description' => t('Whether a touch icon should be displayed.'),
    '#options' => array(
      'none' => 'No touch icon',
      'default' => 'Default touch icon',
      'custom' => 'Custom touch icon',
    ),
    '#default_value' => $touch_icon_plain_display_value,
    '#element_validate' => array(
      '_touch_icons_plain_radio_validate',
    ),
  );

  // deduce which precomposed touch icon radio-button to pre-select
  if ($settings['toggle_touch_icon_precomp'] == '0') {
    $touch_icon_precomp_display_value = 'none';
  }
  elseif ($settings['toggle_touch_icon_precomp'] == 1 && $settings['default_touch_icon_precomp'] == 1) {
    $touch_icon_precomp_display_value = 'default';
  }
  elseif ($settings['toggle_touch_icon_precomp'] == 1 && $settings['default_touch_icon_precomp'] == 0) {
    $touch_icon_precomp_display_value = 'custom';
  }

  // precomposed touch icon radio-buttons
  $form['touch_icons']['precomp']['touch_icon_precomp_display'] = array(
    '#type' => 'radios',
    '#title' => t('Display precomposed touch icon'),
    '#description' => t('Whether a precomposed touch icon should be displayed.'),
    '#options' => array(
      'none' => 'No precomposed touch icon',
      'default' => 'Default precomposed touch icon',
      'custom' => 'Custom precomposed touch icon',
    ),
    '#default_value' => $touch_icon_precomp_display_value,
    '#element_validate' => array(
      '_touch_icons_precomp_radio_validate',
    ),
  );

  // integrate with themsettings_verticaltabs.module
  if (module_exists('themesettings_verticaltabs')) {
    $form['touch_icons']['#attached'] = array(
      'js' => array(
        'vertical-tabs' => drupal_get_path('module', 'touch_icons') . '/touch_icons_verticaltabs_radios.js',
      ),
    );
  }
}

/**
 * Validate plain touch icon display setting.
 *
 * Helper for integration with themesettings_ui_extras.module
 *
 * Ensures that theme settings variables are stored in a core-compatible format,
 * in case themesettings_ui_extras.module is disabled later.
 */
function _touch_icons_plain_radio_validate($element, &$form_state) {
  switch ($form_state['values']['touch_icon_plain_display']) {
    case 'none':
      $form_state['values']['toggle_touch_icon_plain'] = 0;

      // best to set a default value, in case module disabled later...
      $form_state['values']['default_touch_icon_plain'] = 1;
      break;
    case 'default':
      $form_state['values']['toggle_touch_icon_plain'] = 1;
      $form_state['values']['default_touch_icon_plain'] = 1;
      break;
    case 'custom':
      $form_state['values']['toggle_touch_icon_plain'] = 1;
      $form_state['values']['default_touch_icon_plain'] = 0;
      break;
  }

  // no need to store this
  unset($form_state['values']['touch_icon_plain_display']);
}

/**
 * Validate precomp touch icon display setting.
 *
 * Helper for integration with themesettings_ui_extras.module
 *
 * Ensures that theme settings variables are stored in a core-compatible format,
 * in case themesettings_ui_extras.module is disabled later.
 */
function _touch_icons_precomp_radio_validate($element, &$form_state) {
  switch ($form_state['values']['touch_icon_precomp_display']) {
    case 'none':
      $form_state['values']['toggle_touch_icon_precomp'] = 0;

      // best to set a default value, in case module disabled later...
      $form_state['values']['default_touch_icon_precomp'] = 1;
      break;
    case 'default':
      $form_state['values']['toggle_touch_icon_precomp'] = 1;
      $form_state['values']['default_touch_icon_precomp'] = 1;
      break;
    case 'custom':
      $form_state['values']['toggle_touch_icon_precomp'] = 1;
      $form_state['values']['default_touch_icon_precomp'] = 0;
      break;
  }

  // no need to store this
  unset($form_state['values']['touch_icon_precomp_display']);
}

/**
 * Validate custom plain touch icon upload.
 *
 * Saves the uploaded file and prepares file path variable.
 */
function _touch_icons_plain_upload_validate($element, &$form_state) {

  // need theme key for saving theme-specific icons
  // e.g. garland_apple-touch-icon.png
  $key = _touch_icons_get_theme_settings_key();

  // ensure there is a directory to save touch icons
  $directory_path = file_directory_path() . '/touch_icons';
  file_check_directory($directory_path, FILE_CREATE_DIRECTORY);

  // Handle plain touch icon upload
  if ($file = file_save_upload('touch_icon_plain_upload', array(
    'file_validate_is_image' => array(),
  ))) {
    $parts = pathinfo($file->filename);
    $filename = $key ? 'touch_icons/' . str_replace('/', '_', $key) . '_apple-touch-icon.' . $parts['extension'] : 'touch_icons/' . 'apple-touch-icon.' . $parts['extension'];
    if (file_copy($file, $filename, FILE_EXISTS_REPLACE)) {
      drupal_set_message(t('The new touch icon was saved.'));
      $form_state['values']['touch_icon_plain_path'] = $file->filepath;

      // prepare theme settings variables for storage
      // keep consistent with core logo/favicon behaviour
      $form_state['values']['default_touch_icon_plain'] = 0;
      $form_state['values']['toggle_touch_icon_plain'] = 1;
    }
  }
}

/**
 * Validate custom precomposed touch icon upload.
 *
 * Saves the uploaded file and prepares file path variable.
 */
function _touch_icons_precomp_upload_validate($element, &$form_state) {

  // need theme key for saving theme-specific icons
  // e.g. garland_apple-touch-icon.png
  $key = _touch_icons_get_theme_settings_key();

  // ensure there is a directory to save touch icons
  $directory_path = file_directory_path() . '/touch_icons';
  file_check_directory($directory_path, FILE_CREATE_DIRECTORY);

  // Handle precomposed touch icon upload
  if ($file = file_save_upload('touch_icon_precomp_upload', array(
    'file_validate_is_image' => array(),
  ))) {
    $parts = pathinfo($file->filename);
    $filename = $key ? 'touch_icons/' . str_replace('/', '_', $key) . '_apple-touch-icon-precomposed.' . $parts['extension'] : 'touch_icons/' . 'apple-touch-icon-precomposed.' . $parts['extension'];
    if (file_copy($file, $filename, FILE_EXISTS_REPLACE)) {
      drupal_set_message(t('The new precomposed touch icon was saved.'));
      $form_state['values']['touch_icon_precomp_path'] = $file->filepath;

      // prepare theme settings variables for storage
      // keep consistent with core logo/favicon behaviour
      $form_state['values']['default_touch_icon_precomp'] = 0;
      $form_state['values']['toggle_touch_icon_precomp'] = 1;
    }
  }
}

/**
 * Implementation of hook_preprocess_page().
 *
 * Output <link> elements for the touch icons.
 */
function touch_icons_preprocess_page(&$variables) {
  global $theme_key;
  $touch_icons_links = '';

  // output link for plain touch icon
  $url_plain = _touch_icons_create_touch_icon_url($theme_key);
  if (check_url($url_plain)) {
    $touch_icons_links .= '<link href="' . $url_plain . '" type="' . file_get_mimetype($url_plain) . '" rel="apple-touch-icon" />' . "\n";
  }

  // output link for precomposed touch icon
  $url_precomp = _touch_icons_create_touch_icon_url($theme_key, TRUE);
  if (check_url($url_precomp)) {
    $touch_icons_links .= '<link href="' . $url_precomp . '" type="' . file_get_mimetype($url_precomp) . '" rel="apple-touch-icon-precomposed" />' . "\n";
  }
  drupal_set_html_head($touch_icons_links);
  $variables['head'] = drupal_get_html_head();
}

/**
 * Returns a URL for a touch icon image file, for any theme.
 *
 * @param $key
 *   The theme which we need the touch icon URL for.
 * @param $precomp
 *   Specify TRUE if the precomposed touch icon variant is required.
 *   Default value is FALSE, i.e. the plain touch icon variant.
 *
 * @return
 *   A URL for the touch icon.
 */
function _touch_icons_create_touch_icon_url($key, $precomp = FALSE) {
  $themes = list_themes();
  $theme_object = $themes[$key];
  $settings = theme_get_settings($key);
  $icon_type = $precomp ? 'precomp' : 'plain';
  $default_filename = 'apple-touch-icon' . ($precomp ? '-precomposed' : '') . '.png';

  // build apple-touch-icon URL
  $url = '';
  if (!empty($settings['toggle_touch_icon_' . $icon_type])) {
    if (!empty($settings['default_touch_icon_' . $icon_type])) {
      if (file_exists($touch_icon = dirname($theme_object->filename) . '/' . $default_filename)) {
        $url = base_path() . $touch_icon;
      }
      else {
        $url = base_path() . drupal_get_path('module', 'touch_icons') . '/' . $default_filename;
      }
    }
    elseif ($settings['touch_icon_' . $icon_type . '_path']) {
      $url = base_path() . $settings['touch_icon_' . $icon_type . '_path'];
    }
  }
  return $url;
}

Functions

Namesort descending Description
touch_icons_form_system_theme_settings_alter Implementation of hook_form_FORM_ID_alter(). Implementation of hook_form_system_theme_settings_alter().
touch_icons_preprocess_page Implementation of hook_preprocess_page().
_touch_icons_create_touch_icon_url Returns a URL for a touch icon image file, for any theme.
_touch_icons_get_theme_settings_key helper function to get theme key for theme settings page.
_touch_icons_plain_radio_validate Validate plain touch icon display setting.
_touch_icons_plain_upload_validate Validate custom plain touch icon upload.
_touch_icons_precomp_radio_validate Validate precomp touch icon display setting.
_touch_icons_precomp_upload_validate Validate custom precomposed touch icon upload.
_touch_icons_themesettings_checkbox Helper function for touch icons theme settings form elements.
_touch_icons_themesettings_radio Helper function for touch icons theme settings form elements.