diff --git a/cake/libs/view/helpers/javascript.php b/cake/libs/view/helpers/javascript.php index b3baf17d4..688193bd9 100644 --- a/cake/libs/view/helpers/javascript.php +++ b/cake/libs/view/helpers/javascript.php @@ -142,7 +142,7 @@ class JavascriptHelper extends AppHelper { } switch ($key) { case 'cache': - + break; case 'safe': $this->safe = $val; @@ -174,7 +174,8 @@ class JavascriptHelper extends AppHelper { $this->_cachedEvents[] = $script; } else { $block = ($script !== null); - if (($options['safe'] || $this->safe) && !($this->_cacheAll && $options['allowCache'])) { + $safe = ($options['safe'] || $this->safe); + if ($safe && !($this->_cacheAll && $options['allowCache'])) { $script = "\n" . '//' . "\n"; @@ -188,13 +189,15 @@ class JavascriptHelper extends AppHelper { @ob_end_clean(); ob_start(); return null; + } else if (!$block) { + $this->_blockOptions = $options; } if ($options['inline']) { if ($block) { return sprintf($this->tags['javascriptblock'], $script); } else { - return sprintf($this->tags['javascriptstart']); + return sprintf($this->tags['javascriptstart']).ife($safe, "\n" . '//__scriptBuffer; $this->__scriptBuffer = null; $options = $this->_blockOptions; + $safe = ($options['safe'] || $this->safe); $this->_blockOptions = array(); $this->inBlock = false; @@ -226,7 +230,7 @@ class JavascriptHelper extends AppHelper { $this->_cachedEvents[] = $script; return null; } - return $this->tags['javascriptend']; + return ife($safe, "\n" . '//]]>' . "\n", '').$this->tags['javascriptend']; } /** * Returns a JavaScript include tag (SCRIPT element). If the filename is prefixed with "/", diff --git a/cake/tests/cases/libs/view/helpers/javascript.test.php b/cake/tests/cases/libs/view/helpers/javascript.test.php index f30bc6f12..4e02db593 100644 --- a/cake/tests/cases/libs/view/helpers/javascript.test.php +++ b/cake/tests/cases/libs/view/helpers/javascript.test.php @@ -33,6 +33,15 @@ class TheJsTestController extends Controller { var $name = 'TheTest'; var $uses = null; } +class TheView extends View { + function scripts() { + return $this->__scripts; + } +} +class TestJavascriptObject { + var $property1 = 'value1'; + var $property2 = 2; +} /** * Short description for class. * @@ -41,13 +50,20 @@ class TheJsTestController extends Controller { * @since CakePHP Test Suite v 1.0.0.0 */ class JavascriptTest extends UnitTestCase { - function setUp() { - $this->Javascript = new JavascriptHelper(); - $this->Javascript->Html = new HtmlHelper(); - $this->Javascript->Form = new FormHelper(); - $view =& new View(new TheJsTestController()); - ClassRegistry::addObject('view', $view); + $this->Javascript =& new JavascriptHelper(); + $this->Javascript->Html =& new HtmlHelper(); + $this->Javascript->Form =& new FormHelper(); + $this->View =& new TheView(new TheJsTestController()); + ClassRegistry::addObject('view', $this->View); + } + + function tearDown() { + unset($this->Javascript->Html); + unset($this->Javascript->Form); + unset($this->Javascript); + ClassRegistry::removeObject('view'); + unset($this->View); } function testLink() { @@ -86,6 +102,23 @@ class JavascriptTest extends UnitTestCase { $result = $this->Javascript->link('some_other_path/myfile.1.2.2.min'); $expected = ''; $this->assertEqual($result, $expected); + + $result = $this->Javascript->link('http://example.com/jquery.js'); + $expected = ''; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->link(array('prototype.js', 'scriptaculous.js')); + $this->assertPattern('/^\s*]*><\/script>/', $result); + $this->assertPattern('/<\/script>\s*]+>/', $result); + $this->assertPattern('/]*><\/script>\s*$/', $result); + + $result = $this->Javascript->link('jquery-1.1.2', false); + $resultScripts = $this->View->scripts(); + reset($resultScripts); + $expected = ''; + $this->assertNull($result); + $this->assertEqual(count($resultScripts), 1); + $this->assertEqual(current($resultScripts), $expected); } function testFilteringAndTimestamping() { @@ -99,7 +132,7 @@ class JavascriptTest extends UnitTestCase { Configure::write('Asset.timestamp', true); $result = $this->Javascript->link('__cake_js_test'); - $this->assertPattern('/^]+src=".*js\/__cake_js_test.js\?' . $timestamp . '[0-9]{2}"[^<>]*>/', $result); + $this->assertPattern('/^]+src=".*js\/__cake_js_test\.js\?' . $timestamp . '[0-9]{2}"[^<>]*>/', $result); $debug = Configure::read('debug'); Configure::write('debug', 0); @@ -114,17 +147,67 @@ class JavascriptTest extends UnitTestCase { Configure::write('debug', $debug); Configure::write('Asset.timestamp', false); + $old = Configure::read('Asset.filter.js'); + Configure::write('Asset.filter.js', 'js.php'); $result = $this->Javascript->link('__cake_js_test'); - $this->assertPattern('/^]+src=".*cjs\/__cake_js_test.js"[^<>]*>/', $result); - Configure::write('Asset.filter.js', false); + $this->assertPattern('/^]+src=".*cjs\/__cake_js_test\.js"[^<>]*>/', $result); + + Configure::write('Asset.filter.js', true); + $result = $this->Javascript->link('jquery-1.1.2'); + $expected = ''; + $this->assertEqual($result, $expected); + + if ($old === null) { + Configure::delete('Asset.filter.js'); + } unlink(JS . '__cake_js_test.js'); } + function testValue() { + $result = $this->Javascript->value(array('title' => 'New thing', 'indexes' => array(5, 6, 7, 8))); + $expected = '{"title":"New thing","indexes":[5,6,7,8]}'; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->value(null); + $this->assertEqual($result, 'null'); + + $result = $this->Javascript->value(true); + $this->assertEqual($result, 'true'); + + $result = $this->Javascript->value(false); + $this->assertEqual($result, 'false'); + + $result = $this->Javascript->value(5); + $this->assertEqual($result, '5'); + + $result = $this->Javascript->value(floatval(5.3)); + $this->assertPattern('/^5.3[0]+$/', $result); + + $result = $this->Javascript->value(''); + $expected = '""'; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->value('CakePHP' . "\n" . 'Rapid Development Framework'); + $expected = '"CakePHP\\nRapid Development Framework"'; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->value('CakePHP' . "\r\n" . 'Rapid Development Framework' . "\r" . 'For PHP'); + $expected = '"CakePHP\\nRapid Development Framework\\nFor PHP"'; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->value('CakePHP: "Rapid Development Framework"'); + $expected = '"CakePHP: \\"Rapid Development Framework\\""'; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->value('CakePHP: \'Rapid Development Framework\''); + $expected = '"CakePHP: \\\'Rapid Development Framework\\\'"'; + $this->assertEqual($result, $expected); + } + function testObjectGeneration() { $object = array('title' => 'New thing', 'indexes' => array(5, 6, 7, 8)); - $result = $this->Javascript->object($object); $expected = '{"title":"New thing","indexes":[5,6,7,8]}'; $this->assertEqual($result, $expected); @@ -153,11 +236,27 @@ class JavascriptTest extends UnitTestCase { $expected = '{"Object":{"1":true,"2":false,"3":-3.14159265359,"4":-10}}'; $this->assertEqual($result, $expected); - if ($this->Javascript->useNative) { - $this->Javascript->useNative = false; - $this->testObjectGeneration(); + if (function_exists('json_encode')) { + $old = $this->Javascript->useNative; $this->Javascript->useNative = true; + $object = array('title' => 'New thing', 'indexes' => array(5, 6, 7, 8)); + $result = $this->Javascript->object($object); + $expected = '{"title":"New thing","indexes":[5,6,7,8]}'; + $this->assertEqual($result, $expected); + $this->Javascript->useNative = $old; } + + $result = $this->Javascript->object(new TestJavascriptObject()); + $expected = '{"property1":"value1","property2":2}'; + $this->assertEqual($result, $expected); + + $object = array('title' => 'New thing', 'indexes' => array(5, 6, 7, 8)); + $result = $this->Javascript->object($object, array('block' => true)); + $expected = '{"title":"New thing","indexes":[5,6,7,8]}'; + $this->assertPattern('/^]+>\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript">.+<\/script>$/s', $result); + $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); + $this->assertNoPattern('/^]*>/', $result); } function testScriptBlock() { @@ -167,12 +266,43 @@ class JavascriptTest extends UnitTestCase { $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); $this->assertNoPattern('/^]*>/', $result); + $result = $this->Javascript->codeBlock('something', false, false); + $this->assertPattern('/^]+>something<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript">something<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); + $this->assertNoPattern('/^]*>/', $result); + + $result = $this->Javascript->codeBlock('something', true, true); + $this->assertPattern('/^]+>\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript">\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); + $this->assertNoPattern('/^]*>/', $result); + + $result = $this->Javascript->codeBlock('something', false, true); + $this->assertPattern('/^]+>\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript">\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); + $this->assertNoPattern('/^]*>/', $result); + $result = $this->Javascript->codeBlock('something', array('safe' => false)); $this->assertPattern('/^]+>something<\/script>$/', $result); $this->assertPattern('/^]+type="text\/javascript">something<\/script>$/', $result); $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); $this->assertNoPattern('/^]*>/', $result); + $result = $this->Javascript->codeBlock('something', array('safe' => true)); + $this->assertPattern('/^]+>\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript">\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); + $this->assertNoPattern('/^]*>/', $result); + + $result = $this->Javascript->codeBlock(null, array('safe' => true, 'allowCache' => false)); + $this->assertPattern('/^]+>\s*' . str_replace('/', '\\/', preg_quote('//assertNoPattern('/^]*>/', $result); + + $result = $this->Javascript->blockEnd(); + $this->assertPattern('/^\s*' . str_replace('/', '\\/', preg_quote('//]]>')) . '\s*<\/script>$/', $result); + $result = $this->Javascript->codeBlock('something'); $this->assertPattern('/^]+>\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); $this->assertPattern('/^]+type="text\/javascript">.+<\/script>$/s', $result); @@ -180,11 +310,11 @@ class JavascriptTest extends UnitTestCase { $this->assertNoPattern('/^]*>/', $result); $result = $this->Javascript->codeBlock(); - $this->assertPattern('/^]+>$/', $result); + $this->assertPattern('/^]+>\s*' . str_replace('/', '\\/', preg_quote('//assertNoPattern('/^]*>/', $result); $result = $this->Javascript->blockEnd(); - $this->assertEqual("", $result); + $this->assertPattern('/^\s*' . str_replace('/', '\\/', preg_quote('//]]>')) . '\s*<\/script>$/', $result); $this->Javascript->cacheEvents(false, true); $this->assertFalse($this->Javascript->inBlock); @@ -207,8 +337,6 @@ class JavascriptTest extends UnitTestCase { $this->Javascript->codeBlock(null, array('inline' => false)); echo '$(function(){ /* ... */ });'; $this->Javascript->blockEnd(); - - $view =& ClassRegistry::getObject('view'); } function testEvent() { @@ -223,10 +351,132 @@ class JavascriptTest extends UnitTestCase { $this->assertPattern('/^]+type="text\/javascript">' . str_replace('/', '\\/', preg_quote('Event.observe($(\'myId\'), \'click\', function(event) { something(); }, false);')) . '<\/script>$/', $result); $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); $this->assertNoPattern('/^]*>/', $result); + + $result = $this->Javascript->event('myId', 'click'); + $this->assertPattern('/^]+>\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript">.+' . str_replace('/', '\\/', preg_quote('Event.observe($(\'myId\'), \'click\', function(event) { }, false);')) . '.+<\/script>$/s', $result); + $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); + $this->assertNoPattern('/^]*>/', $result); + + $result = $this->Javascript->event('myId', 'click', 'something();', false); + $this->assertPattern('/^]+>\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript">.+' . str_replace('/', '\\/', preg_quote('Event.observe($(\'myId\'), \'click\', function(event) { something(); }, false);')) . '.+<\/script>$/s', $result); + $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); + $this->assertNoPattern('/^]*>/', $result); + + $result = $this->Javascript->event('myId', 'click', 'something();', array('useCapture' => true)); + $this->assertPattern('/^]+>\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript">.+' . str_replace('/', '\\/', preg_quote('Event.observe($(\'myId\'), \'click\', function(event) { something(); }, true);')) . '.+<\/script>$/s', $result); + $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); + $this->assertNoPattern('/^]*>/', $result); + + $result = $this->Javascript->event('document', 'load'); + $this->assertPattern('/^]+>\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript">.+' . str_replace('/', '\\/', preg_quote('Event.observe(document, \'load\', function(event) { }, false);')) . '.+<\/script>$/s', $result); + $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); + $this->assertNoPattern('/^]*>/', $result); + + $result = $this->Javascript->event('$(\'myId\')', 'click', 'something();', array('safe' => false)); + $this->assertPattern('/^]+>[^<>]+<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript">' . str_replace('/', '\\/', preg_quote('Event.observe($(\'myId\'), \'click\', function(event) { something(); }, false);')) . '<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); + $this->assertNoPattern('/^]*>/', $result); + + $result = $this->Javascript->event('\'document\'', 'load', 'something();', array('safe' => false)); + $this->assertPattern('/^]+>[^<>]+<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript">' . str_replace('/', '\\/', preg_quote('Event.observe(\'document\', \'load\', function(event) { something(); }, false);')) . '<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); + $this->assertNoPattern('/^]*>/', $result); + + $this->Javascript->cacheEvents(); + $result = $this->Javascript->event('myId', 'click', 'something();'); + $this->assertNull($result); + + $result = $this->Javascript->getCache(); + $this->assertPattern('/^' . str_replace('/', '\\/', preg_quote('Event.observe($(\'myId\'), \'click\', function(event) { something(); }, false);')) . '$/s', $result); + + $result = $this->Javascript->event('#myId', 'alert(event);'); + $this->assertNull($result); + + $result = $this->Javascript->getCache(); + $this->assertPattern('/^\s*var Rules = {\s*\'#myId\': function\(element, event\)\s*{\s*alert\(event\);\s*}\s*}\s*EventSelectors\.start\(Rules\);\s*$/s', $result); } - function tearDown() { - unset($this->Javascript); + function testWriteEvents() { + $this->Javascript->cacheEvents(); + $result = $this->Javascript->event('myId', 'click', 'something();'); + $this->assertNull($result); + + $result = $this->Javascript->writeEvents(); + $this->assertPattern('/^]+>\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript">.+' . str_replace('/', '\\/', preg_quote('Event.observe($(\'myId\'), \'click\', function(event) { something(); }, false);')) . '.+<\/script>$/s', $result); + $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); + $this->assertNoPattern('/^]*>/', $result); + + $result = $this->Javascript->getCache(); + $this->assertTrue(empty($result)); + + $this->Javascript->cacheEvents(); + $result = $this->Javascript->event('myId', 'click', 'something();'); + $this->assertNull($result); + + $result = $this->Javascript->writeEvents(false); + $resultScripts = $this->View->scripts(); + reset($resultScripts); + $this->assertNull($result); + $this->assertEqual(count($resultScripts), 1); + $result = current($resultScripts); + $this->assertPattern('/^]+>\s*' . str_replace('/', '\\/', preg_quote('//')) . '\s*<\/script>$/', $result); + $this->assertPattern('/^]+type="text\/javascript">.+' . str_replace('/', '\\/', preg_quote('Event.observe($(\'myId\'), \'click\', function(event) { something(); }, false);')) . '.+<\/script>$/s', $result); + $this->assertPattern('/^]+type="text\/javascript"[^<>]*>/', $result); + $this->assertNoPattern('/^]*>/', $result); + + $result = $this->Javascript->getCache(); + $this->assertTrue(empty($result)); + } + + function testEscapeScript() { + $result = $this->Javascript->escapeScript(''); + $expected = ''; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->escapeScript('CakePHP' . "\n" . 'Rapid Development Framework'); + $expected = 'CakePHP\\nRapid Development Framework'; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->escapeScript('CakePHP' . "\r\n" . 'Rapid Development Framework' . "\r" . 'For PHP'); + $expected = 'CakePHP\\nRapid Development Framework\\nFor PHP'; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->escapeScript('CakePHP: "Rapid Development Framework"'); + $expected = 'CakePHP: \\"Rapid Development Framework\\"'; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->escapeScript('CakePHP: \'Rapid Development Framework\''); + $expected = 'CakePHP: \\\'Rapid Development Framework\\\''; + $this->assertEqual($result, $expected); + } + + function testEscapeString() { + $result = $this->Javascript->escapeString(''); + $expected = ''; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->escapeString('CakePHP' . "\n" . 'Rapid Development Framework'); + $expected = 'CakePHP\\nRapid Development Framework'; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->escapeString('CakePHP' . "\r\n" . 'Rapid Development Framework' . "\r" . 'For PHP'); + $expected = 'CakePHP\\nRapid Development Framework\\nFor PHP'; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->escapeString('CakePHP: "Rapid Development Framework"'); + $expected = 'CakePHP: \\"Rapid Development Framework\\"'; + $this->assertEqual($result, $expected); + + $result = $this->Javascript->escapeString('CakePHP: \'Rapid Development Framework\''); + $expected = 'CakePHP: \\\'Rapid Development Framework\\\''; + $this->assertEqual($result, $expected); } }