Commit ea568f1d authored by catch's avatar catch

Issue #784626 by Wim Leers, Manuel Garcia, jcisio, joelpittet, Bevan,...

Issue #784626 by Wim Leers, Manuel Garcia, jcisio, joelpittet, Bevan, fcaspani, dcmouyard: Default all JS to the footer, allow asset libraries to force their JS to the header
parent 5f7ec33a
......@@ -48,6 +48,7 @@ drupal:
misc/drupal.js: { weight: -18 }
dependencies:
- core/domready
- core/drupalSettings
drupalSettings:
version: VERSION
......@@ -308,6 +309,8 @@ drupal.vertical-tabs:
- core/drupal.form
html5shiv:
# Block the page from being loaded until html5shiv is initialized.
header: true
remote: https://github.com/aFarkas/html5shiv
version: 3.7.2
license:
......@@ -807,6 +810,8 @@ matchmedia.addListener:
- core/matchmedia
modernizr:
# Block the page from being loaded until Modernizr is initialized.
header: true
remote: https://github.com/Modernizr/Modernizr
license:
name: MIT
......@@ -814,7 +819,7 @@ modernizr:
gpl-compatible: true
version: v2.8.3
js:
assets/vendor/modernizr/modernizr.min.js: { every_page: true, preprocess: 0, scope: header, weight: -21, minified: true }
assets/vendor/modernizr/modernizr.min.js: { every_page: true, preprocess: 0, weight: -21, minified: true }
normalize:
remote: https://github.com/necolas/normalize.css
......
......@@ -135,8 +135,15 @@ protected function ajaxRender(Request $request) {
// Render the HTML to load these files, and add AJAX commands to insert this
// HTML in the page. Settings are handled separately, afterwards.
$settings = (isset($js_assets_header['drupalSettings'])) ? $js_assets_header['drupalSettings']['data'] : [];
unset($js_assets_header['drupalSettings']);
$settings = [];
if (isset($js_assets_header['drupalSettings'])) {
$settings = $js_assets_header['drupalSettings']['data'];
unset($js_assets_header['drupalSettings']);
}
if (isset($js_assets_footer['drupalSettings'])) {
$settings = $js_assets_footer['drupalSettings']['data'];
unset($js_assets_footer['drupalSettings']);
}
// Prepend commands to add the assets, preserving their relative order.
$resource_commands = array();
......
......@@ -214,8 +214,23 @@ protected function getJsSettingsAssets(AttachedAssetsInterface $assets) {
*/
public function getJsAssets(AttachedAssetsInterface $assets, $optimize) {
$javascript = [];
$libraries_to_load = $this->getLibrariesToLoad($assets);
foreach ($this->getLibrariesToLoad($assets) as $library) {
// Collect all libraries that contain JS assets and are in the header.
$header_js_libraries = [];
foreach ($libraries_to_load as $library) {
list($extension, $name) = explode('/', $library, 2);
$definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
if (isset($definition['js']) && !empty($definition['header'])) {
$header_js_libraries[] = $library;
}
}
// The current list of header JS libraries are only those libraries that are
// in the header, but their dependencies must also be loaded for them to
// function correctly, so update the list with those.
$header_js_libraries = $this->libraryDependencyResolver->getLibrariesWithDependencies($header_js_libraries);
foreach ($libraries_to_load as $library) {
list($extension, $name) = explode('/', $library, 2);
$definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
if (isset($definition['js'])) {
......@@ -225,7 +240,6 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize) {
'group' => JS_DEFAULT,
'every_page' => FALSE,
'weight' => 0,
'scope' => 'header',
'cache' => TRUE,
'preprocess' => TRUE,
'attributes' => array(),
......@@ -233,6 +247,10 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize) {
'browsers' => array(),
);
// 'scope' is a calculated option, based on which libraries are marked
// to be loaded from the header (see above).
$options['scope'] = in_array($library, $header_js_libraries) ? 'header' : 'footer';
// Preprocess can only be set if caching is enabled and no attributes
// are set.
$options['preprocess'] = $options['cache'] && empty($options['attributes']) ? $options['preprocess'] : FALSE;
......@@ -267,8 +285,6 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize) {
}
}
// @todo Refactor this when the default scope is changed to 'footer' in
// https://www.drupal.org/node/784626
// If the core/drupalSettings library is being loaded or is already loaded,
// get the JavaScript settings assets, and convert them into a single
// "regular" JavaScript asset.
......@@ -278,7 +294,6 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize) {
if ($settings_needed && $settings_have_changed) {
$settings = $this->getJsSettingsAssets($assets);
if (!empty($settings)) {
// Prepend to the list of JavaScript assets, to render it first.
$settings_as_inline_javascript = [
'type' => 'setting',
'group' => JS_SETTING,
......@@ -287,7 +302,15 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize) {
'browsers' => array(),
'data' => $settings,
];
$js_assets_header = ['drupalSettings' => $settings_as_inline_javascript] + $js_assets_header;
$settings_js_asset = ['drupalSettings' => $settings_as_inline_javascript];
// Prepend to the list of JS assets, to render it first. Preferably in
// the footer, but in the header if necessary.
if (in_array('core/drupalSettings', $header_js_libraries)) {
$js_assets_header = $settings_js_asset + $js_assets_header;
}
else {
$js_assets_footer = $settings_js_asset + $js_assets_footer;
}
}
}
......
......@@ -86,6 +86,10 @@ public function buildByExtension($extension) {
}
$library += array('dependencies' => array(), 'js' => array(), 'css' => array());
if (isset($library['header']) && !is_bool($library['header'])) {
throw new \LogicException(sprintf("The 'header' key in the library definition '%s' in extension '%s' is invalid: it must be a boolean.", $id, $extension));
}
if (isset($library['version'])) {
// @todo Retrieve version of a non-core extension.
if ($library['version'] === 'VERSION') {
......
......@@ -34,7 +34,7 @@ drupal.editor.dialog:
quickedit.inPlaceEditor.formattedText:
version: VERSION
js:
js/editor.formattedTextEditor.js: { scope: footer, attributes: { defer: true } }
js/editor.formattedTextEditor.js: { attributes: { defer: true } }
dependencies:
- quickedit/quickedit
- editor/drupal.editor
......
......@@ -11,6 +11,6 @@ api:
mark-as-read:
version: VERSION
js:
js/mark-as-read.js: { scope: footer }
js/mark-as-read.js: {}
dependencies:
- history/api
......@@ -33,7 +33,7 @@ class LocaleLibraryAlterTest extends WebTestBase {
public function testLibraryAlter() {
$assets = new AttachedAssets();
$assets->setLibraries(['core/jquery.ui.datepicker']);
$js_assets = $this->container->get('asset.resolver')->getJsAssets($assets, FALSE)[0];
$js_assets = $this->container->get('asset.resolver')->getJsAssets($assets, FALSE)[1];
$this->assertTrue(array_key_exists('core/modules/locale/locale.datepicker.js', $js_assets), 'locale.datepicker.js added to scripts.');
}
}
......@@ -2,24 +2,24 @@ quickedit:
version: VERSION
js:
# Core.
js/quickedit.js: { scope: footer }
js/util.js: { scope: footer }
js/quickedit.js: {}
js/util.js: {}
# Models.
js/models/BaseModel.js: { scope: footer }
js/models/AppModel.js: { scope: footer }
js/models/EntityModel.js: { scope: footer }
js/models/FieldModel.js: { scope: footer }
js/models/EditorModel.js: { scope: footer }
js/models/BaseModel.js: {}
js/models/AppModel.js: {}
js/models/EntityModel.js: {}
js/models/FieldModel.js: {}
js/models/EditorModel.js: {}
# Views.
js/views/AppView.js: { scope: footer }
js/views/FieldDecorationView.js: { scope: footer }
js/views/EntityDecorationView.js: { scope: footer }
js/views/EntityToolbarView.js: { scope: footer }
js/views/ContextualLinkView.js: { scope: footer }
js/views/FieldToolbarView.js: { scope: footer }
js/views/EditorView.js: { scope: footer }
js/views/AppView.js: {}
js/views/FieldDecorationView.js: {}
js/views/EntityDecorationView.js: {}
js/views/EntityToolbarView.js: {}
js/views/ContextualLinkView.js: {}
js/views/FieldToolbarView.js: {}
js/views/EditorView.js: {}
# Other.
js/theme.js: { scope: footer }
js/theme.js: {}
css:
component:
css/quickedit.module.css: {}
......@@ -44,13 +44,13 @@ quickedit:
quickedit.inPlaceEditor.form:
version: VERSION
js:
js/editors/formEditor.js: { scope: footer }
js/editors/formEditor.js: {}
dependencies:
- quickedit/quickedit
quickedit.inPlaceEditor.plainText:
version: VERSION
js:
js/editors/plainTextEditor.js: { scope: footer }
js/editors/plainTextEditor.js: {}
dependencies:
- quickedit/quickedit
drupal.statistics:
version: VERSION
js:
statistics.js: { scope: footer }
statistics.js: {}
dependencies:
- core/jquery
- core/drupal
......
......@@ -47,7 +47,8 @@ public function testOrder() {
$assets = AttachedAssets::createFromRenderArray($build);
$css_render_array = $css_collection_renderer->render($asset_resolver->getCssAssets($assets, FALSE));
$expected_commands[1] = new AddCssCommand($renderer->render($css_render_array));
$build['#attached']['library'][] = 'ajax_test/order-js-command';
$build['#attached']['library'][] = 'ajax_test/order-header-js-command';
$build['#attached']['library'][] = 'ajax_test/order-footer-js-command';
$assets = AttachedAssets::createFromRenderArray($build);
list($js_assets_header, $js_assets_footer) = $asset_resolver->getJsAssets($assets, FALSE);
$js_header_render_array = $js_collection_renderer->render($js_assets_header);
......@@ -126,7 +127,7 @@ public function testLazyLoad() {
$assets->setLibraries([$expected['library_2']])
->setAlreadyLoadedLibraries($original_libraries);
$js_assets = $asset_resolver->getJsAssets($assets, FALSE)[0];
$js_assets = $asset_resolver->getJsAssets($assets, FALSE)[1];
unset($js_assets['drupalSettings']);
$js_render_array = $js_collection_renderer->render($js_assets);
$expected_js_html = $renderer->render($js_render_array);
......
......@@ -3,7 +3,8 @@ order:
ajax: test
dependencies:
- ajax_test/order-css-command
- ajax_test/order-js-command
- ajax_test/order-footer-js-command
- ajax_test/order-header-js-command
order-css-command:
css:
......@@ -12,9 +13,11 @@ order-css-command:
a.css: {}
b.css: {}
order-js-command:
order-footer-js-command:
js:
# Two JavaScript files (first to the footer, should appear last).
footer.js: { scope: footer }
header.js: {}
footer.js: {}
order-header-js-command:
header: true
js:
header.js: {}
......@@ -36,9 +36,12 @@ js-attributes:
foo: bar
defer: true
js-footer:
js-header:
header: true
js:
footer.js: { scope: footer }
header.js: {}
dependencies:
- core/drupal
# Library to test setting cache = FALSE, to prevent aggregation.
no-cache:
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment