add async and defer attributes to js requirements, replaces #4555

This commit is contained in:
Florian Thoma 2016-07-04 16:55:35 +10:00
parent 859acf571e
commit 9fc51dc527
4 changed files with 286 additions and 45 deletions

View File

@ -56,7 +56,7 @@ If you're using the CSS method a second argument can be used. This argument defi
### Javascript Files ### Javascript Files
:::php :::php
Requirements::javascript($path); Requirements::javascript($path, $options);
A variant on the inclusion of custom javascript is the inclusion of *templated* javascript. Here, you keep your A variant on the inclusion of custom javascript is the inclusion of *templated* javascript. Here, you keep your
JavaScript in a separate file and instead load, via search and replace, several PHP-generated variables into that code. JavaScript in a separate file and instead load, via search and replace, several PHP-generated variables into that code.
@ -75,7 +75,6 @@ that your included files provide these scripts. This will ensure that subsequent
Requirement calls that rely on those included scripts will not double include those Requirement calls that rely on those included scripts will not double include those
files. files.
:::php :::php
Requirements::javascript('<my-module-dir>/javascript/dist/bundle.js', ['provides' => [ Requirements::javascript('<my-module-dir>/javascript/dist/bundle.js', ['provides' => [
'<my-module-dir>/javascript/jquery.js' '<my-module-dir>/javascript/jquery.js'
@ -84,6 +83,16 @@ files.
]]); ]]);
Requirements::javascript('<my-module-dir>/javascript/jquery.js'); // Will will skip this file Requirements::javascript('<my-module-dir>/javascript/jquery.js'); // Will will skip this file
You can also use the second argumet to add the 'async' and/or 'defer attributes to the script tag generated:
:::php
Requirements::javascript(
"<my-module-dir>/javascript/some_file.js",
array(
"async" => true,
"defer" => true,
)
);
### Custom Inline CSS or Javascript ### Custom Inline CSS or Javascript
@ -218,6 +227,20 @@ When combining CSS files, take care of relative urls, as these will not be re-wr
the destination location of the resulting combined CSS. the destination location of the resulting combined CSS.
</div> </div>
### Combined JS Files
You can also add the 'async' and/or 'defer' attributes to combined Javascript files as you would with the
`Requirements::javascript` call - use the third paramter of the `combine_files` function:
:::php
$scripts = array(
"$themeDir/javascript/some_script.js",
"$themeDir/javascript/some_other_script.js",
);
Requirements::combine_files('scripts.js', $scripts, array('async' => true, 'defer' => true));
## Clearing assets ## Clearing assets
:::php :::php

View File

