diff --git a/core/MAINTAINERS.txt b/core/MAINTAINERS.txt
index 28153ec..b5f0c8d 100644
--- a/core/MAINTAINERS.txt
+++ b/core/MAINTAINERS.txt
@@ -129,7 +129,6 @@ Markup
Migrate
- Ben Dougherty 'benjy' https://drupal.org/user/1852732
-- Claudiu Cristea "claudiu.cristea" https://drupal.org/user/56348
- Mike Ryan 'mikeryan' http://drupal.org/user/4420
Menu system
diff --git a/core/UPGRADE.txt b/core/UPGRADE.txt
index 420f6ad..f035b6c 100644
--- a/core/UPGRADE.txt
+++ b/core/UPGRADE.txt
@@ -5,7 +5,7 @@ This document describes how to:
* Update your Drupal site from one minor 8.x version to another minor 8.x
version; for example, from 8.8 to 8.9, or from 8.6 to 8.10.
- * Migrate your Drupal site to version 8.x.
+ * Upgrade your Drupal site's major version from 7.x to 8.x.
First steps and definitions:
@@ -121,10 +121,118 @@ following the instructions in the INTRODUCTION section at the top of this file:
Disable the "Put site into maintenance mode" checkbox and save the
configuration.
-MAJOR VERSION MIGRATION
------------------------
-Upgrading from a prior major version of Drupal to Drupal 8.x is not possible.
-The process now requires a migration to a Drupal 8.x site, utilizing the Migrate
-module in Drupal core.
+MAJOR VERSION UPGRADE
+---------------------
+To upgrade from a previous major version of Drupal to Drupal 8.x, after
+following the instructions in the INTRODUCTION section at the top of this file:
+
+1. Check on the Drupal 8 status of your contributed and custom modules and
+ themes. See http://drupal.org/node/948216 for information on upgrading
+ contributed modules and themes. See http://drupal.org/node/895314 for a list
+ of modules that have been moved into core for Drupal 8, and instructions on
+ how to update them. See http://drupal.org/update/modules for information on
+ how to update your custom modules, and http://drupal.org/update/theme for
+ custom themes.
+
+ You may decide at this point that you cannot upgrade your site because
+ needed modules or themes are not ready for Drupal 8
+
+2. Update to the latest available version of Drupal 7.x (if your current version
+ is Drupal 6.x, you have to upgrade to 7.x first). If you need to update,
+ download Drupal 7.x and follow the instructions in its UPGRADE.txt. This
+ document only applies for upgrades from 7.x to 8.x.
+
+3. In addition to updating to the latest available version of Drupal 7.x core,
+ you must also upgrade all of your contributed modules for Drupal to their
+ latest Drupal 7.x versions.
+
+4. Log in as user ID 1 (the site maintenance user).
+
+5. Go to Administer > Site configuration > Site maintenance. Select
+ "Off-line" and save the configuration.
+
+6. Go to Administer > Site building > Themes. Enable "Bartik" and select it as
+ the default theme.
+
+7. Go to Administer > Site building > Modules. Disable all modules that are not
+ listed under "Core - required" or "Core - optional". It is possible that some
+ modules cannot be disabled because others depend on them. Repeat this step
+ until all non-core modules are disabled.
+
+ If you know that you will not re-enable some modules for Drupal 8.x and you
+ no longer need their data, then you can uninstall them under the Uninstall
+ tab after disabling them.
+
+8. On the command line or in your FTP client, remove the file
+
+ sites/default/default.settings.php
+
+9. Remove all old core files and directories, except for the 'sites' directory
+ and any custom files you added elsewhere.
+
+ If you made modifications to files like .htaccess or robots.txt, you will
+ need to re-apply them from your backup, after the new files are in place.
+
+10. If you uninstalled any modules, remove them from the /modules and other
+ sites/*/modules directories. Leave other modules in place, even though they
+ are incompatible with Drupal 8.x.
+
+11. Download the latest Drupal 8.x release from http://drupal.org to a
+ directory outside of your web root. Extract the archive and copy the files
+ into your Drupal directory.
+
+ On a typical Unix/Linux command line, use the following commands to download
+ and extract:
+
+ wget http://drupal.org/files/projects/drupal-x.y.tar.gz
+ tar -zxvf drupal-x.y.tar.gz
+
+ This creates a new directory drupal-x.y/ containing all Drupal files and
+ directories. Copy the files into your Drupal installation directory:
+
+ cp -R drupal-x.y/* drupal-x.y/.htaccess /path/to/your/installation
+
+ If you do not have command line access to your server, download the archive
+ from http://drupal.org using your web browser, extract it, and then use an
+ FTP client to upload the files to your web root.
+
+12. Re-apply any modifications to files such as .htaccess or robots.txt.
+
+13. Make your settings.php file writeable, so that the update process can
+ convert it to the format of Drupal 8.x. settings.php is usually located in
+
+ sites/default/settings.php
+
+14. Run update.php by visiting http://www.example.com/core/update.php (replace
+ www.example.com with your domain name). This will update the core database
+ tables.
+
+ If you are unable to access update.php do the following:
+
+ - Open settings.php with a text editor.
+
+ - Find the line that says:
+ $settings['update_free_access'] = FALSE;
+
+ - Change it into:
+ $settings['update_free_access'] = TRUE;
+
+ - Once the upgrade is done, $settings['update_free_access'] must be
+ reverted to FALSE.
+
+15. Backup your database after the core upgrade has run.
+
+16. Replace and update your non-core modules and themes, following the
+ procedures at http://drupal.org/node/948216
+
+17. Go to Administration > Reports > Status report. Verify that everything is
+ working as expected.
+
+18. Ensure that $settings['update_free_access'] is FALSE in settings.php.
+
+19. Go to Administration > Configuration > Development > Maintenance mode.
+ Disable the "Put site into maintenance mode" checkbox and save the
+ configuration.
-Note that migration support in Drupal 8 is currently only partially implemented.
+To get started with Drupal 8 administration, visit
+http://drupal.org/getting-started/7/admin
diff --git a/core/assets/vendor/domready/ready.min.js b/core/assets/vendor/domready/ready.min.js
index c4ebe97..0d681c7 100644
--- a/core/assets/vendor/domready/ready.min.js
+++ b/core/assets/vendor/domready/ready.min.js
@@ -1,4 +1,4 @@
/*!
- * domready (c) Dustin Diaz 2014 - License MIT
+ * domready (c) Dustin Diaz 2012 - License MIT
*/
-!function(e,t){typeof module!="undefined"?module.exports=t():typeof define=="function"&&typeof define.amd=="object"?define(t):this[e]=t()}("domready",function(){var e=[],t,n=document,r="DOMContentLoaded",i=/^loaded|^i|^c/.test(n.readyState);return i||n.addEventListener(r,t=function(){n.removeEventListener(r,t),i=1;while(t=e.shift())t()}),function(t){i?t():e.push(t)}})
+!function(e,t){typeof module!="undefined"?module.exports=t():typeof define=="function"&&typeof define.amd=="object"?define(t):this[e]=t()}("domready",function(e){function p(e){h=1;while(e=t.shift())e()}var t=[],n,r=!1,i=document,s=i.documentElement,o=s.doScroll,u="DOMContentLoaded",a="addEventListener",f="onreadystatechange",l="readyState",c=o?/^loaded|^c/:/^loaded|c/,h=c.test(i[l]);return i[a]&&i[a](u,n=function(){i.removeEventListener(u,n,r),p()},r),o&&i.attachEvent(f,n=function(){/^c/.test(i[l])&&(i.detachEvent(f,n),p())}),e=o?function(n){self!=top?h?n():t.push(n):function(){try{s.doScroll("left")}catch(t){return setTimeout(function(){e(n)},50)}n()}()}:function(e){h?e():t.push(e)}})
diff --git a/core/authorize.php b/core/authorize.php
index ba71c5d..d812f2e 100644
--- a/core/authorize.php
+++ b/core/authorize.php
@@ -71,6 +71,9 @@ function authorize_access_allowed() {
\Drupal::moduleHandler()->load('system');
\Drupal::moduleHandler()->load('user');
+// Initialize the language system.
+drupal_language_initialize();
+
// Initialize the maintenance theme for this administrative script.
drupal_maintenance_theme();
diff --git a/core/core.libraries.yml b/core/core.libraries.yml
index d2c35b9..bc3cb37 100644
--- a/core/core.libraries.yml
+++ b/core/core.libraries.yml
@@ -25,7 +25,8 @@ ckeditor:
domready:
remote: https://github.com/ded/domready
- version: 1.0.4
+ # @todo Stable release required for Drupal 8.0.
+ version: master
js:
assets/vendor/domready/ready.min.js: { weight: -21 }
@@ -280,7 +281,7 @@ html5shiv:
remote: https://github.com/aFarkas/html5shiv
version: 3.6.2
js:
- assets/vendor/html5shiv/html5.js: { every_page: true, weight: -22, browsers: { IE: 'lte IE 8', '!IE': false } }
+ assets/vendor/html5shiv/html5.js: { weight: -22, browsers: { IE: 'lte IE 8', '!IE': false } }
jquery:
remote: https://github.com/jquery/jquery
diff --git a/core/core.services.yml b/core/core.services.yml
index ac24e17..c158be4 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -18,6 +18,7 @@ services:
class: Drupal\Core\Cache\CacheBackendInterface
tags:
- { name: cache.bin }
+ - { name: persist }
factory_method: get
factory_service: cache_factory
arguments: [config]
@@ -73,9 +74,12 @@ services:
config.storage:
class: Drupal\Core\Config\CachedStorage
arguments: ['@config.cachedstorage.storage', '@cache.config']
+ tags:
+ - { name: persist }
config.factory:
class: Drupal\Core\Config\ConfigFactory
tags:
+ - { name: persist }
- { name: event_subscriber }
arguments: ['@config.storage', '@event_dispatcher', '@config.typed']
config.installer:
@@ -130,6 +134,8 @@ services:
state:
class: Drupal\Core\KeyValueStore\State
arguments: ['@keyvalue']
+ tags:
+ - { name: persist }
queue:
class: Drupal\Core\Queue\QueueFactory
arguments: ['@settings']
@@ -177,9 +183,6 @@ services:
default_plugin_manager:
abstract: true
arguments: ['@container.namespaces', '@cache.cache', '@language_manager', '@module_handler']
- module_handler:
- class: Drupal\Core\Extension\CachedModuleHandler
- arguments: ['%container.modules%', '@state', '@cache.bootstrap']
theme_handler:
class: Drupal\Core\Extension\ThemeHandler
arguments: ['@config.factory', '@module_handler', '@cache.cache', '@info_parser', '@config.installer', '@router.builder']
@@ -608,9 +611,13 @@ services:
image.toolkit.manager:
class: Drupal\Core\ImageToolkit\ImageToolkitManager
arguments: ['@container.namespaces', '@cache.cache', '@language_manager', '@config.factory', '@module_handler']
+ image.toolkit:
+ class: Drupal\Core\ImageToolkit\ImageToolkitInterface
+ factory_method: getDefaultToolkit
+ factory_service: image.toolkit.manager
image.factory:
class: Drupal\Core\Image\ImageFactory
- arguments: ['@image.toolkit.manager']
+ arguments: ['@image.toolkit']
breadcrumb:
class: Drupal\Core\Breadcrumb\BreadcrumbManager
arguments: ['@module_handler']
diff --git a/core/includes/ajax.inc b/core/includes/ajax.inc
index 7a98472..59941a0 100644
--- a/core/includes/ajax.inc
+++ b/core/includes/ajax.inc
@@ -332,8 +332,8 @@ function ajax_pre_render_element($element) {
// Attach JavaScript settings to the element.
if (isset($element['#ajax']['event'])) {
- $element['#attached']['library'][] = 'core/jquery.form';
- $element['#attached']['library'][] = 'core/drupal.ajax';
+ $element['#attached']['library'][] = array('core', 'jquery.form');
+ $element['#attached']['library'][] = array('core', 'drupal.ajax');
$settings = $element['#ajax'];
diff --git a/core/includes/batch.inc b/core/includes/batch.inc
index daa7b2f..d78248d 100644
--- a/core/includes/batch.inc
+++ b/core/includes/batch.inc
@@ -47,38 +47,42 @@ function _batch_page(Request $request) {
// Register database update for the end of processing.
drupal_register_shutdown_function('_batch_shutdown');
- $build = array();
-
// Add batch-specific CSS.
+ $attached = array('#attached' => array('css' => array()));
foreach ($batch['sets'] as $batch_set) {
if (isset($batch_set['css'])) {
foreach ($batch_set['css'] as $css) {
- $build['#attached']['css'][$css] = array();
+ $attached['#attached']['css'][$css] = array();
}
}
}
+ drupal_render($attached);
$op = $request->get('op', '');
+ $output = NULL;
switch ($op) {
case 'start':
- case 'do_nojs':
// Display the full progress page on startup and on each additional
// non-JavaScript iteration.
- $current_set = _batch_current_set();
- $build['#title'] = $current_set['title'];
- $build['content'] = _batch_progress_page();
+ $output = _batch_progress_page();
break;
case 'do':
// JavaScript-based progress page callback.
- return _batch_do();
+ $output = _batch_do();
+ break;
+
+ case 'do_nojs':
+ // Non-JavaScript-based progress page.
+ $output = _batch_progress_page();
+ break;
case 'finished':
- // _batch_finished() returns a RedirectResponse.
- return _batch_finished();
+ $output = _batch_finished();
+ break;
}
- return $build;
+ return $output;
}
/**
@@ -103,6 +107,7 @@ function _batch_progress_page() {
$batch = &batch_get();
$current_set = _batch_current_set();
+ drupal_set_title($current_set['title'], PASS_THROUGH);
$new_op = 'do_nojs';
@@ -123,7 +128,6 @@ function _batch_progress_page() {
$fallback = $current_set['error_message'] . '
' . $batch['error_message'];
$fallback = array(
'#theme' => 'maintenance_page',
- '#title' => $current_set['title'],
'#content' => $fallback,
'#show_messages' => FALSE,
);
@@ -187,11 +191,11 @@ function _batch_progress_page() {
),
),
'library' => array(
- 'core/drupal.batch',
+ array('core', 'drupal.batch'),
),
),
);
- return $build;
+ return drupal_render($build);
}
/**
diff --git a/core/includes/bootstrap.inc b/core/includes/bootstrap.inc
index 7962015..222ac0c 100644
--- a/core/includes/bootstrap.inc
+++ b/core/includes/bootstrap.inc
@@ -184,6 +184,13 @@
define('REQUEST_TIME', (int) $_SERVER['REQUEST_TIME']);
/**
+ * Flag for drupal_set_title(); text has already been sanitized.
+ *
+ * @todo Move to the Title class.
+ */
+const PASS_THROUGH = -1;
+
+/**
* Regular expression to match PHP function names.
*
* @see http://php.net/manual/language.functions.php
@@ -341,6 +348,75 @@ function config_get_config_directory($type = CONFIG_ACTIVE_DIRECTORY) {
}
/**
+ * Sets appropriate server variables needed for command line scripts to work.
+ *
+ * This function can be called by command line scripts before bootstrapping
+ * Drupal, to ensure that the page loads with the desired server parameters.
+ * This is because many parts of Drupal assume that they are running in a web
+ * browser and therefore use information from the global PHP $_SERVER variable
+ * that does not get set when Drupal is run from the command line.
+ *
+ * In many cases, the default way in which this function populates the $_SERVER
+ * variable is sufficient, and it can therefore be called without passing in
+ * any input. However, command line scripts running on a multisite installation
+ * (or on any installation that has settings.php stored somewhere other than
+ * the sites/default folder) need to pass in the URL of the site to allow
+ * Drupal to detect the correct location of the settings.php file. Passing in
+ * the 'url' parameter is also required for functions like request_uri() to
+ * return the expected values.
+ *
+ * Most other parameters do not need to be passed in, but may be necessary in
+ * some cases; for example, if \Drupal::request()->getClientIP()
+ * needs to return anything but the standard localhost value ('127.0.0.1'),
+ * the command line script should pass in the desired value via the
+ * 'REMOTE_ADDR' key.
+ *
+ * @param $variables
+ * (optional) An associative array of variables within
+ * \Drupal::request()->server that should be replaced. If the special element
+ * 'url' is provided in this array, it will be used to populate some of the
+ * server defaults; it should be set to the URL of the current page request,
+ * excluding any GET request but including the script name
+ * (e.g., http://www.example.com/mysite/index.php).
+ *
+ * @see conf_path()
+ * @see request_uri()
+ * @see \Symfony\Component\HttpFoundation\Request::getClientIP()
+ */
+function drupal_override_server_variables($variables = array()) {
+ $request = \Drupal::request();
+ $server_vars = $request->server->all();
+ // Allow the provided URL to override any existing values in $_SERVER.
+ if (isset($variables['url'])) {
+ $url = parse_url($variables['url']);
+ if (isset($url['host'])) {
+ $server_vars['HTTP_HOST'] = $url['host'];
+ }
+ if (isset($url['path'])) {
+ $server_vars['SCRIPT_NAME'] = $url['path'];
+ }
+ unset($variables['url']);
+ }
+ // Define default values for $_SERVER keys. These will be used if $_SERVER
+ // does not already define them and no other values are passed in to this
+ // function.
+ $defaults = array(
+ 'HTTP_HOST' => 'localhost',
+ 'SCRIPT_NAME' => NULL,
+ 'REMOTE_ADDR' => '127.0.0.1',
+ 'REQUEST_METHOD' => 'GET',
+ 'SERVER_NAME' => NULL,
+ 'SERVER_SOFTWARE' => NULL,
+ 'HTTP_USER_AGENT' => NULL,
+ );
+ // Replace elements of the $_SERVER array, as appropriate.
+ $request->server->replace($variables + $server_vars + $defaults);
+
+ // @todo remove once conf_path() no longer uses $_SERVER.
+ $_SERVER = $request->server->all();
+}
+
+/**
* Initializes the PHP environment.
*/
function drupal_environment_initialize() {
@@ -1324,6 +1400,46 @@ function drupal_get_messages($type = NULL, $clear_queue = TRUE) {
}
/**
+ * Gets the title of the current page.
+ *
+ * The title is displayed on the page and in the title bar.
+ *
+ * @return
+ * The current page's title.
+ */
+function drupal_get_title() {
+ return drupal_set_title() ?: '';
+}
+
+/**
+ * Sets the title of the current page.
+ *
+ * The title is displayed on the page and in the title bar.
+ *
+ * @param $title
+ * Optional string value to assign to the page title; or if set to NULL
+ * (default), leaves the current title unchanged.
+ * @param $output
+ * Optional flag - normally should be left as Title::CHECK_PLAIN. Only set to
+ * PASS_THROUGH if you have already removed any possibly dangerous code
+ * from $title using a function like
+ * \Drupal\Component\Utility\String::checkPlain() or filter_xss(). With this
+ * flag the string will be passed through unchanged.
+ *
+ * @return
+ * The updated title of the current page.
+ */
+function drupal_set_title($title = NULL, $output = Title::CHECK_PLAIN) {
+ $stored_title = &drupal_static(__FUNCTION__);
+
+ if (isset($title)) {
+ $stored_title = ($output == PASS_THROUGH) ? $title : String::checkPlain($title);
+ }
+
+ return $stored_title;
+}
+
+/**
* Generates a default anonymous $user object.
*
* @return \Drupal\Core\Session\AccountInterface
@@ -1893,6 +2009,15 @@ function drupal_installation_attempted() {
}
/**
+ * Initializes all the defined language types and sets the default langcode.
+ */
+function drupal_language_initialize() {
+ $language_manager = \Drupal::languageManager();
+ $language_manager->init();
+ \Drupal::translation()->setDefaultLangcode($language_manager->getCurrentLanguage()->id);
+}
+
+/**
* Returns the language object for a given language type.
*
* @see \Drupal\Core\Language\LanguageManager
diff --git a/core/includes/common.inc b/core/includes/common.inc
index d18c0c1..57095f7 100644
--- a/core/includes/common.inc
+++ b/core/includes/common.inc
@@ -2457,7 +2457,7 @@ function drupal_pre_render_scripts($elements) {
* FALSE if there were any missing library dependencies; TRUE if all library
* dependencies were met.
*
- * @see _drupal_add_library()
+ * @see drupal_add_library()
* @see _drupal_add_js()
* @see _drupal_add_css()
* @see drupal_render()
@@ -2473,7 +2473,7 @@ function drupal_process_attached($elements, $dependency_check = FALSE) {
// Add the libraries first.
$success = TRUE;
foreach ($elements['#attached']['library'] as $library) {
- if (_drupal_add_library($library) === FALSE) {
+ if (drupal_add_library($library[0], $library[1]) === FALSE) {
$success = FALSE;
// Exit if the dependency is missing.
if ($dependency_check) {
@@ -2641,7 +2641,7 @@ function drupal_process_attached($elements, $dependency_check = FALSE) {
* @see form_example_states_form()
*/
function drupal_process_states(&$elements) {
- $elements['#attached']['library'][] = 'core/drupal.states';
+ $elements['#attached']['library'][] = array('core', 'drupal.states');
// Elements of '#type' => 'item' are not actual form input elements, but we
// still want to be able to show/hide them. Since there's no actual HTML input
// element available, setting #attributes does not make sense, but a wrapper
@@ -2660,7 +2660,9 @@ function drupal_process_states(&$elements) {
* depending module, without having to add all files of the library separately.
* Each library is only loaded once.
*
- * @param $library_name
+ * @param $module
+ * The name of the module that registered the library.
+ * @param $name
* The name of the library to add.
* @param $every_page
* Set to TRUE if this library is added to every page on the site.
@@ -2672,16 +2674,15 @@ function drupal_process_states(&$elements) {
* @see drupal_get_library()
* @see hook_library_info_alter()
*/
-function _drupal_add_library($library_name, $every_page = NULL) {
+function drupal_add_library($module, $name, $every_page = NULL) {
$added = &drupal_static(__FUNCTION__, array());
- list($extension, $name) = explode('/', $library_name, 2);
// Only process the library if it exists and it was not added already.
- if (!isset($added[$extension][$name])) {
- if ($library = drupal_get_library($library_name)) {
+ if (!isset($added[$module][$name])) {
+ if ($library = drupal_get_library($module, $name)) {
// Allow modules and themes to dynamically attach request and context
// specific data for this library; e.g., localization.
- \Drupal::moduleHandler()->alter('library', $library, $library_name);
+ \Drupal::moduleHandler()->alter('library', $library, $module, $name);
// Add all components within the library.
$elements['#attached'] = array(
@@ -2698,15 +2699,15 @@ function _drupal_add_library($library_name, $every_page = NULL) {
}
}
- $added[$extension][$name] = drupal_process_attached($elements, TRUE);
+ $added[$module][$name] = drupal_process_attached($elements, TRUE);
}
else {
// Requested library does not exist.
- $added[$extension][$name] = FALSE;
+ $added[$module][$name] = FALSE;
}
}
- return $added[$extension][$name];
+ return $added[$module][$name];
}
/**
@@ -2722,27 +2723,26 @@ function _drupal_add_library($library_name, $every_page = NULL) {
* - Two (or more) modules can still register the same library and use it
* without conflicts in case the libraries are loaded on certain pages only.
*
- * @param $library_name
- * The name of a registered library to retrieve. By default, all
- * libraries registered by the extension are returned.
+ * @param $extension
+ * The name of the extension that registered a library.
+ * @param $name
+ * (optional) The name of a registered library to retrieve. By default, all
+ * libraries registered by $extension are returned.
*
* @return
* The definition of the requested library, if $name was passed and it exists,
* or FALSE if it does not exist. If no $name was passed, an associative array
- * of libraries registered by the module is returned (which may be empty).
+ * of libraries registered by $extension is returned (which may be empty).
*
- * @see _drupal_add_library()
+ * @see drupal_add_library()
* @see hook_library_info_alter()
*
* @todo The purpose of drupal_get_*() is completely different to other page
* requisite API functions; find and use a different name.
*/
-function drupal_get_library($library_name) {
+function drupal_get_library($extension, $name = NULL) {
$libraries = &drupal_static(__FUNCTION__, array());
- $library_info = explode('/', $library_name, 2);
- $extension = $library_info[0];
- $name = isset($library_info[1]) ? $library_info[1] : NULL;
if (!isset($libraries[$extension]) && ($cache = \Drupal::cache()->get('library:info:' . $extension))) {
$libraries[$extension] = $cache->data;
}
@@ -2875,6 +2875,13 @@ function drupal_get_library($library_name) {
);
unset($library['settings']);
}
+ // @todo Convert all uses of #attached[library][]=array('provider','name')
+ // into #attached[library][]='provider/name' and remove this.
+ foreach ($library['dependencies'] as $i => $dependency) {
+ if (!is_array($dependency)) {
+ $library['dependencies'][$i] = explode('/', $dependency, 2);
+ }
+ }
}
\Drupal::cache()->set('library:info:' . $extension, $libraries[$extension], Cache::PERMANENT, array(
'extension' => array(TRUE, $extension),
@@ -3039,7 +3046,7 @@ function drupal_attach_tabledrag(&$element, array $options) {
'limit' => $options['limit'],
);
- $element['#attached']['library'][] = 'core/drupal.tabledrag';
+ $element['#attached']['library'][] = array('core', 'drupal.tabledrag');
$element['#attached']['js'][] = array('data' => $settings, 'type' => 'setting');
}
@@ -3203,6 +3210,10 @@ function _drupal_bootstrap_full($skip = FALSE) {
return;
}
+ // Initialize language (which can strip path prefix) prior to initializing
+ // current_path().
+ drupal_language_initialize();
+
// Let all modules take action before the menu system handles the request.
// We do not want this while running update.php.
if (!defined('MAINTENANCE_MODE') || MAINTENANCE_MODE != 'update') {
@@ -3587,7 +3598,7 @@ function drupal_pre_render_links($element) {
* Pre-render callback: Attaches the dropbutton library and required markup.
*/
function drupal_pre_render_dropbutton($element) {
- $element['#attached']['library'][] = 'core/drupal.dropbutton';
+ $element['#attached']['library'][] = array('core', 'drupal.dropbutton');
$element['#attributes']['class'][] = 'dropbutton';
if (!isset($element['#theme_wrappers'])) {
$element['#theme_wrappers'] = array();
@@ -3894,12 +3905,6 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
drupal_process_states($elements);
}
- // Add additional libraries, CSS, JavaScript and other custom
- // attached data associated with this element.
- if (!empty($elements['#attached'])) {
- drupal_process_attached($elements);
- }
-
// Get the children of the element, sorted by weight.
$children = Element::children($elements, TRUE);
@@ -3945,6 +3950,12 @@ function drupal_render(&$elements, $is_recursive_call = FALSE) {
$elements['#children'] = $elements['#markup'] . $elements['#children'];
}
+ // Add additional libraries, CSS, JavaScript an other custom
+ // attached data associated with this element.
+ if (!empty($elements['#attached'])) {
+ drupal_process_attached($elements);
+ }
+
// Let the theme functions in #theme_wrappers add markup around the rendered
// children.
// #states and #attached have to be processed before #theme_wrappers, because
@@ -4560,7 +4571,7 @@ function drupal_render_cache_by_query($query, $function, $expire = Cache::PERMAN
* $granularity was passed in, more parts are added.
*/
function drupal_render_cid_parts($granularity = NULL) {
- global $theme, $base_root;
+ global $theme, $base_root, $user;
$cid_parts[] = $theme;
@@ -4577,10 +4588,10 @@ function drupal_render_cid_parts($granularity = NULL) {
// resource drag for sites with many users, so when a module is being
// equivocal, we favor the less expensive 'PER_ROLE' pattern.
if ($granularity & DRUPAL_CACHE_PER_ROLE) {
- $cid_parts[] = 'r.' . implode(',', \Drupal::currentUser()->getRoles());
+ $cid_parts[] = 'r.' . implode(',', $user->getRoles());
}
elseif ($granularity & DRUPAL_CACHE_PER_USER) {
- $cid_parts[] = 'u.' . \Drupal::currentUser()->id();
+ $cid_parts[] = 'u.' . $user->id();
}
if ($granularity & DRUPAL_CACHE_PER_PAGE) {
diff --git a/core/includes/entity.inc b/core/includes/entity.inc
index 51b0f79..fa5f370 100644
--- a/core/includes/entity.inc
+++ b/core/includes/entity.inc
@@ -241,7 +241,11 @@ function entity_revision_delete($entity_type, $revision_id) {
function entity_load_by_uuid($entity_type_id, $uuid, $reset = FALSE) {
$entity_type = \Drupal::entityManager()->getDefinition($entity_type_id);
- if (!$uuid_key = $entity_type->getKey('uuid')) {
+ // Configuration entities do not use annotations to set the UUID key.
+ if ($entity_type->isSubclassOf('Drupal\Core\Config\Entity\ConfigEntityInterface')) {
+ $uuid_key = 'uuid';
+ }
+ elseif (!$uuid_key = $entity_type->getKey('uuid')) {
throw new EntityStorageException("Entity type $entity_type_id does not support UUIDs.");
}
diff --git a/core/includes/errors.inc b/core/includes/errors.inc
index 56c276f..761b7bd 100644
--- a/core/includes/errors.inc
+++ b/core/includes/errors.inc
@@ -218,22 +218,19 @@ function _drupal_log_error($error, $fatal = FALSE) {
}
if ($fatal) {
+ // Should not translate the string to avoid errors producing more errors.
+ drupal_set_title('Error');
// We fallback to a maintenance page at this point, because the page generation
// itself can generate errors.
// Should not translate the string to avoid errors producing more errors.
$message = 'The website has encountered an error. Please try again later.';
if ($is_installer) {
// install_display_output() prints the output and ends script execution.
- $output = array(
- '#title' => 'Error',
- '#markup' => $message,
- );
- install_display_output($output, $GLOBALS['install_state']);
+ install_display_output($message, $GLOBALS['install_state']);
}
else {
$output = array(
'#theme' => 'maintenance_page',
- '#title' => 'Error',
'#content' => $message,
);
$output = drupal_render($output);
diff --git a/core/includes/form.inc b/core/includes/form.inc
index f4a7718..20edb53 100644
--- a/core/includes/form.inc
+++ b/core/includes/form.inc
@@ -9,7 +9,6 @@
use Drupal\Component\Utility\Number;
use Drupal\Component\Utility\String;
use Drupal\Component\Utility\UrlHelper;
-use Drupal\Component\Utility\Xss;
use Drupal\Core\Database\Database;
use Drupal\Core\Language\Language;
use Drupal\Core\Template\Attribute;
@@ -877,9 +876,7 @@ function form_process_select($element) {
}
/**
- * Prepares variables for select element templates.
- *
- * Default template: select.html.twig.
+ * Returns HTML for a select form element.
*
* It is possible to group options together; to do this, change the format of
* $options to an associative array in which the keys are group labels, and the
@@ -890,14 +887,15 @@ function form_process_select($element) {
* - element: An associative array containing the properties of the element.
* Properties used: #title, #value, #options, #description, #extra,
* #multiple, #required, #name, #attributes, #size.
+ *
+ * @ingroup themeable
*/
-function template_preprocess_select(&$variables) {
+function theme_select($variables) {
$element = $variables['element'];
element_set_attributes($element, array('id', 'name', 'size'));
_form_set_attributes($element, array('form-select'));
- $variables['attributes'] = $element['#attributes'];
- $variables['options'] = form_select_options($element);
+ return '';
}
/**
@@ -1002,59 +1000,68 @@ function form_get_options($element, $key) {
}
/**
- * Prepares variables for fieldset element templates.
- *
- * Default template: fieldset.html.twig.
+ * Returns HTML for a fieldset form element and its children.
*
- * @param array $variables
+ * @param $variables
* An associative array containing:
* - element: An associative array containing the properties of the element.
- * Properties used: #attributes, #children, #description, #id, #title,
- * #value.
+ * Properties used: #attributes, #children, #description, #id,
+ * #title, #value.
+ *
+ * @ingroup themeable
*/
-function template_preprocess_fieldset(&$variables) {
+function theme_fieldset($variables) {
$element = $variables['element'];
element_set_attributes($element, array('id'));
_form_set_attributes($element, array('form-wrapper'));
- $variables['attributes'] = $element['#attributes'];
- $variables['attributes']['class'][] = 'form-item';
+
+ $element['#attributes']['class'][] = 'form-item';
+
+ if (!empty($element['#description'])) {
+ $description_id = $element['#attributes']['id'] . '--description';
+ $element['#attributes']['aria-describedby'] = $description_id;
+ }
// If the element is required, a required marker is appended to the label.
- $variables['required'] = '';
+ // @see theme_form_element_label()
+ $required = '';
if (!empty($element['#required'])) {
- $variables['required'] = array(
+ $marker = array(
'#theme' => 'form_required_marker',
'#element' => $element,
);
+ $required = drupal_render($marker);
}
- $variables['prefix'] = isset($element['#field_prefix']) ? $element['#field_prefix'] : NULL;
- $variables['suffix'] = isset($element['#field_suffix']) ? $element['#field_suffix'] : NULL;
- $variables['children'] = $element['#children'];
-
- // Build legend properties.
- $variables['legend'] = array();
$legend_attributes = array();
if (isset($element['#title_display']) && $element['#title_display'] == 'invisible') {
$legend_attributes['class'][] = 'visually-hidden';
}
- $variables['legend']['attributes'] = new Attribute($legend_attributes);
- $variables['legend']['title'] = (isset($element['#title']) && $element['#title'] !== '') ? Xss::filterAdmin($element['#title']) : '';
- // Build description properties.
- $variables['description'] = array();
- if (!empty($element['#description'])) {
- $description_id = $element['#attributes']['id'] . '--description';
- $description_attributes = array(
- 'class' => 'description',
- 'id' => $description_id,
- );
- $variables['description']['attributes'] = new Attribute($description_attributes);
- $variables['description']['content'] = $element['#description'];
+ $output = '
' . t('Congratulations, you installed @drupal!', array('@drupal' => drupal_install_profile_distribution_name())) . '
'; // Ensure the URL that is generated for the home page does not have 'install.php' @@ -2047,11 +2197,7 @@ function install_finished(&$install_state) { $snapshot = \Drupal::service('config.storage.snapshot'); \Drupal::service('config.manager')->createSnapshot($active, $snapshot); - $build = array( - '#title' => t('@drupal installation complete', array('@drupal' => drupal_install_profile_distribution_name())), - '#markup' => $output, - ); - return $build; + return $output; } /** @@ -2379,7 +2525,7 @@ function install_check_requirements($install_state) { * in the URL. Otherwise, no output is returned, so that the next task can be * run in the same page request. * - * @throws \Drupal\Core\Installer\Exception\InstallerException + * @thows \Exception */ function install_display_requirements($install_state, $requirements) { // Check the severity of the requirements reported. @@ -2390,13 +2536,14 @@ function install_display_requirements($install_state, $requirements) { // and indicating a desire to continue anyway. See drupal_requirements_url(). if ($severity == REQUIREMENT_ERROR || ($severity == REQUIREMENT_WARNING && empty($install_state['parameters']['continue']))) { if ($install_state['interactive']) { - $build['#title'] = t('Requirements problem'); - $build['report'] = array( + drupal_set_title(t('Requirements problem')); + $status_report = array( '#theme' => 'status_report', '#requirements' => $requirements, - '#suffix' => t('Check the messages and try again.', array('!url' => check_url(drupal_requirements_url($severity)))), ); - return $build; + $status_report = drupal_render($status_report); + $status_report .= t('Check the messages and try again.', array('!url' => check_url(drupal_requirements_url($severity)))); + return $status_report; } else { // Throw an exception showing any unmet requirements. @@ -2410,7 +2557,7 @@ function install_display_requirements($install_state, $requirements) { } } if (!empty($failures)) { - throw new InstallerException(implode("\n\n", $failures)); + throw new \Exception(implode("\n\n", $failures)); } } } @@ -2578,7 +2725,7 @@ function install_configure_form_submit($form, &$form_state) { $account->pass = $form_state['values']['account']['pass']; $account->name = $form_state['values']['account']['name']; $account->save(); - // Load current user and perform final login tasks. + // Load global $user and perform final login tasks. $account = user_load(1); user_login_finalize($account); diff --git a/core/includes/install.inc b/core/includes/install.inc index c2a138c..74d8e39 100644 --- a/core/includes/install.inc +++ b/core/includes/install.inc @@ -573,7 +573,9 @@ function drupal_verify_profile($install_state) { include_once __DIR__ . '/common.inc'; $profile = $install_state['parameters']['profile']; - if (!isset($profile) || !isset($install_state['profiles'][$profile])) { + $profile_file = $install_state['profiles'][$profile]->uri; + + if (!isset($profile) || !file_exists($profile_file)) { throw new Exception(install_no_profile_error()); } $info = $install_state['profile_info']; @@ -582,7 +584,7 @@ function drupal_verify_profile($install_state) { $listing = new ExtensionDiscovery(); $present_modules = array(); foreach ($listing->scan('module') as $present_module) { - $present_modules[] = $present_module->getName(); + $present_modules[] = $present_module->name; } // The installation profile is also a module, which needs to be installed @@ -623,16 +625,19 @@ function drupal_install_system($install_state) { // Create tables. drupal_install_schema('system'); - // Immediately boot a new kernel into the regular production environment. - $request = \Drupal::hasRequest() ? \Drupal::request() : FALSE; - - unset($GLOBALS['conf']['container_service_providers']['InstallerServiceProvider']); - $kernel = new DrupalKernel('prod', drupal_classloader(), FALSE); - $kernel->boot(); + if (!\Drupal::hasService('kernel')) { + // Immediately boot a kernel to have real services ready. If there's already + // an initialized request object in the pre-kernel container, persist it in + // the post-kernel container. + if (\Drupal::getContainer()->initialized('request')) { + $request = \Drupal::request(); + } + $kernel = new DrupalKernel('install', drupal_classloader(), FALSE); + $kernel->boot(); + if (isset($request)) { + \Drupal::getContainer()->set('request', $request); + } - if ($request) { - $kernel->getContainer()->enterScope('request'); - $kernel->getContainer()->set('request', $request, 'request'); } $system_path = drupal_get_path('module', 'system'); diff --git a/core/includes/menu.inc b/core/includes/menu.inc index 838b32a..a1c8a01 100644 --- a/core/includes/menu.inc +++ b/core/includes/menu.inc @@ -342,7 +342,7 @@ function menu_tree($menu_name) { } /** - * Returns an output structure for rendering a menu tree. + * Returns a rendered menu tree. * * The menu item's LI element is given one of the following classes: * - expanded: The menu item is showing its submenu. diff --git a/core/includes/module.inc b/core/includes/module.inc index 7bb0e3e..e412598 100644 --- a/core/includes/module.inc +++ b/core/includes/module.inc @@ -63,7 +63,7 @@ function system_list($type) { $lists['filepaths'][] = array( 'type' => 'theme', 'name' => $name, - 'filepath' => $theme->getPathname(), + 'filepath' => $theme->filename, ); } } diff --git a/core/includes/tablesort.inc b/core/includes/tablesort.inc index cd5c0c1..5b1440c 100644 --- a/core/includes/tablesort.inc +++ b/core/includes/tablesort.inc @@ -9,7 +9,7 @@ * @file * Functions to aid in the creation of sortable tables. * - * All tables created when rendering a '#type' => 'table' have the option of + * All tables created when rendering a '#theme' => 'table' have the option of * having column headers that the user can click on to sort the table by that * column. */ @@ -33,7 +33,7 @@ function tablesort_init($header) { * @param $cell * The cell to format. * @param $header - * An array of column headers in the format described in '#type' => 'table'. + * An array of column headers in the format described in '#theme' => 'table'. * @param $ts * The current table sort context as returned from tablesort_init(). * @@ -77,7 +77,7 @@ function tablesort_header($cell, $header, $ts) { * @param $cell * The cell to format. * @param $header - * An array of column headers in the format described in '#type' => 'table'. + * An array of column headers in the format described in '#theme' => 'table'. * @param $ts * The current table sort context as returned from tablesort_init(). * @param $i @@ -113,7 +113,7 @@ function tablesort_get_query_parameters() { * Determines the current sort criterion. * * @param $headers - * An array of column headers in the format described in '#type' => 'table'. + * An array of column headers in the format described in '#theme' => 'table'. * * @return * An associative array describing the criterion, containing the keys: @@ -150,7 +150,7 @@ function tablesort_get_order($headers) { * Determines the current sort direction. * * @param $headers - * An array of column headers in the format described in '#type' => 'table'. + * An array of column headers in the format described in '#theme' => 'table'. * * @return * The current sort direction ("asc" or "desc"). diff --git a/core/includes/theme.inc b/core/includes/theme.inc index bbeb9cb..1526113 100644 --- a/core/includes/theme.inc +++ b/core/includes/theme.inc @@ -79,7 +79,7 @@ */ function drupal_theme_access($theme) { if ($theme instanceof Extension) { - $theme = $theme->getName(); + $theme = $theme->name; } return \Drupal::service('access_check.theme')->checkAccess($theme); } @@ -88,7 +88,7 @@ function drupal_theme_access($theme) { * Initializes the theme system by loading the theme. */ function drupal_theme_initialize() { - global $theme, $theme_key; + global $theme, $user, $theme_key; // If $theme is already set, assume the others are set, too, and do nothing if (isset($theme)) { @@ -135,7 +135,7 @@ function _drupal_theme_initialize($theme, $base_theme = array()) { $theme_info = $theme; $base_theme_info = $base_theme; - $theme_path = $theme->getPath(); + $theme_path = dirname($theme->filename); // Prepare stylesheets from this theme as well as all ancestor themes. // We work it this way so that we can have child themes override parent @@ -155,7 +155,7 @@ function _drupal_theme_initialize($theme, $base_theme = array()) { } } } - $base_theme_path = $base->getPath(); + $base_theme_path = dirname($base->filename); if (!empty($base->info['stylesheets-remove'])) { foreach ($base->info['stylesheets-remove'] as $basename) { $theme->stylesheets_remove[$basename] = $base_theme_path . '/' . $basename; @@ -340,23 +340,87 @@ function list_themes($refresh = FALSE) { } /** - * Generates themed output (internal use only). - * - * _theme() is an internal function. Do not call this function directly as it - * will prevent the following items from working correctly: - * - Render caching. - * - JavaScript and CSS asset attachment. - * - Pre / post render hooks. - * - Defaults provided by hook_element_info(), including attached assets. - * Instead, build a render array with a #theme key, and either return the - * array (where possible) or call drupal_render() to convert it to HTML. - * - * All requests for themed output must go through this function, which is - * invoked as part of the @link theme_render drupal_render() process @endlink. - * The appropriate theme function is indicated by the #theme property - * of a renderable array. _theme() examines the request and routes it to the - * appropriate @link themeable theme function or template @endlink, by checking - * the theme registry. + * Generates themed output. + * + * All requests for themed output must go through this function (however, + * calling the _theme() function directly is very strongly discouraged - see + * next paragraph). It examines the request and routes it to the appropriate + * @link themeable theme function or template @endlink, by checking the theme + * registry. + * + * Avoid calling this function directly. It is preferable to replace direct + * calls to the _theme() function with calls to drupal_render() by passing a + * render array with a #theme key to drupal_render(), which in turn calls + * _theme(). + * + * @section sec_theme_hooks Theme Hooks + * Most commonly, the first argument to this function is the name of the theme + * hook. For instance, to theme a taxonomy term, the theme hook name is + * 'taxonomy_term'. Modules register theme hooks within a hook_theme() + * implementation and provide a default implementation via a function named + * theme_HOOK() (e.g., theme_taxonomy_term()) or via a template file named + * according to the value of the 'template' key registered with the theme hook + * (see hook_theme() for details). Default templates are implemented with the + * Twig rendering engine and are named the same as the theme hook, with + * underscores changed to hyphens, so for the 'taxonomy_term' theme hook, the + * default template is 'taxonomy-term.html.twig'. + * + * @subsection sub_overriding_theme_hooks Overriding Theme Hooks + * Themes may also register new theme hooks within a hook_theme() + * implementation, but it is more common for themes to override default + * implementations provided by modules than to register entirely new theme + * hooks. Themes can override a default implementation by implementing a + * function named THEME_HOOK() (for example, the 'bartik' theme overrides the + * default implementation of the 'menu_tree' theme hook by implementing a + * bartik_menu_tree() function), or by adding a template file within its folder + * structure that follows the template naming structure used by the theme's + * rendering engine (for example, since the Bartik theme uses the Twig rendering + * engine, it overrides the default implementation of the 'page' theme hook by + * containing a 'page.html.twig' file within its folder structure). + * + * @subsection sub_preprocess_templates Preprocessing for Template Files + * If the implementation is a template file, several functions are called before + * the template file is invoked to modify the $variables array. These make up + * the "preprocessing" phase, and are executed (if they exist), in the following + * order (note that in the following list, HOOK indicates the theme hook name, + * MODULE indicates a module name, THEME indicates a theme name, and ENGINE + * indicates a theme engine name): + * - template_preprocess(&$variables, $hook): Creates a default set of variables + * for all theme hooks with template implementations. + * - template_preprocess_HOOK(&$variables): Should be implemented by the module + * that registers the theme hook, to set up default variables. + * - MODULE_preprocess(&$variables, $hook): hook_preprocess() is invoked on all + * implementing modules. + * - MODULE_preprocess_HOOK(&$variables): hook_preprocess_HOOK() is invoked on + * all implementing modules, so that modules that didn't define the theme hook + * can alter the variables. + * - ENGINE_engine_preprocess(&$variables, $hook): Allows the theme engine to + * set necessary variables for all theme hooks with template implementations. + * - ENGINE_engine_preprocess_HOOK(&$variables): Allows the theme engine to set + * necessary variables for the particular theme hook. + * - THEME_preprocess(&$variables, $hook): Allows the theme to set necessary + * variables for all theme hooks with template implementations. + * - THEME_preprocess_HOOK(&$variables): Allows the theme to set necessary + * variables specific to the particular theme hook. + * + * @subsection sub_preprocess_theme_funcs Preprocessing for Theme Functions + * If the implementation is a function, only the theme-hook-specific preprocess + * functions (the ones ending in _HOOK) are called from the list above. This is + * because theme hooks with function implementations need to be fast, and + * calling the non-theme-hook-specific preprocess functions for them would incur + * a noticeable performance penalty. + * + * @subsection sub_alternate_suggestions Suggesting Alternate Hooks + * Alternate hooks can be suggested by implementing the hook-specific + * hook_theme_suggestions_HOOK_alter() or the generic + * hook_theme_suggestions_alter(). These alter hooks are used to manipulate an + * array of suggested alternate theme hooks to use, in reverse order of + * priority. _theme() will use the highest priority implementation that exists. + * If none exists, _theme() will use the implementation for the theme hook it + * was called with. These suggestions are similar to and are used for similar + * reasons as calling _theme() with an array as the $hook parameter (see below). + * The difference is whether the suggestions are determined by the code that + * calls _theme() or by altering the suggestions via the suggestion alter hooks. * * @param $hook * The name of the theme hook to call. If the name contains a @@ -729,7 +793,7 @@ function drupal_find_theme_templates($cache, $extension, $path) { $theme_paths = array(); foreach (list_themes() as $theme_info) { if (!empty($theme_info->base_theme)) { - $theme_paths[$theme_info->base_theme][$theme_info->getName()] = $theme_info->getPath(); + $theme_paths[$theme_info->base_theme][$theme_info->name] = dirname($theme_info->filename); } } foreach ($theme_paths as $basetheme => $subthemes) { @@ -864,17 +928,17 @@ function theme_get_setting($setting_name, $theme = NULL) { } foreach ($theme_keys as $theme_key) { if (!empty($themes[$theme_key]->info['settings'])) { - $cache[$theme]->merge($themes[$theme_key]->info['settings']); + $cache[$theme]->mergeData($themes[$theme_key]->info['settings']); } } } // Get the global settings from configuration. - $cache[$theme]->merge(\Drupal::config('system.theme.global')->get()); + $cache[$theme]->mergeData(\Drupal::config('system.theme.global')->get()); if ($theme) { // Get the saved theme-specific settings from the configuration system. - $cache[$theme]->merge(\Drupal::config($theme . '.settings')->get()); + $cache[$theme]->mergeData(\Drupal::config($theme . '.settings')->get()); // If the theme does not support a particular feature, override the global // setting and set the value to NULL. @@ -891,7 +955,7 @@ function theme_get_setting($setting_name, $theme = NULL) { if ($cache[$theme]->get('features.logo')) { $logo_path = $cache[$theme]->get('logo.path'); if ($cache[$theme]->get('logo.use_default')) { - $cache[$theme]->set('logo.url', file_create_url($theme_object->getPath() . '/logo.png')); + $cache[$theme]->set('logo.url', file_create_url(dirname($theme_object->filename) . '/logo.png')); } elseif ($logo_path) { $cache[$theme]->set('logo.url', file_create_url($logo_path)); @@ -902,7 +966,7 @@ function theme_get_setting($setting_name, $theme = NULL) { if ($cache[$theme]->get('features.favicon')) { $favicon_path = $cache[$theme]->get('favicon.path'); if ($cache[$theme]->get('favicon.use_default')) { - if (file_exists($favicon = $theme_object->getPath() . '/favicon.ico')) { + if (file_exists($favicon = dirname($theme_object->filename) . '/favicon.ico')) { $cache[$theme]->set('favicon.url', file_create_url($favicon)); } else { @@ -1352,24 +1416,6 @@ function drupal_pre_render_table(array $element) { // Take over $element['#id'] as HTML ID attribute, if not already set. element_set_attributes($element, array('id')); - - // Add sticky headers, if applicable. - if (count($element['#header']) && $element['#sticky']) { - $element['#attached']['library'][] = 'core/drupal.tableheader'; - // Add 'sticky-enabled' class to the table to identify it for JS. - // This is needed to target tables constructed by this function. - $element['#attributes']['class'][] = 'sticky-enabled'; - } - // If the table has headers and it should react responsively to columns hidden - // with the classes represented by the constants RESPONSIVE_PRIORITY_MEDIUM - // and RESPONSIVE_PRIORITY_LOW, add the tableresponsive behaviors. - if (count($element['#header']) && $element['#responsive']) { - $element['#attached']['library'][] = 'core/drupal.tableresponsive'; - // Add 'responsive-enabled' class to the table to identify it for JS. - // This is needed to target tables constructed by this function. - $element['#attributes']['class'][] = 'responsive-enabled'; - } - // If the custom #tabledrag is set and there is a HTML ID, add the table's // HTML ID to the options and attach the behavior. if (!empty($element['#tabledrag']) && isset($element['#attributes']['id'])) { @@ -1477,6 +1523,23 @@ function theme_table($variables) { $responsive = $variables['responsive']; $empty = $variables['empty']; + // Add sticky headers, if applicable. + if (count($header) && $sticky) { + drupal_add_library('core', 'drupal.tableheader'); + // Add 'sticky-enabled' class to the table to identify it for JS. + // This is needed to target tables constructed by this function. + $attributes['class'][] = 'sticky-enabled'; + } + // If the table has headers and it should react responsively to columns hidden + // with the classes represented by the constants RESPONSIVE_PRIORITY_MEDIUM + // and RESPONSIVE_PRIORITY_LOW, add the tableresponsive behaviors. + if (count($header) && $responsive) { + drupal_add_library('core', 'drupal.tableresponsive'); + // Add 'responsive-enabled' class to the table to identify it for JS. + // This is needed to target tables constructed by this function. + $attributes['class'][] = 'responsive-enabled'; + } + $output = '