- Patch #769226 by Owen Barton, sun, effulgentsia, alanburke, bleen18, mfer: optimize JS/CSS aggregation for front-end performance and DX.

merge-requests/26/head
Dries Buytaert 2010-10-05 19:59:10 +00:00
parent 0614a78538
commit facc581013
12 changed files with 236 additions and 90 deletions

View File

@ -565,7 +565,7 @@ function ajax_process_form($element, &$form_state) {
// Attach JavaScript settings to the element. // Attach JavaScript settings to the element.
if (isset($element['#ajax']['event'])) { if (isset($element['#ajax']['event'])) {
$element['#attached']['library'][] = array('system', 'form'); $element['#attached']['library'][] = array('system', 'form');
$element['#attached']['js']['misc/ajax.js'] = array('weight' => JS_LIBRARY + 2); $element['#attached']['js']['misc/ajax.js'] = array('group' => JS_LIBRARY, 'weight' => 2);
$settings = $element['#ajax']; $settings = $element['#ajax'];

View File

@ -56,33 +56,33 @@ define('SAVED_UPDATED', 2);
define('SAVED_DELETED', 3); define('SAVED_DELETED', 3);
/** /**
* The default weight of system CSS files added to the page. * The default group for system CSS files added to the page.
*/ */
define('CSS_SYSTEM', -100); define('CSS_SYSTEM', -100);
/** /**
* The default weight of CSS files added to the page. * The default group for module CSS files added to the page.
*/ */
define('CSS_DEFAULT', 0); define('CSS_DEFAULT', 0);
/** /**
* The default weight of theme CSS files added to the page. * The default group for theme CSS files added to the page.
*/ */
define('CSS_THEME', 100); define('CSS_THEME', 100);
/** /**
* The weight of JavaScript libraries, settings or jQuery plugins being * The default group for JavaScript libraries, settings or jQuery plugins added
* added to the page. * to the page.
*/ */
define('JS_LIBRARY', -100); define('JS_LIBRARY', -100);
/** /**
* The default weight of JavaScript being added to the page. * The default group for module JavaScript code added to the page.
*/ */
define('JS_DEFAULT', 0); define('JS_DEFAULT', 0);
/** /**
* The weight of theme JavaScript code being added to the page. * The default group for theme JavaScript code added to the page.
*/ */
define('JS_THEME', 100); define('JS_THEME', 100);
@ -2734,19 +2734,50 @@ function drupal_add_html_head_link($attributes, $header = FALSE) {
* 'modules/node/node.css' is 'node.css'. If the external library "node.js" * 'modules/node/node.css' is 'node.css'. If the external library "node.js"
* ships with a 'node.css', then a different, unique basename would be * ships with a 'node.css', then a different, unique basename would be
* 'node.js.css'. * 'node.js.css'.
* - 'weight': The weight of the stylesheet specifies the order in which the * - 'group': A number identifying the group in which to add the stylesheet.
* CSS will appear when presented on the page. Available constants are: * Available constants are:
* - CSS_SYSTEM: Any system-layer CSS. * - CSS_SYSTEM: Any system-layer CSS.
* - CSS_DEFAULT: Any module-layer CSS. * - CSS_DEFAULT: Any module-layer CSS.
* - CSS_THEME: Any theme-layer CSS. * - CSS_THEME: Any theme-layer CSS.
* If you need to embed a CSS file before any other module's stylesheets, * The group number serves as a weight: the markup for loading a stylesheet
* for example, you would use CSS_DEFAULT - 1. Note that inline CSS is * within a lower weight group is output to the page before the markup for
* simply appended to the end of the specified scope (region), so they * loading a stylesheet within a higher weight group, so CSS within higher
* always come last. * weight groups take precendence over CSS within lower weight groups.
* - 'every_page': For optimal front-end performance when aggregation is
* enabled, this should be set to TRUE if the stylesheet is present on every
* page of the website for users for whom it is present at all. This
* defaults to FALSE. It is set to TRUE for stylesheets added via module and
* theme .info files. Modules that add stylesheets within hook_init()
* implementations, or from other code that ensures that the stylesheet is
* added to all website pages, should also set this flag to TRUE. All
* stylesheets within the same group that have the 'every_page' flag set to
* TRUE and do not have 'preprocess' set to FALSE are aggregated together
* into a single aggregate file, and that aggregate file can be reused
* across a user's entire site visit, leading to faster navigation between
* pages. However, stylesheets that are only needed on pages less frequently
* visited, can be added by code that only runs for those particular pages,
* and that code should not set the 'every_page' flag. This minimizes the
* size of the aggregate file that the user needs to download when first
* visiting the website. Stylesheets without the 'every_page' flag are
* aggregated into a separate aggregate file. This other aggregate file is
* likely to change from page to page, and each new aggregate file needs to
* be downloaded when first encountered, so it should be kept relatively
* small by ensuring that most commonly needed stylesheets are added to
* every page.
* - 'weight': The weight of the stylesheet specifies the order in which the
* CSS will appear relative to other stylesheets with the same group and
* 'every_page' flag. The exact ordering of stylesheets is as follows:
* - First by group.
* - Then by the 'every_page' flag, with TRUE coming before FALSE.
* - Then by weight.
* - Then by the order in which the CSS was added. For example, all else
* being the same, a stylesheet added by a call to drupal_add_css() that
* happened later in the page request gets added to the page after one for
* which drupal_add_css() happened earlier in the page request.
* - 'media': The media type for the stylesheet, e.g., all, print, screen. * - 'media': The media type for the stylesheet, e.g., all, print, screen.
* Defaults to 'all'. * Defaults to 'all'.
* - 'preprocess': If TRUE and CSS aggregation/compression is enabled, the * - 'preprocess': If TRUE and CSS aggregation/compression is enabled, the
* styles will be aggregated and compressed. Defaults to FALSE. * styles will be aggregated and compressed. Defaults to TRUE.
* - 'browsers': An array containing information specifying which browsers * - 'browsers': An array containing information specifying which browsers
* should load the CSS item. See drupal_pre_render_conditional_comments() * should load the CSS item. See drupal_pre_render_conditional_comments()
* for details. * for details.
@ -2772,9 +2803,11 @@ function drupal_add_css($data = NULL, $options = NULL) {
if (isset($data)) { if (isset($data)) {
$options += array( $options += array(
'type' => 'file', 'type' => 'file',
'weight' => CSS_DEFAULT, 'group' => CSS_DEFAULT,
'weight' => 0,
'every_page' => FALSE,
'media' => 'all', 'media' => 'all',
'preprocess' => FALSE, 'preprocess' => TRUE,
'data' => $data, 'data' => $data,
'browsers' => array(), 'browsers' => array(),
); );
@ -2783,6 +2816,11 @@ function drupal_add_css($data = NULL, $options = NULL) {
'!IE' => TRUE, '!IE' => TRUE,
); );
// Files with a query string cannot be preprocessed.
if ($options['type'] === 'file' && $options['preprocess'] && strpos($options['data'], '?') !== FALSE) {
$options['preprocess'] = FALSE;
}
// Always add a tiny value to the weight, to conserve the insertion order. // Always add a tiny value to the weight, to conserve the insertion order.
$options['weight'] += count($css) / 1000; $options['weight'] += count($css) / 1000;
@ -2839,8 +2877,8 @@ function drupal_get_css($css = NULL, $skip_alter = FALSE) {
drupal_alter('css', $css); drupal_alter('css', $css);
} }
// Sort CSS items according to their weights. // Sort CSS items, so that they appear in the correct order.
uasort($css, 'drupal_sort_weight'); uasort($css, 'drupal_sort_css_js');
// Remove the overridden CSS files. Later CSS files override former ones. // Remove the overridden CSS files. Later CSS files override former ones.
$previous_item = array(); $previous_item = array();
@ -2870,6 +2908,46 @@ function drupal_get_css($css = NULL, $skip_alter = FALSE) {
return drupal_render($styles); return drupal_render($styles);
} }
/**
* Function used by uasort to sort the array structures returned by drupal_add_css() and drupal_add_js().
*
* This sort order helps optimize front-end performance while providing modules
* and themes with the necessary control for ordering the CSS and JavaScript
* appearing on a page.
*/
function drupal_sort_css_js($a, $b) {
// First order by group, so that, for example, all items in the CSS_SYSTEM
// group appear before items in the CSS_DEFAULT_GROUP, which appear before
// all items in the CSS_THEME group. Modules may create additional groups by
// defining their own constants.
if ($a['group'] < $b['group']) {
return -1;
}
elseif ($a['group'] > $b['group']) {
return 1;
}
// Within a group, order all infrequently needed, page-specific files after
// common files needed throughout the website. Separating this way allows for
// the aggregate file generated for all of the common files to be reused
// across a site visit without being cut by a page using a less common file.
elseif ($a['every_page'] && !$b['every_page']) {
return -1;
}
elseif (!$a['every_page'] && $b['every_page']) {
return 1;
}
// Finally, order by weight.
elseif ($a['weight'] < $b['weight']) {
return -1;
}
elseif ($a['weight'] > $b['weight']) {
return 1;
}
else {
return 0;
}
}
/** /**
* Default callback to group CSS items. * Default callback to group CSS items.
* *
@ -2933,7 +3011,10 @@ function drupal_group_css($css) {
switch ($item['type']) { switch ($item['type']) {
case 'file': case 'file':
// Group file items if their 'preprocess' flag is TRUE. // Group file items if their 'preprocess' flag is TRUE.
$group_keys = $item['preprocess'] ? array($item['type'], $item['media'], $item['browsers']) : FALSE; // Help ensure maximum reuse of aggregate files by only grouping
// together items that share the same 'group' value and 'every_page'
// flag. See drupal_add_css() for details about that.
$group_keys = $item['preprocess'] ? array($item['type'], $item['group'], $item['every_page'], $item['media'], $item['browsers']) : FALSE;
break; break;
case 'inline': case 'inline':
// Always group inline items. // Always group inline items.
@ -3683,27 +3764,63 @@ function drupal_region_class($region) {
* - scope: The location in which you want to place the script. Possible * - scope: The location in which you want to place the script. Possible
* values are 'header' or 'footer'. If your theme implements different * values are 'header' or 'footer'. If your theme implements different
* regions, you can also use these. Defaults to 'header'. * regions, you can also use these. Defaults to 'header'.
* - weight: A number defining the order in which the JavaScript is added to * - 'group': A number identifying the group in which to add the JavaScript.
* the page. In some cases, the order in which the JavaScript is presented * Available constants are:
* on the page is very important. jQuery, for example, must be added to
* the page before any jQuery code is run, so jquery.js uses a weight of
* JS_LIBRARY - 20, jquery.once.js (a library drupal.js depends on) uses
* a weight of JS_LIBRARY - 19, drupal.js uses a weight of JS_LIBRARY - 1,
* and all following scripts depending on jQuery and Drupal behaviors are
* simply added using the default weight of JS_DEFAULT. Available constants
* are:
* - JS_LIBRARY: Any libraries, settings, or jQuery plugins. * - JS_LIBRARY: Any libraries, settings, or jQuery plugins.
* - JS_DEFAULT: Any module-layer JavaScript. * - JS_DEFAULT: Any module-layer JavaScript.
* - JS_THEME: Any theme-layer JavaScript. * - JS_THEME: Any theme-layer JavaScript.
* If you need to invoke a JavaScript file before any other module's * The group number serves as a weight: JavaScript within a lower weight
* JavaScript, for example, you would use JS_DEFAULT - 1. * group is presented on the page before JavaScript within a higher weight
* group.
* - 'every_page': For optimal front-end performance when aggregation is
* enabled, this should be set to TRUE if the JavaScript is present on every
* page of the website for users for whom it is present at all. This
* defaults to FALSE. It is set to TRUE for JavaScript files that are added
* via module and theme .info files. Modules that add JavaScript within
* hook_init() implementations, or from other code that ensures that the
* JavaScript is added to all website pages, should also set this flag to
* TRUE. All JavaScript files within the same group and that have the
* 'every_page' flag set to TRUE and do not have 'preprocess' set to FALSE
* are aggregated together into a single aggregate file, and that aggregate
* file can be reused across a user's entire site visit, leading to faster
* navigation between pages. However, JavaScript that is only needed on
* pages less frequently visited, can be added by code that only runs for
* those particular pages, and that code should not set the 'every_page'
* flag. This minimizes the size of the aggregate file that the user needs
* to download when first visiting the website. JavaScript without the
* 'every_page' flag is aggregated into a separate aggregate file. This
* other aggregate file is likely to change from page to page, and each new
* aggregate file needs to be downloaded when first encountered, so it
* should be kept relatively small by ensuring that most commonly needed
* JavaScript is added to every page.
* - weight: A number defining the order in which the JavaScript is added to
* the page relative to other JavaScript with the same 'scope', 'group',
* and 'every_page' value. In some cases, the order in which the JavaScript
* is presented on the page is very important. jQuery, for example, must be
* added to the page before any jQuery code is run, so jquery.js uses the
* JS_LIBRARY group and a weight of -20, jquery.once.js (a library drupal.js
* depends on) uses the JS_LIBRARY group and a weight of -19, drupal.js uses
* the JS_LIBRARY group and a weight of -1, other libraries use the
* JS_LIBRARY group and a weight of 0 or higher, and all other scripts use
* one of the other group constants. The exact ordering of JavaScript is as
* follows:
* - First by scope, with 'header' first, 'footer' last, and any other
* scopes provided by a custom theme coming in between, as determined by
* the theme.
* - Then by group.
* - Then by the 'every_page' flag, with TRUE coming before FALSE.
* - Then by weight.
* - Then by the order in which the JavaScript was added. For example, all
* else being the same, JavaScript added by a call to drupal_add_js() that
* happened later in the page request gets added to the page after one for
* which drupal_add_js() happened earlier in the page request.
* - defer: If set to TRUE, the defer attribute is set on the &lt;script&gt; * - defer: If set to TRUE, the defer attribute is set on the &lt;script&gt;
* tag. Defaults to FALSE. * tag. Defaults to FALSE.
* - cache: If set to FALSE, the JavaScript file is loaded anew on every page * - cache: If set to FALSE, the JavaScript file is loaded anew on every page
* call; in other words, it is not cached. Used only when 'type' references * call; in other words, it is not cached. Used only when 'type' references
* a JavaScript file. Defaults to TRUE. * a JavaScript file. Defaults to TRUE.
* - preprocess: If TRUE and JavaScript aggregation is enabled, the script * - preprocess: If TRUE and JavaScript aggregation is enabled, the script
* file will be aggregated. Defaults to FALSE. * file will be aggregated. Defaults to TRUE.
* *
* @return * @return
* The current array of JavaScript files, settings, and in-line code, * The current array of JavaScript files, settings, and in-line code,
@ -3744,21 +3861,25 @@ function drupal_add_js($data = NULL, $options = NULL) {
), ),
'type' => 'setting', 'type' => 'setting',
'scope' => 'header', 'scope' => 'header',
'weight' => JS_LIBRARY, 'group' => JS_LIBRARY,
'every_page' => TRUE,
'weight' => 0,
), ),
'misc/drupal.js' => array( 'misc/drupal.js' => array(
'data' => 'misc/drupal.js', 'data' => 'misc/drupal.js',
'type' => 'file', 'type' => 'file',
'scope' => 'header', 'scope' => 'header',
'weight' => JS_LIBRARY - 1, 'group' => JS_LIBRARY,
'every_page' => TRUE,
'weight' => -1,
'preprocess' => TRUE,
'cache' => TRUE, 'cache' => TRUE,
'defer' => FALSE, 'defer' => FALSE,
'preprocess' => TRUE,
), ),
); );
// Register all required libraries. // Register all required libraries.
drupal_add_library('system', 'jquery'); drupal_add_library('system', 'jquery', TRUE);
drupal_add_library('system', 'once'); drupal_add_library('system', 'once', TRUE);
} }
switch ($options['type']) { switch ($options['type']) {
@ -3792,11 +3913,13 @@ function drupal_add_js($data = NULL, $options = NULL) {
function drupal_js_defaults($data = NULL) { function drupal_js_defaults($data = NULL) {
return array( return array(
'type' => 'file', 'type' => 'file',
'weight' => JS_DEFAULT, 'group' => JS_DEFAULT,
'every_page' => FALSE,
'weight' => 0,
'scope' => 'header', 'scope' => 'header',
'cache' => TRUE, 'cache' => TRUE,
'defer' => FALSE, 'defer' => FALSE,
'preprocess' => FALSE, 'preprocess' => TRUE,
'version' => NULL, 'version' => NULL,
'data' => $data, 'data' => $data,
); );
@ -3880,8 +4003,8 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
// third-party code might require the use of a different query string. // third-party code might require the use of a different query string.
$js_version_string = variable_get('drupal_js_version_query_string', 'v='); $js_version_string = variable_get('drupal_js_version_query_string', 'v=');
// Sort the JavaScript by weight so that it appears in the correct order. // Sort the JavaScript so that it appears in the correct order.
uasort($items, 'drupal_sort_weight'); uasort($items, 'drupal_sort_css_js');
// Provide the page with information about the individual JavaScript files // Provide the page with information about the individual JavaScript files
// used, information not otherwise available when aggregation is enabled. // used, information not otherwise available when aggregation is enabled.
@ -3942,8 +4065,13 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
} }
else { else {
// By increasing the index for each aggregated file, we maintain // By increasing the index for each aggregated file, we maintain
// the relative ordering of JS by weight. // the relative ordering of JS by weight. We also set the key such
$key = 'aggregate' . $index; // that groups are split by items sharing the same 'group' value and
// 'every_page' flag. While this potentially results in more aggregate
// files, it helps make each one more reusable across a site visit,
// leading to better front-end performance of a website as a whole.
// See drupal_add_js() for details.
$key = 'aggregate_' . $item['group'] . '_' . $item['every_page'] . '_' . $index;
$processed[$key] = ''; $processed[$key] = '';
$files[$key][$item['data']] = $item; $files[$key][$item['data']] = $item;
} }
@ -4007,9 +4135,9 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
* *
* @param $elements * @param $elements
* The structured array describing the data being rendered. * The structured array describing the data being rendered.
* @param $weight * @param $group
* The default weight of JavaScript and CSS being added. This is only applied * The default group of JavaScript and CSS being added. This is only applied
* to the stylesheets and JavaScript items that don't have an explicit weight * to the stylesheets and JavaScript items that don't have an explicit group
* assigned to them. * assigned to them.
* @param $dependency_check * @param $dependency_check
* When TRUE, will exit if a given library's dependencies are missing. When * When TRUE, will exit if a given library's dependencies are missing. When
@ -4025,7 +4153,7 @@ function drupal_get_js($scope = 'header', $javascript = NULL, $skip_alter = FALS
* @see drupal_add_css() * @see drupal_add_css()
* @see drupal_render() * @see drupal_render()
*/ */
function drupal_process_attached($elements, $weight = JS_DEFAULT, $dependency_check = FALSE) { function drupal_process_attached($elements, $group = JS_DEFAULT, $dependency_check = FALSE, $every_page = NULL) {
// Add defaults to the special attached structures that should be processed differently. // Add defaults to the special attached structures that should be processed differently.
$elements['#attached'] += array( $elements['#attached'] += array(
'library' => array(), 'library' => array(),
@ -4036,7 +4164,7 @@ function drupal_process_attached($elements, $weight = JS_DEFAULT, $dependency_ch
// Add the libraries first. // Add the libraries first.
$success = TRUE; $success = TRUE;
foreach ($elements['#attached']['library'] as $library) { foreach ($elements['#attached']['library'] as $library) {
if (drupal_add_library($library[0], $library[1]) === FALSE) { if (drupal_add_library($library[0], $library[1], $every_page) === FALSE) {
$success = FALSE; $success = FALSE;
// Exit if the dependency is missing. // Exit if the dependency is missing.
if ($dependency_check) { if ($dependency_check) {
@ -4063,9 +4191,13 @@ function drupal_process_attached($elements, $weight = JS_DEFAULT, $dependency_ch
$data = $options['data']; $data = $options['data'];
unset($options['data']); unset($options['data']);
} }
// Apply the default weight if the weight isn't explicitly given. // Apply the default group if it isn't explicitly given.
if (!isset($options['weight'])) { if (!isset($options['group'])) {
$options['weight'] = $weight; $options['group'] = $group;
}
// Set the every_page flag if one was passed.
if (isset($every_page)) {
$options['every_page'] = $every_page;
} }
call_user_func('drupal_add_' . $type, $data, $options); call_user_func('drupal_add_' . $type, $data, $options);
} }
@ -4212,7 +4344,7 @@ function drupal_process_attached($elements, $weight = JS_DEFAULT, $dependency_ch
* @see form_example_states_form() * @see form_example_states_form()
*/ */
function drupal_process_states(&$elements) { function drupal_process_states(&$elements) {
$elements['#attached']['js']['misc/states.js'] = array('weight' => JS_LIBRARY + 1); $elements['#attached']['js']['misc/states.js'] = array('group' => JS_LIBRARY, 'weight' => 1);
$elements['#attached']['js'][] = array( $elements['#attached']['js'][] = array(
'type' => 'setting', 'type' => 'setting',
'data' => array('states' => array('#' . $elements['#id'] => $elements['#states'])), 'data' => array('states' => array('#' . $elements['#id'] => $elements['#states'])),
@ -4241,7 +4373,7 @@ function drupal_process_states(&$elements) {
* @see hook_library() * @see hook_library()
* @see hook_library_alter() * @see hook_library_alter()
*/ */
function drupal_add_library($module, $name) { function drupal_add_library($module, $name, $every_page = NULL) {
$added = &drupal_static(__FUNCTION__, array()); $added = &drupal_static(__FUNCTION__, array());
// Only process the library if it exists and it was not added already. // Only process the library if it exists and it was not added already.
@ -4253,7 +4385,7 @@ function drupal_add_library($module, $name) {
'js' => $library['js'], 'js' => $library['js'],
'css' => $library['css'], 'css' => $library['css'],
); );
$added[$module][$name] = drupal_process_attached($elements, JS_LIBRARY, TRUE); $added[$module][$name] = drupal_process_attached($elements, JS_LIBRARY, TRUE, $every_page);
} }
else { else {
// Requested library does not exist. // Requested library does not exist.
@ -4434,8 +4566,8 @@ function drupal_add_tabledrag($table_id, $action, $relationship, $group, $subgro
// Add the table drag JavaScript to the page before the module JavaScript // Add the table drag JavaScript to the page before the module JavaScript
// to ensure that table drag behaviors are registered before any module // to ensure that table drag behaviors are registered before any module
// uses it. // uses it.
drupal_add_js('misc/jquery.cookie.js', array('weight' => JS_DEFAULT - 2)); drupal_add_js('misc/jquery.cookie.js', array('weight' => -2));
drupal_add_js('misc/tabledrag.js', array('weight' => JS_DEFAULT - 1)); drupal_add_js('misc/tabledrag.js', array('weight' => -1));
$js_added = TRUE; $js_added = TRUE;
} }

View File

@ -3061,7 +3061,7 @@ function form_process_fieldset(&$element, &$form_state) {
} }
// Contains form element summary functionalities. // Contains form element summary functionalities.
$element['#attached']['js']['misc/form.js'] = array('weight' => JS_LIBRARY + 1); $element['#attached']['js']['misc/form.js'] = array('group' => JS_LIBRARY, 'weight' => 1);
// The .form-wrapper class is required for #states to treat fieldsets like // The .form-wrapper class is required for #states to treat fieldsets like
// containers. // containers.

View File

@ -173,7 +173,7 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb
// And now add the stylesheets properly // And now add the stylesheets properly
foreach ($final_stylesheets as $media => $stylesheets) { foreach ($final_stylesheets as $media => $stylesheets) {
foreach ($stylesheets as $stylesheet) { foreach ($stylesheets as $stylesheet) {
drupal_add_css($stylesheet, array('weight' => CSS_THEME, 'media' => $media, 'preprocess' => TRUE)); drupal_add_css($stylesheet, array('group' => CSS_THEME, 'every_page' => TRUE, 'media' => $media));
} }
} }
@ -198,7 +198,7 @@ function _drupal_theme_initialize($theme, $base_theme = array(), $registry_callb
// Add scripts used by this theme. // Add scripts used by this theme.
foreach ($final_scripts as $script) { foreach ($final_scripts as $script) {
drupal_add_js($script, array('weight' => JS_THEME, 'preprocess' => TRUE)); drupal_add_js($script, array('group' => JS_THEME, 'every_page' => TRUE));
} }
$theme_engine = NULL; $theme_engine = NULL;

View File

@ -247,7 +247,7 @@ function theme_color_scheme_form($variables) {
$preview_js_path = isset($info['preview_js']) ? $path . $info['preview_js'] : drupal_get_path('module', 'color') . '/' . 'preview.js'; $preview_js_path = isset($info['preview_js']) ? $path . $info['preview_js'] : drupal_get_path('module', 'color') . '/' . 'preview.js';
// Add the JS at a weight below color.js. // Add the JS at a weight below color.js.
drupal_add_js($preview_js_path, array('weight' => JS_DEFAULT - 1)); drupal_add_js($preview_js_path, array('weight' => -1));
$output = ''; $output = '';
$output .= '<div class="color-form clearfix">'; $output .= '<div class="color-form clearfix">';

View File

@ -880,7 +880,7 @@ function locale_library_alter(&$libraries, $module) {
global $language; global $language;
if ($module == 'system' && isset($libraries['system']['ui.datepicker'])) { if ($module == 'system' && isset($libraries['system']['ui.datepicker'])) {
$datepicker = drupal_get_path('module', 'locale') . '/locale.datepicker.js'; $datepicker = drupal_get_path('module', 'locale') . '/locale.datepicker.js';
$libraries['system']['ui.datepicker']['js'][$datepicker] = array('weight' => JS_THEME); $libraries['system']['ui.datepicker']['js'][$datepicker] = array('group' => JS_THEME);
$libraries['system']['ui.datepicker']['js'][] = array( $libraries['system']['ui.datepicker']['js'][] = array(
'data' => array( 'data' => array(
'jqueryuidatepicker' => array( 'jqueryuidatepicker' => array(

View File

@ -655,7 +655,7 @@ class CascadingStylesheetsTestCase extends DrupalWebTestCase {
function testRenderInlinePreprocess() { function testRenderInlinePreprocess() {
$css = 'body { padding: 0px; }'; $css = 'body { padding: 0px; }';
$css_preprocessed = '<style type="text/css" media="all">' . drupal_load_stylesheet_content($css, TRUE) . '</style>'; $css_preprocessed = '<style type="text/css" media="all">' . drupal_load_stylesheet_content($css, TRUE) . '</style>';
drupal_add_css($css, array('type' => 'inline', 'preprocess' => TRUE)); drupal_add_css($css, array('type' => 'inline'));
$styles = drupal_get_css(); $styles = drupal_get_css();
$this->assertEqual(trim($styles), $css_preprocessed, t('Rendering preprocessed inline CSS adds it to the page.')); $this->assertEqual(trim($styles), $css_preprocessed, t('Rendering preprocessed inline CSS adds it to the page.'));
} }
@ -665,7 +665,7 @@ class CascadingStylesheetsTestCase extends DrupalWebTestCase {
*/ */
function testRenderInlineNoPreprocess() { function testRenderInlineNoPreprocess() {
$css = 'body { padding: 0px; }'; $css = 'body { padding: 0px; }';
drupal_add_css($css, array('type' => 'inline')); drupal_add_css($css, array('type' => 'inline', 'preprocess' => FALSE));
$styles = drupal_get_css(); $styles = drupal_get_css();
$this->assertTrue(strpos($styles, $css) > 0, t('Rendering non-preprocessed inline CSS adds it to the page.')); $this->assertTrue(strpos($styles, $css) > 0, t('Rendering non-preprocessed inline CSS adds it to the page.'));
} }
@ -675,7 +675,9 @@ class CascadingStylesheetsTestCase extends DrupalWebTestCase {
*/ */
function testRenderInlineFullPage() { function testRenderInlineFullPage() {
$css = 'body { font-size: 254px; }'; $css = 'body { font-size: 254px; }';
$expected = $css; // Inline CSS is minified unless 'preprocess' => FALSE is passed as a
// drupal_add_css() option.
$expected = 'body{font-size:254px;}';
// Create a node, using the PHP filter that tests drupal_add_css(). // Create a node, using the PHP filter that tests drupal_add_css().
$php_format_id = db_query_range('SELECT format FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'PHP code'))->fetchField(); $php_format_id = db_query_range('SELECT format FROM {filter_format} WHERE name = :name', 0, 1, array(':name' => 'PHP code'))->fetchField();
@ -706,9 +708,9 @@ class CascadingStylesheetsTestCase extends DrupalWebTestCase {
drupal_add_css(drupal_get_path('module', 'simpletest') . '/simpletest.css'); drupal_add_css(drupal_get_path('module', 'simpletest') . '/simpletest.css');
// A few system CSS files, ordered in a strange way. // A few system CSS files, ordered in a strange way.
$system_path = drupal_get_path('module', 'system'); $system_path = drupal_get_path('module', 'system');
drupal_add_css($system_path . '/system.menus.css', array('weight' => CSS_SYSTEM)); drupal_add_css($system_path . '/system.menus.css', array('group' => CSS_SYSTEM));
drupal_add_css($system_path . '/system.base.css', array('weight' => CSS_SYSTEM - 10)); drupal_add_css($system_path . '/system.base.css', array('group' => CSS_SYSTEM, 'weight' => -10));
drupal_add_css($system_path . '/system.theme.css', array('weight' => CSS_SYSTEM)); drupal_add_css($system_path . '/system.theme.css', array('group' => CSS_SYSTEM));
$expected = array( $expected = array(
$system_path . '/system.base.css', $system_path . '/system.base.css',
@ -1241,12 +1243,20 @@ class JavaScriptTestCase extends DrupalWebTestCase {
$this->assertFalse($javascript['misc/collapse.js']['preprocess'], t('Setting cache to FALSE sets proprocess to FALSE when adding JavaScript.')); $this->assertFalse($javascript['misc/collapse.js']['preprocess'], t('Setting cache to FALSE sets proprocess to FALSE when adding JavaScript.'));
} }
/**
* Test adding a JavaScript file with a different group.
*/
function testDifferentGroup() {
$javascript = drupal_add_js('misc/collapse.js', array('group' => JS_THEME));
$this->assertEqual($javascript['misc/collapse.js']['group'], JS_THEME, t('Adding a JavaScript file with a different group caches the given group.'));
}
/** /**
* Test adding a JavaScript file with a different weight. * Test adding a JavaScript file with a different weight.
*/ */
function testDifferentWeight() { function testDifferentWeight() {
$javascript = drupal_add_js('misc/collapse.js', array('weight' => JS_THEME)); $javascript = drupal_add_js('misc/collapse.js', array('weight' => 2));
$this->assertEqual($javascript['misc/collapse.js']['weight'], JS_THEME, t('Adding a JavaScript file with a different weight caches the given weight.')); $this->assertEqual($javascript['misc/collapse.js']['weight'], 2, t('Adding a JavaScript file with a different weight caches the given weight.'));
} }
/** /**
@ -1295,7 +1305,10 @@ class JavaScriptTestCase extends DrupalWebTestCase {
* Test rendering the JavaScript with a file's weight above jQuery's. * Test rendering the JavaScript with a file's weight above jQuery's.
*/ */
function testRenderDifferentWeight() { function testRenderDifferentWeight() {
drupal_add_js('misc/collapse.js', array('weight' => JS_LIBRARY - 21)); // JavaScript files are sorted first by group, then by the 'every_page'
// flag, then by weight (see drupal_sort_css_js()), so to test the effect of
// weight, we need the other two options to be the same.
drupal_add_js('misc/collapse.js', array('group' => JS_LIBRARY, 'every_page' => TRUE, 'weight' => -21));
$javascript = drupal_get_js(); $javascript = drupal_get_js();
$this->assertTrue(strpos($javascript, 'misc/collapse.js') < strpos($javascript, 'misc/jquery.js'), t('Rendering a JavaScript file above jQuery.')); $this->assertTrue(strpos($javascript, 'misc/collapse.js') < strpos($javascript, 'misc/jquery.js'), t('Rendering a JavaScript file above jQuery.'));
} }
@ -1308,7 +1321,7 @@ class JavaScriptTestCase extends DrupalWebTestCase {
function testAlter() { function testAlter() {
// Add both tableselect.js and simpletest.js, with a larger weight on SimpleTest. // Add both tableselect.js and simpletest.js, with a larger weight on SimpleTest.
drupal_add_js('misc/tableselect.js'); drupal_add_js('misc/tableselect.js');
drupal_add_js(drupal_get_path('module', 'simpletest') . '/simpletest.js', array('weight' => JS_THEME)); drupal_add_js(drupal_get_path('module', 'simpletest') . '/simpletest.js', array('weight' => 9999));
// Render the JavaScript, testing if simpletest.js was altered to be before // Render the JavaScript, testing if simpletest.js was altered to be before
// tableselect.js. See simpletest_js_alter() to see where this alteration // tableselect.js. See simpletest_js_alter() to see where this alteration

View File

@ -1066,7 +1066,7 @@ function system_library() {
'website' => 'http://jquery.com', 'website' => 'http://jquery.com',
'version' => '1.4.2', 'version' => '1.4.2',
'js' => array( 'js' => array(
'misc/jquery.js' => array('weight' => JS_LIBRARY - 20, 'preprocess' => TRUE), 'misc/jquery.js' => array('group' => JS_LIBRARY, 'weight' => -20),
), ),
); );
@ -1076,7 +1076,7 @@ function system_library() {
'website' => 'http://plugins.jquery.com/project/once', 'website' => 'http://plugins.jquery.com/project/once',
'version' => '1.2', 'version' => '1.2',
'js' => array( 'js' => array(
'misc/jquery.once.js' => array('weight' => JS_LIBRARY - 19, 'preprocess' => TRUE), 'misc/jquery.once.js' => array('group' => JS_LIBRARY, 'weight' => -19),
), ),
); );
@ -1142,7 +1142,7 @@ function system_library() {
'website' => 'http://jqueryui.com', 'website' => 'http://jqueryui.com',
'version' => '1.8', 'version' => '1.8',
'js' => array( 'js' => array(
'misc/ui/jquery.ui.core.min.js' => array('weight' => JS_LIBRARY - 11), 'misc/ui/jquery.ui.core.min.js' => array('group' => JS_LIBRARY, 'weight' => -11),
), ),
'css' => array( 'css' => array(
'misc/ui/jquery.ui.core.css' => array(), 'misc/ui/jquery.ui.core.css' => array(),
@ -1359,7 +1359,7 @@ function system_library() {
'website' => 'http://docs.jquery.com/UI/Widget', 'website' => 'http://docs.jquery.com/UI/Widget',
'version' => '1.8', 'version' => '1.8',
'js' => array( 'js' => array(
'misc/ui/jquery.ui.widget.min.js' => array('weight' => JS_LIBRARY - 10), 'misc/ui/jquery.ui.widget.min.js' => array('group' => JS_LIBRARY, 'weight' => -10),
), ),
'dependencies' => array( 'dependencies' => array(
array('system', 'ui'), array('system', 'ui'),
@ -1370,7 +1370,7 @@ function system_library() {
'website' => 'http://jqueryui.com/demos/effect/', 'website' => 'http://jqueryui.com/demos/effect/',
'version' => '1.8', 'version' => '1.8',
'js' => array( 'js' => array(
'misc/ui/jquery.effects.core.min.js' => array('weight' => JS_LIBRARY - 9), 'misc/ui/jquery.effects.core.min.js' => array('group' => JS_LIBRARY, 'weight' => -9),
), ),
); );
$libraries['effects.blind'] = array( $libraries['effects.blind'] = array(
@ -1819,14 +1819,15 @@ function _system_filetransfer_backend_form_common() {
*/ */
function system_init() { function system_init() {
$path = drupal_get_path('module', 'system'); $path = drupal_get_path('module', 'system');
// Add the CSS for this module. // Add the CSS for this module. These aren't in system.info, because they
drupal_add_css($path . '/system.base.css', array('weight' => CSS_SYSTEM, 'preprocess' => TRUE)); // need to be in the CSS_SYSTEM group rather than the CSS_DEFAULT group.
drupal_add_css($path . '/system.base.css', array('group' => CSS_SYSTEM, 'every_page' => TRUE));
if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit' || arg(2) == 'delete'))) { if (arg(0) == 'admin' || (variable_get('node_admin_theme', '0') && arg(0) == 'node' && (arg(1) == 'add' || arg(2) == 'edit' || arg(2) == 'delete'))) {
drupal_add_css($path . '/system.admin.css', array('weight' => CSS_SYSTEM)); drupal_add_css($path . '/system.admin.css', array('group' => CSS_SYSTEM));
} }
drupal_add_css($path . '/system.menus.css', array('weight' => CSS_SYSTEM, 'preprocess' => TRUE)); drupal_add_css($path . '/system.menus.css', array('group' => CSS_SYSTEM, 'every_page' => TRUE));
drupal_add_css($path . '/system.messages.css', array('weight' => CSS_SYSTEM, 'preprocess' => TRUE)); drupal_add_css($path . '/system.messages.css', array('group' => CSS_SYSTEM, 'every_page' => TRUE));
drupal_add_css($path . '/system.theme.css', array('weight' => CSS_SYSTEM, 'preprocess' => TRUE)); drupal_add_css($path . '/system.theme.css', array('group' => CSS_SYSTEM, 'every_page' => TRUE));
// Ignore slave database servers for this request. // Ignore slave database servers for this request.
// //
@ -1862,13 +1863,13 @@ function system_add_module_assets() {
if (!empty($info['stylesheets'])) { if (!empty($info['stylesheets'])) {
foreach ($info['stylesheets'] as $media => $stylesheets) { foreach ($info['stylesheets'] as $media => $stylesheets) {
foreach ($stylesheets as $stylesheet) { foreach ($stylesheets as $stylesheet) {
drupal_add_css($stylesheet, array('media' => $media, 'preprocess' => TRUE)); drupal_add_css($stylesheet, array('every_page' => TRUE, 'media' => $media));
} }
} }
} }
if (!empty($info['scripts'])) { if (!empty($info['scripts'])) {
foreach ($info['scripts'] as $script) { foreach ($info['scripts'] as $script) {
drupal_add_js($script, array('preprocess' => TRUE)); drupal_add_js($script, array('every_page' => TRUE));
} }
} }
} }

View File

@ -188,7 +188,7 @@ function toolbar_view() {
'#attached'=> array( '#attached'=> array(
'js' => array( 'js' => array(
$module_path . '/toolbar.js', $module_path . '/toolbar.js',
array('data' => 'misc/jquery.cookie.js', 'weight' => JS_LIBRARY + 2), array('data' => 'misc/jquery.cookie.js', 'group' => JS_LIBRARY, 'weight' => 2),
array( array(
'data' => array('tableHeaderOffset' => 'Drupal.toolbar.height'), 'data' => array('tableHeaderOffset' => 'Drupal.toolbar.height'),
'type' => 'setting' 'type' => 'setting'

View File

@ -23,8 +23,8 @@ function bartik_preprocess_html(&$variables) {
} }
// Add conditional stylesheets for IE // Add conditional stylesheets for IE
drupal_add_css(path_to_theme() . '/css/ie.css', array('weight' => CSS_THEME, 'browsers' => array('IE' => 'lte IE 7', '!IE' => FALSE))); drupal_add_css(path_to_theme() . '/css/ie.css', array('group' => CSS_THEME, 'browsers' => array('IE' => 'lte IE 7', '!IE' => FALSE), 'preprocess' => FALSE));
drupal_add_css(path_to_theme() . '/css/ie6.css', array('weight' => CSS_THEME, 'browsers' => array('IE' => 'IE 6', '!IE' => FALSE))); drupal_add_css(path_to_theme() . '/css/ie6.css', array('group' => CSS_THEME, 'browsers' => array('IE' => 'IE 6', '!IE' => FALSE), 'preprocess' => FALSE));
} }
/** /**

View File

@ -42,7 +42,7 @@ function garland_preprocess_html(&$vars) {
$vars['classes_array'][] = 'fluid-width'; $vars['classes_array'][] = 'fluid-width';
} }
// Add conditional CSS for IE6. // Add conditional CSS for IE6.
drupal_add_css(path_to_theme() . '/fix-ie.css', array('weight' => CSS_THEME, 'browsers' => array('IE' => 'lt IE 7', '!IE' => FALSE))); drupal_add_css(path_to_theme() . '/fix-ie.css', array('group' => CSS_THEME, 'browsers' => array('IE' => 'lt IE 7', '!IE' => FALSE), 'preprocess' => FALSE));
} }
/** /**

View File

@ -18,9 +18,9 @@ function seven_preprocess_maintenance_page(&$vars) {
*/ */
function seven_preprocess_html(&$vars) { function seven_preprocess_html(&$vars) {
// Add conditional CSS for IE8 and below. // Add conditional CSS for IE8 and below.
drupal_add_css(path_to_theme() . '/ie.css', array('weight' => CSS_THEME, 'browsers' => array('IE' => 'lte IE 8', '!IE' => FALSE))); drupal_add_css(path_to_theme() . '/ie.css', array('group' => CSS_THEME, 'browsers' => array('IE' => 'lte IE 8', '!IE' => FALSE), 'preprocess' => FALSE));
// Add conditional CSS for IE6. // Add conditional CSS for IE6.
drupal_add_css(path_to_theme() . '/ie6.css', array('weight' => CSS_THEME, 'browsers' => array('IE' => 'lt IE 7', '!IE' => FALSE))); drupal_add_css(path_to_theme() . '/ie6.css', array('group' => CSS_THEME, 'browsers' => array('IE' => 'lt IE 7', '!IE' => FALSE), 'preprocess' => FALSE));
} }
/** /**