@ -118,6 +118,29 @@ class RequirementsTest extends SapphireTest {
); );
} }
protected function setupCombinedRequirementsJavascriptAsyncDefer($backend, $async, $defer) {
$basePath = $this->getCurrentRelativePath();
$this->setupRequirements($backend);
// require files normally (e.g. called from a FormField instance)
$backend->javascript($basePath . '/RequirementsTest_a.js');
$backend->javascript($basePath . '/RequirementsTest_b.js');
$backend->javascript($basePath . '/RequirementsTest_c.js');
// require two of those files as combined includes
$backend->combineFiles(
'RequirementsTest_bc.js',
array(
$basePath . '/RequirementsTest_b.js',
$basePath . '/RequirementsTest_c.js'
),
array(
'async' => $async,
'defer' => $defer,
)
);
}
public function testCombinedJavascript() { public function testCombinedJavascript() {
/** @var Requirements_Backend $backend */ /** @var Requirements_Backend $backend */
$backend = Injector::inst()->create('Requirements_Backend'); $backend = Injector::inst()->create('Requirements_Backend');
@ -205,6 +228,152 @@ class RequirementsTest extends SapphireTest {
); );
} }
public function testCombinedJavascriptAsyncDefer() {
/** @var Requirements_Backend $backend */
$backend = Injector::inst()->create('Requirements_Backend');
$this->setupCombinedRequirementsJavascriptAsyncDefer($backend, true, false);
$combinedFileName = '/_combinedfiles/RequirementsTest_bc-2a55d56.js';
$combinedFilePath = AssetStoreTest_SpyStore::base_path() . $combinedFileName;
$html = $backend->includeInHTML(false, self::$html_template);
/* ASYNC IS INCLUDED IN SCRIPT TAG */
$this->assertRegExp(
'/src=".*' . preg_quote($combinedFileName, '/') . '" async/',
$html,
'async is included in script tag'
);
/* DEFER IS NOT INCLUDED IN SCRIPT TAG */
$this->assertNotContains('defer', $html, 'defer is not included');
/* COMBINED JAVASCRIPT FILE EXISTS */
clearstatcache(); // needed to get accurate file_exists() results
$this->assertFileExists($combinedFilePath,
'combined javascript file exists');
/* COMBINED JAVASCRIPT HAS CORRECT CONTENT */
$this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false),
'combined javascript has correct content');
$this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('c')") !== false),
'combined javascript has correct content');
/* COMBINED FILES ARE NOT INCLUDED TWICE */
$this->assertNotRegExp('/src=".*\/RequirementsTest_b\.js/', $html,
'combined files are not included twice');
$this->assertNotRegExp('/src=".*\/RequirementsTest_c\.js/', $html,
'combined files are not included twice');
/* NORMAL REQUIREMENTS ARE STILL INCLUDED */
$this->assertRegExp('/src=".*\/RequirementsTest_a\.js/', $html,
'normal requirements are still included');
/* NORMAL REQUIREMENTS DON'T HAVE ASYNC/DEFER */
$this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" async/', $html,
'normal requirements don\'t have async');
$this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" defer/', $html,
'normal requirements don\'t have defer');
$this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" async defer/', $html,
'normal requirements don\'t have async/defer');
// setup again for testing defer
unlink($combinedFilePath);
/** @var Requirements_Backend $backend */
$backend = Injector::inst()->create('Requirements_Backend');
$this->setupCombinedRequirementsJavascriptAsyncDefer($backend, false, true);
$html = $backend->includeInHTML(self::$html_template);
/* DEFER IS INCLUDED IN SCRIPT TAG */
$this->assertRegExp(
'/src=".*' . preg_quote($combinedFileName, '/') . '" defer/',
$html,
'defer is included in script tag'
);
/* ASYNC IS NOT INCLUDED IN SCRIPT TAG */
$this->assertNotContains('async', $html, 'async is not included');
/* COMBINED JAVASCRIPT FILE EXISTS */
clearstatcache(); // needed to get accurate file_exists() results
$this->assertFileExists($combinedFilePath,
'combined javascript file exists');
/* COMBINED JAVASCRIPT HAS CORRECT CONTENT */
$this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false),
'combined javascript has correct content');
$this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('c')") !== false),
'combined javascript has correct content');
/* COMBINED FILES ARE NOT INCLUDED TWICE */
$this->assertNotRegExp('/src=".*\/RequirementsTest_b\.js/', $html,
'combined files are not included twice');
$this->assertNotRegExp('/src=".*\/RequirementsTest_c\.js/', $html,
'combined files are not included twice');
/* NORMAL REQUIREMENTS ARE STILL INCLUDED */
$this->assertRegExp('/src=".*\/RequirementsTest_a\.js/', $html,
'normal requirements are still included');
/* NORMAL REQUIREMENTS DON'T HAVE ASYNC/DEFER */
$this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" async/', $html,
'normal requirements don\'t have async');
$this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" defer/', $html,
'normal requirements don\'t have defer');
$this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" async defer/', $html,
'normal requirements don\'t have async/defer');
// setup again for testing async and defer
unlink($combinedFilePath);
/** @var Requirements_Backend $backend */
$backend = Injector::inst()->create('Requirements_Backend');
$this->setupCombinedRequirementsJavascriptAsyncDefer($backend, true, true);
$html = $backend->includeInHTML(self::$html_template);
/* ASYNC/DEFER IS INCLUDED IN SCRIPT TAG */
$this->assertRegExp(
'/src=".*' . preg_quote($combinedFileName, '/') . '" async defer/',
$html,
'async and defer are included in script tag'
);
/* COMBINED JAVASCRIPT FILE EXISTS */
clearstatcache(); // needed to get accurate file_exists() results
$this->assertFileExists($combinedFilePath,
'combined javascript file exists');
/* COMBINED JAVASCRIPT HAS CORRECT CONTENT */
$this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('b')") !== false),
'combined javascript has correct content');
$this->assertTrue((strpos(file_get_contents($combinedFilePath), "alert('c')") !== false),
'combined javascript has correct content');
/* COMBINED FILES ARE NOT INCLUDED TWICE */
$this->assertNotRegExp('/src=".*\/RequirementsTest_b\.js/', $html,
'combined files are not included twice');
$this->assertNotRegExp('/src=".*\/RequirementsTest_c\.js/', $html,
'combined files are not included twice');
/* NORMAL REQUIREMENTS ARE STILL INCLUDED */
$this->assertRegExp('/src=".*\/RequirementsTest_a\.js/', $html,
'normal requirements are still included');
/* NORMAL REQUIREMENTS DON'T HAVE ASYNC/DEFER */
$this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" async/', $html,
'normal requirements don\'t have async');
$this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" defer/', $html,
'normal requirements don\'t have defer');
$this->assertNotRegExp('/src=".*\/RequirementsTest_a\.js\?m=\d+" async defer/', $html,
'normal requirements don\'t have async/defer');
unlink($combinedFilePath);
}
public function testCombinedCss() { public function testCombinedCss() {
$basePath = $this->getCurrentRelativePath(); $basePath = $this->getCurrentRelativePath();
/** @var Requirements_Backend $backend */ /** @var Requirements_Backend $backend */
@ -217,7 +386,9 @@ class RequirementsTest extends SapphireTest {
$basePath . '/RequirementsTest_print_a.css', $basePath . '/RequirementsTest_print_a.css',
$basePath . '/RequirementsTest_print_b.css' $basePath . '/RequirementsTest_print_b.css'
), ),
'print' array(
'media' => 'print'
)
); );
$html = $backend->includeInHTML(self::$html_template); $html = $backend->includeInHTML(self::$html_template);
@ -284,7 +455,7 @@ class RequirementsTest extends SapphireTest {
/* BLOCKED UNCOMBINED FILES ARE NOT INCLUDED */ /* BLOCKED UNCOMBINED FILES ARE NOT INCLUDED */
$this->setupCombinedRequirements($backend); $this->setupCombinedRequirements($backend);
$backend->block($basePath .'/RequirementsTest_b.js'); $backend->block($basePath .'/RequirementsTest_b.js');
$combinedFileName2 = '/_combinedfiles/RequirementsTest_bc-3748f67.js'; // SHA1 without file c included $combinedFileName2 = '/_combinedfiles/RequirementsTest_bc-3748f67.js'; // SHA1 without file b included
$combinedFilePath2 = AssetStoreTest_SpyStore::base_path() . $combinedFileName2; $combinedFilePath2 = AssetStoreTest_SpyStore::base_path() . $combinedFileName2;
clearstatcache(); // needed to get accurate file_exists() results clearstatcache(); // needed to get accurate file_exists() results
$html = $backend->includeInHTML(self::$html_template); $html = $backend->includeInHTML(self::$html_template);
@ -353,7 +524,7 @@ class RequirementsTest extends SapphireTest {
$this->assertTrue(count($backend->getJavascript()) == 1, $this->assertTrue(count($backend->getJavascript()) == 1,
"There should be only 1 file included in required javascript."); "There should be only 1 file included in required javascript.");
$this->assertTrue(in_array($basePath . '/a.js', $backend->getJavascript()), $this->assertArrayHasKey($basePath . '/a.js', $backend->getJavascript(),
"a.js should be included in required javascript."); "a.js should be included in required javascript.");
$backend->javascript($basePath . '/b.js'); $backend->javascript($basePath . '/b.js');
@ -363,9 +534,9 @@ class RequirementsTest extends SapphireTest {
$backend->block($basePath . '/a.js'); $backend->block($basePath . '/a.js');
$this->assertTrue(count($backend->getJavascript()) == 1, $this->assertTrue(count($backend->getJavascript()) == 1,
"There should be only 1 file included in required javascript."); "There should be only 1 file included in required javascript.");
$this->assertFalse(in_array($basePath . '/a.js', $backend->getJavascript()), $this->assertArrayNotHasKey($basePath . '/a.js', $backend->getJavascript(),
"a.js should not be included in required javascript after it has been blocked."); "a.js should not be included in required javascript after it has been blocked.");
$this->assertTrue(in_array($basePath . '/b.js', $backend->getJavascript()), $this->assertArrayHasKey($basePath . '/b.js', $backend->getJavascript(),
"b.js should be included in required javascript."); "b.js should be included in required javascript.");
$backend->css($basePath . '/a.css'); $backend->css($basePath . '/a.css');
@ -675,8 +846,7 @@ EOS
case 'js': case 'js':
case 'javascript': case 'javascript':
case 'script': case 'script':
$scripts = $backend->getJavascript(); return $backend->getJavascript();
return array_combine(array_values($scripts), array_values($scripts));
} }
return array(); return array();
} }

