/** * Processes asset libraries into render arrays. * * @param array $attached * The attachments to process. * @param array $placeholders * The placeholders that exist in the response. * * @return array * An array keyed by asset type, with keys: * - styles * - scripts * - scripts_bottom */ protected function processAssetLibraries(array $attached, array $placeholders) { $all_attached = ['#attached' => $attached]; $assets = AttachedAssets::createFromRenderArray($all_attached); // Take Ajax page state into account, to allow for something like Turbolinks // to be implemented without altering core. // @see https://github.com/rails/turbolinks/ // @todo https://www.drupal.org/node/2497115 - Below line is broken due to ->request. $ajax_page_state = $this->requestStack->getCurrentRequest()->request->get('ajax_page_state'); $assets->setAlreadyLoadedLibraries(isset($ajax_page_state) ? explode(',', $ajax_page_state['libraries']) : []); $variables = []; // Print styles - if present. if (isset($placeholders['styles'])) { // Optimize CSS if necessary, but only during normal site operation. $optimize_css = !defined('MAINTENANCE_MODE') && $this->config->get('css.preprocess'); $variables['styles'] = $this->cssCollectionRenderer->render($this->assetResolver->getCssAssets($assets, $optimize_css)); } // Print scripts - if any are present. if (isset($placeholders['scripts']) || isset($placeholders['scripts_bottom'])) { // Optimize JS if necessary, but only during normal site operation. $optimize_js = !defined('MAINTENANCE_MODE') && !\Drupal::state()->get('system.maintenance_mode') && $this->config->get('js.preprocess'); list($js_assets_header, $js_assets_footer) = $this->assetResolver->getJsAssets($assets, $optimize_js); $variables['scripts'] = $this->jsCollectionRenderer->render($js_assets_header); $variables['scripts_bottom'] = $this->jsCollectionRenderer->render($js_assets_footer); } return $variables; }
/** * Prepares the AJAX commands to attach assets. * * @param \Drupal\Core\Ajax\AjaxResponse $response * The AJAX response to update. * @param \Symfony\Component\HttpFoundation\Request $request * The request object that the AJAX is responding to. * * @return array * An array of commands ready to be returned as JSON. */ protected function buildAttachmentsCommands(AjaxResponse $response, Request $request) { $ajax_page_state = $request->request->get('ajax_page_state'); // Aggregate CSS/JS if necessary, but only during normal site operation. $optimize_css = !defined('MAINTENANCE_MODE') && $this->config->get('css.preprocess'); $optimize_js = !defined('MAINTENANCE_MODE') && $this->config->get('js.preprocess'); $attachments = $response->getAttachments(); // Resolve the attached libraries into asset collections. $assets = new AttachedAssets(); $assets->setLibraries(isset($attachments['library']) ? $attachments['library'] : [])->setAlreadyLoadedLibraries(isset($ajax_page_state['libraries']) ? explode(',', $ajax_page_state['libraries']) : [])->setSettings(isset($attachments['drupalSettings']) ? $attachments['drupalSettings'] : []); $css_assets = $this->assetResolver->getCssAssets($assets, $optimize_css); list($js_assets_header, $js_assets_footer) = $this->assetResolver->getJsAssets($assets, $optimize_js); // Render the HTML to load these files, and add AJAX commands to insert this // HTML in the page. Settings are handled separately, afterwards. $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(); if ($css_assets) { $css_render_array = $this->cssCollectionRenderer->render($css_assets); $resource_commands[] = new AddCssCommand((string) $this->renderer->renderPlain($css_render_array)); } if ($js_assets_header) { $js_header_render_array = $this->jsCollectionRenderer->render($js_assets_header); $resource_commands[] = new PrependCommand('head', (string) $this->renderer->renderPlain($js_header_render_array)); } if ($js_assets_footer) { $js_footer_render_array = $this->jsCollectionRenderer->render($js_assets_footer); $resource_commands[] = new AppendCommand('body', (string) $this->renderer->renderPlain($js_footer_render_array)); } foreach (array_reverse($resource_commands) as $resource_command) { $response->addCommand($resource_command, TRUE); } // Prepend a command to merge changes and additions to drupalSettings. if (!empty($settings)) { // During Ajax requests basic path-specific settings are excluded from // new drupalSettings values. The original page where this request comes // from already has the right values. An Ajax request would update them // with values for the Ajax request and incorrectly override the page's // values. // @see system_js_settings_alter() unset($settings['path']); $response->addCommand(new SettingsCommand($settings, TRUE), TRUE); } $commands = $response->getCommands(); $this->moduleHandler->alter('ajax_render', $commands); return $commands; }
/** * Tests JavaScript files that have querystrings attached get added right. */ function testAddJsFileWithQueryString() { $build['#attached']['library'][] = 'common_test/querystring'; $assets = AttachedAssets::createFromRenderArray($build); $css = $this->assetResolver->getCssAssets($assets, FALSE); $js = $this->assetResolver->getJsAssets($assets, FALSE)[1]; $this->assertTrue(array_key_exists('core/modules/system/tests/modules/common_test/querystring.css?arg1=value1&arg2=value2', $css), 'CSS file with query string is correctly added.'); $this->assertTrue(array_key_exists('core/modules/system/tests/modules/common_test/querystring.js?arg1=value1&arg2=value2', $js), 'JavaScript file with query string is correctly added.'); $css_render_array = \Drupal::service('asset.css.collection_renderer')->render($css); $rendered_css = $this->renderer->renderPlain($css_render_array); $js_render_array = \Drupal::service('asset.js.collection_renderer')->render($js); $rendered_js = $this->renderer->renderPlain($js_render_array); $query_string = $this->container->get('state')->get('system.css_js_query_string') ?: '0'; $this->assertNotIdentical(strpos($rendered_css, '<link rel="stylesheet" href="' . str_replace('&', '&', file_url_transform_relative(file_create_url('core/modules/system/tests/modules/common_test/querystring.css?arg1=value1&arg2=value2'))) . '&' . $query_string . '" media="all" />'), FALSE, 'CSS file with query string gets version query string correctly appended..'); $this->assertNotIdentical(strpos($rendered_js, '<script src="' . str_replace('&', '&', file_url_transform_relative(file_create_url('core/modules/system/tests/modules/common_test/querystring.js?arg1=value1&arg2=value2'))) . '&' . $query_string . '"></script>'), FALSE, 'JavaScript file with query string gets version query string correctly appended.'); }
/** * Processes asset libraries into render arrays. * * @param \Drupal\Core\Asset\AttachedAssetsInterface $assets * The attached assets collection for the current response. * @param array $placeholders * The placeholders that exist in the response. * * @return array * An array keyed by asset type, with keys: * - styles * - scripts * - scripts_bottom */ protected function processAssetLibraries(AttachedAssetsInterface $assets, array $placeholders) { $variables = []; // Print styles - if present. if (isset($placeholders['styles'])) { // Optimize CSS if necessary, but only during normal site operation. $optimize_css = !defined('MAINTENANCE_MODE') && $this->config->get('css.preprocess'); $variables['styles'] = $this->cssCollectionRenderer->render($this->assetResolver->getCssAssets($assets, $optimize_css)); } // Print scripts - if any are present. if (isset($placeholders['scripts']) || isset($placeholders['scripts_bottom'])) { // Optimize JS if necessary, but only during normal site operation. $optimize_js = !defined('MAINTENANCE_MODE') && !\Drupal::state()->get('system.maintenance_mode') && $this->config->get('js.preprocess'); list($js_assets_header, $js_assets_footer) = $this->assetResolver->getJsAssets($assets, $optimize_js); $variables['scripts'] = $this->jsCollectionRenderer->render($js_assets_header); $variables['scripts_bottom'] = $this->jsCollectionRenderer->render($js_assets_footer); } return $variables; }