Merge pull request #2684 from Firesphere/feature/force_write_js_to_bottom

NEW Forcefully write javascripts to the end of the HTML if wished
This commit is contained in:
Ingo Schommer 2013-12-19 09:21:06 -08:00
commit 78a530524b
2 changed files with 89 additions and 2 deletions

View File

@ -350,6 +350,55 @@ class RequirementsTest extends SapphireTest {
$this->assertContains('</script></body>', $html);
}
public function testForceJsToBottom() {
$backend = new Requirements_Backend();
$backend->javascript('http://www.mydomain.com/test.js');
// Test matching with HTML5 <header> tags as well
$template = '<html><head></head><body><header>My header</header><p>Body<script></script></p></body></html>';
// The expected outputs
$JsInHead = "<html><head><script type=\"text/javascript\" src=\"http://www.mydomain.com/test.js\"></script>\n</head><body><header>My header</header><p>Body<script></script></p></body></html>";
$JsInBody = "<html><head></head><body><header>My header</header><p>Body<script type=\"text/javascript\" src=\"http://www.mydomain.com/test.js\"></script><script></script></p></body></html>";
$JsAtEnd = "<html><head></head><body><header>My header</header><p>Body<script></script></p><script type=\"text/javascript\" src=\"http://www.mydomain.com/test.js\"></script></body></html>";
// Test if the script is before the head tag, not before the body.
// Expected: $JsInHead
$backend->set_write_js_to_body(false);
$backend->set_force_js_to_bottom(false);
$html = $backend->includeInHTML(false, $template);
$this->assertNotEquals($JsInBody, $html);
$this->assertNotEquals($JsAtEnd, $html);
$this->assertEquals($JsInHead, $html);
// Test if the script is before the first <script> tag, not before the body.
// Expected: $JsInBody
$backend->set_write_js_to_body(true);
$backend->set_force_js_to_bottom(false);
$html = $backend->includeInHTML(false, $template);
$this->assertNotEquals($JsAtEnd, $html);
$this->assertEquals($JsInBody, $html);
// Test if the script is placed just before the closing bodytag, with write-to-body false.
// Expected: $JsAtEnd
$backend->set_write_js_to_body(false);
$backend->set_force_js_to_bottom(true);
$html = $backend->includeInHTML(false, $template);
$this->assertNotEquals($JsInHead, $html);
$this->assertNotEquals($JsInBody, $html);
$this->assertEquals($JsAtEnd, $html);
// Test if the script is placed just before the closing bodytag, with write-to-body true.
// Expected: $JsAtEnd
$backend->set_write_js_to_body(true);
$backend->set_force_js_to_bottom(true);
$html = $backend->includeInHTML(false, $template);
$this->assertNotEquals($JsInHead, $html);
$this->assertNotEquals($JsInBody, $html);
$this->assertEquals($JsAtEnd, $html);
}
public function testSuffix() {
$template = '<html><head></head><body><header>My header</header><p>Body</p></body></html>';
$basePath = $this->getCurrentRelativePath();

View File

@ -308,6 +308,17 @@ class Requirements {
self::backend()->set_write_js_to_body($var);
}
/**
* Set the javascript to be forced to end of the HTML, or use the default.
* Useful if you use inline <script> tags, that don't need the javascripts
* included via Requirements::require();
*
* @param boolean $var If true, force the javascripts to be included at the bottom.
*/
public static function set_force_js_to_bottom($var) {
self::backend()->set_force_js_to_bottom($var);
}
public static function debug() {
return self::backend()->debug();
}
@ -436,7 +447,15 @@ class Requirements_Backend {
* @var boolean
*/
public $write_js_to_body = true;
/**
* Force the javascripts to the bottom of the page, even if there's a
* <script> tag in the body already
*
* @var boolean
*/
protected $force_js_to_bottom = false;
public function set_combined_files_enabled($enable) {
$this->combined_files_enabled = (bool) $enable;
}
@ -487,6 +506,14 @@ class Requirements_Backend {
public function set_write_js_to_body($var) {
$this->write_js_to_body = $var;
}
/**
* Forces the javascript to the end of the body, just before the closing body-tag.
*
* @param boolean
*/
public function set_force_js_to_bottom($var) {
$this->force_js_to_bottom = $var;
}
/**
* Register the given javascript file as required.
* Filenames should be relative to the base, eg, 'framework/javascript/loader.js'
@ -701,7 +728,18 @@ class Requirements_Backend {
$requirements .= "$customHeadTag\n";
}
if($this->write_js_to_body) {
if ($this->force_js_to_bottom) {
// Remove all newlines from code to preserve layout
$jsRequirements = preg_replace('/>\n*/', '>', $jsRequirements);
// We put script tags into the body, for performance.
// We forcefully put it at the bottom instead of before
// the first script-tag occurence
$content = preg_replace("/(<\/body[^>]*>)/i", $jsRequirements . "\\1", $content);
// Put CSS at the bottom of the head
$content = preg_replace("/(<\/head>)/i", $requirements . "\\1", $content);
} elseif($this->write_js_to_body) {
// Remove all newlines from code to preserve layout
$jsRequirements = preg_replace('/>\n*/', '>', $jsRequirements);