View File

@ -183,7 +183,7 @@ class SSViewerTest extends SapphireTest {
// secondly, make sure that requirements is generated, even though minification failed // secondly, make sure that requirements is generated, even though minification failed
$testBackend->processCombinedFiles(); $testBackend->processCombinedFiles();
$js = $testBackend->getJavascript(); $js = array_keys($testBackend->getJavascript());
$combinedTestFilePath = BASE_PATH . reset($js); $combinedTestFilePath = BASE_PATH . reset($js);
$this->assertContains('_combinedfiles/testRequirementsCombine-4c0e97a.js', $combinedTestFilePath); $this->assertContains('_combinedfiles/testRequirementsCombine-4c0e97a.js', $combinedTestFilePath);

View File

@ -112,6 +112,8 @@ class Requirements implements Flushable {
* @param string $file Relative to docroot * @param string $file Relative to docroot
* @param array $options List of options. Available options include: * @param array $options List of options. Available options include:
* - 'provides' : List of scripts files included in this file * - 'provides' : List of scripts files included in this file
* - 'async' : Boolean value to set async attribute to script tag
* - 'defer' : Boolean value to set defer attribute to script tag
*/ */
public static function javascript($file, $options = array()) { public static function javascript($file, $options = array()) {
self::backend()->javascript($file, $options); self::backend()->javascript($file, $options);
@ -337,12 +339,19 @@ class Requirements implements Flushable {
* *
* @param string $combinedFileName Filename of the combined file relative to docroot * @param string $combinedFileName Filename of the combined file relative to docroot
* @param array $files Array of filenames relative to docroot * @param array $files Array of filenames relative to docroot
* @param string $media * @param array $options Array of options for combining files. Available options are:
* - 'media' : If including CSS Files, you can specify a media type
* - 'async' : If including JavaScript Files, boolean value to set async attribute to script tag
* - 'defer' : If including JavaScript Files, boolean value to set defer attribute to script tag
* *
* @return bool|void * @return bool|void
*/ */
public static function combine_files($combinedFileName, $files, $media = null) { public static function combine_files($combinedFileName, $files, $options = array()) {
self::backend()->combineFiles($combinedFileName, $files, $media); if(is_string($options)) {
Deprecation::notice('4.0', 'Parameter media is deprecated. Use options array instead.');
$options = array('media' => $options);
}
self::backend()->combineFiles($combinedFileName, $files, $options);
} }
/** /**
@ -803,14 +812,37 @@ class Requirements_Backend
* @param string $file Relative to docroot * @param string $file Relative to docroot
* @param array $options List of options. Available options include: * @param array $options List of options. Available options include:
* - 'provides' : List of scripts files included in this file * - 'provides' : List of scripts files included in this file
* - 'async' : Boolean value to set async attribute to script tag
* - 'defer' : Boolean value to set defer attribute to script tag
*/ */
public function javascript($file, $options = array()) { public function javascript($file, $options = array()) {
$this->javascript[$file] = true; // make sure that async/defer is set if it is set once even if file is included multiple times
$async = (
isset($options['async']) && isset($options['async']) == true
|| (
isset($this->javascript[$file])
&& isset($this->javascript[$file]['async'])
&& $this->javascript[$file]['async'] == true
)
);
$defer = (
isset($options['defer']) && isset($options['defer']) == true
|| (
isset($this->javascript[$file])
&& isset($this->javascript[$file]['defer'])
&& $this->javascript[$file]['defer'] == true
)
);
$this->javascript[$file] = array(
'async' => $async,
'defer' => $defer,
);
// Record scripts included in this file // Record scripts included in this file
if(isset($options['provides'])) { if(isset($options['provides'])) {
$this->providedJavascript[$file] = array_values($options['provides']); $this->providedJavascript[$file] = array_values($options['provides']);
} }
} }
/** /**
@ -841,7 +873,7 @@ class Requirements_Backend
public function getProvidedScripts() { public function getProvidedScripts() {
$providedScripts = array(); $providedScripts = array();
$includedScripts = array(); $includedScripts = array();
foreach($this->javascript as $script => $flag) { foreach($this->javascript as $script => $options) {
// Ignore scripts that are explicitly blocked // Ignore scripts that are explicitly blocked
if(isset($this->blocked[$script])) { if(isset($this->blocked[$script])) {
continue; continue;
@ -869,11 +901,11 @@ class Requirements_Backend
* @return array * @return array
*/ */
public function getJavascript() { public function getJavascript() {
return array_keys(array_diff_key( return array_diff_key(
$this->javascript, $this->javascript,
$this->getBlocked(), $this->getBlocked(),
$this->getProvidedScripts() $this->getProvidedScripts()
)); );
} }
/** /**
@ -882,7 +914,7 @@ class Requirements_Backend
* @return array Indexed array of javascript files * @return array Indexed array of javascript files
*/ */
protected function getAllJavascript() { protected function getAllJavascript() {
return array_keys($this->javascript); return $this->javascript;
} }
/** /**
@ -1130,10 +1162,12 @@ class Requirements_Backend
// Combine files - updates $this->javascript and $this->css // Combine files - updates $this->javascript and $this->css
$this->processCombinedFiles(); $this->processCombinedFiles();
foreach($this->getJavascript() as $file) { foreach($this->getJavascript() as $file => $attributes) {
$async = (isset($attributes['async']) && $attributes['async'] == true) ? " async" : "";
$defer = (isset($attributes['defer']) && $attributes['defer'] == true) ? " defer" : "";
$path = Convert::raw2att($this->pathForFile($file)); $path = Convert::raw2att($this->pathForFile($file));
if($path) { if($path) {
$jsRequirements .= "<script type=\"application/javascript\" src=\"$path\"></script>"; $jsRequirements .= "<script type=\"application/javascript\" src=\"$path\"{$async}{$defer}></script>";
} }
} }
@ -1267,7 +1301,7 @@ class Requirements_Backend
$jsRequirements = array(); $jsRequirements = array();
$cssRequirements = array(); $cssRequirements = array();
foreach($this->getJavascript() as $file) { foreach($this->getJavascript() as $file => $attributes) {
$path = $this->pathForFile($file); $path = $this->pathForFile($file);
if($path) { if($path) {
$jsRequirements[] = str_replace(',', '%2C', $path); $jsRequirements[] = str_replace(',', '%2C', $path);
@ -1399,10 +1433,14 @@ class Requirements_Backend
* Example for combined JavaScript: * Example for combined JavaScript:
* <code> * <code>
* Requirements::combine_files( * Requirements::combine_files(
* 'foobar.js', * 'foobar.js',
* array( * array(
* 'mysite/javascript/foo.js', * 'mysite/javascript/foo.js',
* 'mysite/javascript/bar.js', * 'mysite/javascript/bar.js',
* ),
* array(
* 'async' => true,
* 'defer' => true,
* ) * )
* ); * );
* </code> * </code>
@ -1410,23 +1448,33 @@ class Requirements_Backend
* Example for combined CSS: * Example for combined CSS:
* <code> * <code>
* Requirements::combine_files( * Requirements::combine_files(
* 'foobar.css', * 'foobar.css',
* array( * array(
* 'mysite/javascript/foo.css', * 'mysite/javascript/foo.css',
* 'mysite/javascript/bar.css', * 'mysite/javascript/bar.css',
* ),
* array(
* 'media' => 'print',
* ) * )
* ); * );
* </code> * </code>
* *
* @param string $combinedFileName Filename of the combined file relative to docroot * @param string $combinedFileName Filename of the combined file relative to docroot
* @param array $files Array of filenames relative to docroot * @param array $files Array of filenames relative to docroot
* @param string $media If including CSS Files, you can specify a media type * @param array $options Array of options for combining files. Available options are:
* - 'media' : If including CSS Files, you can specify a media type
* - 'async' : If including JavaScript Files, boolean value to set async attribute to script tag
* - 'defer' : If including JavaScript Files, boolean value to set defer attribute to script tag
*/ */
public function combineFiles($combinedFileName, $files, $media = null) { public function combineFiles($combinedFileName, $files, $options = array()) {
if(is_string($options)) {
Deprecation::notice('4.0', 'Parameter media is deprecated. Use options array instead.');
$options = array('media' => $options);
}
// Skip this combined files if already included // Skip this combined files if already included
if(isset($this->combinedFiles[$combinedFileName])) { if(isset($this->combinedFiles[$combinedFileName])) {
return; return;
} }
// Add all files to necessary type list // Add all files to necessary type list
$paths = array(); $paths = array();
@ -1436,25 +1484,25 @@ class Requirements_Backend
list($path, $type) = $this->parseCombinedFile($file); list($path, $type) = $this->parseCombinedFile($file);
if($type === 'javascript') { if($type === 'javascript') {
$type = 'js'; $type = 'js';
} }
if($combinedType && $type && $combinedType !== $type) { if($combinedType && $type && $combinedType !== $type) {
throw new InvalidArgumentException( throw new InvalidArgumentException(
"Cannot mix js and css files in same combined file {$combinedFileName}" "Cannot mix js and css files in same combined file {$combinedFileName}"
); );
} }
switch($type) { switch($type) {
case 'css': case 'css':
$this->css($path, $media); $this->css($path, (isset($options['media']) ? $options['media'] : null));
break; break;
case 'js': case 'js':
$this->javascript($path); $this->javascript($path, $options);
break; break;
default: default:
throw new InvalidArgumentException("Invalid combined file type: {$type}"); throw new InvalidArgumentException("Invalid combined file type: {$type}");
} }
$combinedType = $type; $combinedType = $type;
$paths[] = $path; $paths[] = $path;
} }
// Duplicate check // Duplicate check
foreach($this->combinedFiles as $existingCombinedFilename => $combinedItem) { foreach($this->combinedFiles as $existingCombinedFilename => $combinedItem) {
@ -1466,15 +1514,15 @@ class Requirements_Backend
implode(',', $duplicates), implode(',', $duplicates),
$existingCombinedFilename $existingCombinedFilename
)); ));
} }
} }
$this->combinedFiles[$combinedFileName] = array( $this->combinedFiles[$combinedFileName] = array(
'files' => $paths, 'files' => $paths,
'type' => $combinedType, 'type' => $combinedType,
'media' => $media 'options' => $options,
); );
} }
/** /**
* Return path and type of given combined file * Return path and type of given combined file
@ -1559,7 +1607,7 @@ class Requirements_Backend
foreach($this->getAllCombinedFiles() as $combinedFile => $combinedItem) { foreach($this->getAllCombinedFiles() as $combinedFile => $combinedItem) {
$fileList = $combinedItem['files']; $fileList = $combinedItem['files'];
$type = $combinedItem['type']; $type = $combinedItem['type'];
$media = $combinedItem['media']; $options = $combinedItem['options'];
// Generate this file, unless blocked // Generate this file, unless blocked
$combinedURL = null; $combinedURL = null;
@ -1585,7 +1633,7 @@ class Requirements_Backend
if(!in_array($css, $fileList)) { if(!in_array($css, $fileList)) {
$newCSS[$css] = $spec; $newCSS[$css] = $spec;
} elseif(!$included && $combinedURL) { } elseif(!$included && $combinedURL) {
$newCSS[$combinedURL] = array('media' => $media); $newCSS[$combinedURL] = array('media' => (isset($options['media']) ? $options['media'] : null));
$included = true; $included = true;
} }
// If already included, or otherwise blocked, then don't add into CSS // If already included, or otherwise blocked, then don't add into CSS
@ -1594,13 +1642,13 @@ class Requirements_Backend
break; break;
} }
case 'js': { case 'js': {
// Assoc array of file => true // Assoc array of file => attributes
$newJS = array(); $newJS = array();
foreach($this->getAllJavascript() as $script) { foreach($this->getAllJavascript() as $script => $attributes) {
if(!in_array($script, $fileList)) { if(!in_array($script, $fileList)) {
$newJS[$script] = true; $newJS[$script] = $attributes;
} elseif(!$included && $combinedURL) { } elseif(!$included && $combinedURL) {
$newJS[$combinedURL] = true; $newJS[$combinedURL] = $options;
$included = true; $included = true;
} }
// If already included, or otherwise blocked, then don't add into scripts // If already included, or otherwise blocked, then don't add into scripts