diff --git a/core/modules/system/system.admin.inc b/core/modules/system/system.admin.inc index 6dca80b..2ba496c 100644 --- a/core/modules/system/system.admin.inc +++ b/core/modules/system/system.admin.inc @@ -451,15 +451,13 @@ function system_theme_settings($form, &$form_state, $key = '') { $form['logo'] = array( '#type' => 'fieldset', '#title' => t('Logo image settings'), - '#description' => t('If toggled on, the following logo will be displayed.'), '#attributes' => array('class' => array('theme-settings-bottom')), ); $form['logo']['default_logo'] = array( '#type' => 'checkbox', - '#title' => t('Use the default logo'), + '#title' => t('Use the default logo supplied by the theme'), '#default_value' => theme_get_setting('default_logo', $key), '#tree' => FALSE, - '#description' => t('Check here if you want the theme to use the logo supplied with it.') ); $form['logo']['settings'] = array( '#type' => 'container', @@ -470,17 +468,10 @@ function system_theme_settings($form, &$form_state, $key = '') { ), ), ); - $logo_path = theme_get_setting('logo_path', $key); - // If $logo_path is a public:// URI, display the path relative to the files - // directory; stream wrappers are not end-user friendly. - if (file_uri_scheme($logo_path) == 'public') { - $logo_path = file_uri_target($logo_path); - } $form['logo']['settings']['logo_path'] = array( '#type' => 'textfield', '#title' => t('Path to custom logo'), - '#default_value' => $logo_path, - '#description' => t('The path to the file you would like to use as your logo file instead of the default logo.'), + '#default_value' => theme_get_setting('logo_path', $key), ); $form['logo']['settings']['logo_upload'] = array( '#type' => 'file', @@ -498,9 +489,8 @@ function system_theme_settings($form, &$form_state, $key = '') { ); $form['favicon']['default_favicon'] = array( '#type' => 'checkbox', - '#title' => t('Use the default shortcut icon.'), + '#title' => t('Use the default shortcut icon supplied by the theme'), '#default_value' => theme_get_setting('default_favicon', $key), - '#description' => t('Check here if you want the theme to use the default shortcut icon.') ); $form['favicon']['settings'] = array( '#type' => 'container', @@ -511,17 +501,10 @@ function system_theme_settings($form, &$form_state, $key = '') { ), ), ); - $favicon_path = theme_get_setting('favicon_path', $key); - // If $favicon_path is a public:// URI, display the path relative to the - // files directory; stream wrappers are not end-user friendly. - if (file_uri_scheme($favicon_path) == 'public') { - $favicon_path = file_uri_target($favicon_path); - } $form['favicon']['settings']['favicon_path'] = array( '#type' => 'textfield', '#title' => t('Path to custom icon'), - '#default_value' => $favicon_path, - '#description' => t('The path to the image file you would like to use as your custom shortcut icon.') + '#default_value' => theme_get_setting('favicon_path', $key), ); $form['favicon']['settings']['favicon_upload'] = array( '#type' => 'file', @@ -530,6 +513,36 @@ function system_theme_settings($form, &$form_state, $key = '') { ); } + // Inject human-friendly values and form element descriptions for logo and + // favicon. + foreach (array('logo' => 'logo.png', 'favicon' => 'favicon.ico') as $type => $default) { + if (isset($form[$type]['settings'][$type . '_path'])) { + $element = &$form[$type]['settings'][$type . '_path']; + $original_path = $element['#default_value']; + // If path is a public:// URI, display the path relative to the files + // directory; stream wrappers are not end-user friendly. + if (file_uri_scheme($original_path) == 'public') { + $friendly_path = file_uri_target($original_path); + $element['#default_value'] = $friendly_path; + } + // Prepare local file path for description. + if ($original_path) { + $local_file = '/' . strtr($original_path, array('public:/' => variable_get('file_public_path', conf_path() . '/files'))); + } + elseif ($key) { + $local_file = base_path() . drupal_get_path('theme', $key) . '/' . $default; + } + else { + $local_file = base_path() . path_to_theme() . '/' . $default; + } + $element['#description'] = t('Use @implicit-public-file to reference a file in the public filesystem, @explicit-file for a specific filesystem, or @local-file for an arbitrary local file within this site.', array( + '@implicit-public-file' => isset($friendly_path) ? $friendly_path : $default, + '@explicit-file' => $original_path ? $original_path : 'public://' . $default, + '@local-file' => $local_file, + )); + } + } + if ($key) { // Call engine-specific settings. $function = $themes[$key]->prefix . '_engine_settings'; @@ -657,21 +670,36 @@ function system_theme_settings_validate($form, &$form_state) { * the path could not be validated. */ function _system_theme_settings_validate_path($path) { - if (drupal_realpath($path)) { - // The path is relative to the Drupal root, or is a valid URI. - return $path; + // Check whether the path is semi-absolute; i.e., pointing to a file in the + // document root. + if ($path[0] === '/') { + if (file_exists(DRUPAL_ROOT . '/' . substr($path, 1))) { + return $path; + } + return FALSE; } - $uri = 'public://' . $path; - if (file_exists($uri)) { - return $uri; + // Otherwise, it must be a stream wrapper URI. + else { + // Prepend 'public://' for relative file paths within public filesystem. + if (file_uri_scheme($path) === FALSE) { + $path = 'public://' . $path; + } + if (file_exists($path)) { + return $path; + } + return FALSE; } - return FALSE; } /** * Process system_theme_settings form submissions. */ function system_theme_settings_submit($form, &$form_state) { + // Exclude unnecessary elements before saving. + form_state_values_clean($form_state); + $key = $form_state['values']['var']; + unset($form_state['values']['var']); + $values = $form_state['values']; // If the user uploaded a new logo or favicon, save it to a permanent location @@ -703,10 +731,7 @@ function system_theme_settings_submit($form, &$form_state) { if (empty($values['default_favicon']) && !empty($values['favicon_path'])) { $values['favicon_mimetype'] = file_get_mimetype($values['favicon_path']); } - $key = $values['var']; - // Exclude unnecessary elements before saving. - unset($values['var'], $values['submit'], $values['reset'], $values['form_id'], $values['op'], $values['form_build_id'], $values['form_token']); variable_set($key, $values); drupal_set_message(t('The configuration options have been saved.')); diff --git a/core/modules/system/system.test b/core/modules/system/system.test index 12797ed..8353e15 100644 --- a/core/modules/system/system.test +++ b/core/modules/system/system.test @@ -1600,6 +1600,8 @@ class SystemMainContentFallback extends DrupalWebTestCase { * Tests for the theme interface functionality. */ class SystemThemeFunctionalTest extends DrupalWebTestCase { + protected $profile = 'testing'; + public static function getInfo() { return array( 'name' => 'Theme interface functionality', @@ -1609,7 +1611,9 @@ class SystemThemeFunctionalTest extends DrupalWebTestCase { } function setUp() { - parent::setUp(); + parent::setUp(array('block')); + + $this->drupalCreateContentType(array('type' => 'page', 'name' => 'Basic page')); $this->admin_user = $this->drupalCreateUser(array('access administration pages', 'view the administration theme', 'administer themes', 'bypass node access', 'administer blocks')); $this->drupalLogin($this->admin_user); @@ -1622,26 +1626,73 @@ class SystemThemeFunctionalTest extends DrupalWebTestCase { function testThemeSettings() { // Specify a filesystem path to be used for the logo. $file = current($this->drupalGetTestFiles('image')); - $fullpath = drupal_realpath($file->uri); - $edit = array( - 'default_logo' => FALSE, - 'logo_path' => $fullpath, + $supported_paths = array( + // Raw stream wrapper URIs are supported. + $file->uri, + // Relative paths within the public filesystem are supported. + file_uri_target($file->uri), + // Semi-absolute paths to public files are supported. + '/' . strtr($file->uri, array('public:/' => variable_get('file_public_path', conf_path() . '/files'))), + // Semi-absolute paths to arbitrary files are supported. + '/' . path_to_theme() . '/logo.png', ); - $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration')); - $this->drupalGet('node'); - $this->assertRaw($fullpath, t('Logo path successfully changed.')); + foreach ($supported_paths as $path) { + $edit = array( + 'default_logo' => FALSE, + 'logo_path' => $path, + ); + $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration')); + $this->assertNoText('The custom logo path is invalid.'); + + $this->drupalGet(''); + // Use semi-absolute path directly. + if ($path[0] === '/') { + // Do nothing. + } + // Prepend 'public://' for the relative file path within public + // filesystem case. + elseif (file_uri_scheme($path) === FALSE) { + $path = 'public://' . $path; + } + $elements = $this->xpath('//*[@id=:id]/img', array(':id' => 'logo')); + $this->assertEqual($elements[0]['src'], file_create_url($path)); + } + + $unsupported_paths = array( + // Stream wrapper URI to non-existing file. + 'public://whatever.png', + // Relative path within the public filesystem to non-existing file. + 'whatever.png', + // Semi-absolute paths to non-existing public file. + '/' . variable_get('file_public_path', conf_path() . '/files') . '/whatever.png', + // Semi-absolute paths to non-existing arbitrary file. + '/' . path_to_theme() . '/whatever.png', + // Absolute paths to any local file (even if it exists). + drupal_realpath($file->uri), + ); + foreach ($unsupported_paths as $path) { + $edit = array( + 'default_logo' => FALSE, + 'logo_path' => $path, + ); + $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration')); + $this->assertText('The custom logo path is invalid.'); + } // Upload a file to use for the logo. - $file = current($this->drupalGetTestFiles('image')); $edit = array( 'default_logo' => FALSE, 'logo_path' => '', 'files[logo_upload]' => drupal_realpath($file->uri), ); - $options = array(); - $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration'), $options); - $this->drupalGet('node'); - $this->assertRaw($file->name, t('Logo file successfully uploaded.')); + $this->drupalPost('admin/appearance/settings', $edit, t('Save configuration')); + + $fields = $this->xpath($this->constructFieldXpath('name', 'logo_path')); + $uploaded_filename = 'public://' . $fields[0]['value']; + + $this->drupalGet(''); + $elements = $this->xpath('//*[@id=:id]/img', array(':id' => 'logo')); + $this->assertEqual($elements[0]['src'], file_create_url($uploaded_filename)); } /** @@ -1700,20 +1751,20 @@ class SystemThemeFunctionalTest extends DrupalWebTestCase { * Test switching the default theme. */ function testSwitchDefaultTheme() { - // Enable "stark" and set it as the default theme. - theme_enable(array('stark')); + // Enable Bartik and set it as the default theme. + theme_enable(array('bartik')); $this->drupalGet('admin/appearance'); - $this->clickLink(t('Set default'), 1); - $this->assertTrue(variable_get('theme_default', '') == 'stark', t('Site default theme switched successfully.')); + $this->clickLink(t('Set default')); + $this->assertEqual(variable_get('theme_default', ''), 'bartik'); // Test the default theme on the secondary links (blocks admin page). $this->drupalGet('admin/structure/block'); - $this->assertText('Stark(' . t('active tab') . ')', t('Default local task on blocks admin page is the default theme.')); - // Switch back to Bartik and test again to test that the menu cache is cleared. + $this->assertText('Bartik(' . t('active tab') . ')', t('Default local task on blocks admin page is the default theme.')); + // Switch back to Stark and test again to test that the menu cache is cleared. $this->drupalGet('admin/appearance'); $this->clickLink(t('Set default'), 0); $this->drupalGet('admin/structure/block'); - $this->assertText('Bartik(' . t('active tab') . ')', t('Default local task on blocks admin page has changed.')); + $this->assertText('Stark(' . t('active tab') . ')', t('Default local task on blocks admin page has changed.')); } }