diff --git a/cake/libs/view/helpers/js.php b/cake/libs/view/helpers/js.php index 65a838669..5fc73d92e 100644 --- a/cake/libs/view/helpers/js.php +++ b/cake/libs/view/helpers/js.php @@ -39,7 +39,7 @@ class JsHelper extends AppHelper { * * @var array **/ - var $helpers = array('Html'); + var $helpers = array('Html', 'Form'); /** * Scripts that are queued for output * @@ -205,9 +205,13 @@ class JsHelper extends AppHelper { * element that is enhanced with Javascript. Options can include * both those for HtmlHelper::link() and JsBaseEngine::request(), JsBaseEngine::event(); * - * ### Options + * ### Options * - * - confirm - Generate a confirm() dialog before sending the event. + * - confirm - Generate a confirm() dialog before sending the event. + * - id - use a custom id. + * - htmlAttrs - additional non-standard htmlAttributes. Standard attributes are class, id, + * rel, title, escape, onblur and onfocus. + * - buffer - Disable the buffering and return a script tag in addition to the link. * * @param string $title Title for the link. * @param mixed $url Mixed either a string URL or an cake url array. @@ -223,13 +227,15 @@ class JsHelper extends AppHelper { $this->get('#' . $htmlOptions['id']); $requestString = ''; if (isset($options['confirm'])) { - $requestString .= 'var _confirm = ' . $this->confirm($options['confirm']); - $requestString .= "if (!_confirm) {\n\treturn false;\n}"; + $requestString = $this->confirmReturn($options['confirm']); unset($options['confirm']); } $requestString .= $this->request($url, $options); if (!empty($requestString)) { - $this->event('click', $requestString, $options); + $event = $this->event('click', $requestString, $options); + } + if (isset($options['buffer']) && $options['buffer'] == false) { + $out .= $this->Html->scriptBlock($event, $options); } return $out; } @@ -242,18 +248,40 @@ class JsHelper extends AppHelper { * @param array $options Array of options to use. * @return string Completed submit button. **/ - function submit($title, $options = array()) { - + function submit($caption = null, $options = array()) { + if (!isset($options['id'])) { + $options['id'] = 'submit-' . intval(mt_rand()); + } + $formOptions = array('div'); + $htmlOptions = $this->_getHtmlOptions($options, $formOptions); + $out = $this->Form->submit($caption, $htmlOptions); + + $this->get('#' . $htmlOptions['id']); + $options['data'] = $this->serializeForm('#' . $htmlOptions); + $requestString = ''; + if (isset($options['confirm'])) { + $requestString = $this->confirmReturn($options['confirm']); + unset($options['confirm']); + } + $requestString .= $this->request('', $options); + if (!empty($requestString)) { + $event = $this->event('click', $requestString, $options); + } + if (isset($options['buffer']) && $options['buffer'] == false) { + $out .= $this->Html->scriptBlock($event, $options); + } + return $out; } /** * Parse a set of Options and extract the Html options. * Extracted Html Options are removed from the $options param. * - * @param array Options to filter. + * @param array $options Options to filter. + * @param array $additional Array of additional keys to extract and include in the return options array. * @return array Array of options for non-js. **/ - function _getHtmlOptions(&$options) { - $htmlKeys = array('class', 'id', 'escape', 'onblur', 'onfocus', 'rel', 'title'); + function _getHtmlOptions(&$options, $additional = array()) { + $htmlKeys = array_merge(array('class', 'id', 'escape', 'onblur', 'onfocus', 'rel', 'title'), $additional); $htmlOptions = array(); foreach ($htmlKeys as $key) { if (isset($options[$key])) { @@ -261,6 +289,10 @@ class JsHelper extends AppHelper { } unset($options[$key]); } + if (isset($options['htmlAttributes'])) { + $htmlOptions = array_merge($htmlOptions, $options['htmlAttributes']); + unset($options['htmlAttributes']); + } return $htmlOptions; } } @@ -340,6 +372,19 @@ class JsBaseEngineHelper extends AppHelper { function confirm($message) { return 'confirm("' . $this->escape($message) . '");'; } +/** + * Generate a confirm snippet that returns false from the current + * function scope. + * + * @param string $message Message to use in the confirm dialog. + * @access public + * @return string + **/ + function confirmReturn($message) { + $out = 'var _confirm = ' . $this->confirm($message); + $out .= "if (!_confirm) {\n\treturn false;\n}"; + return $out; + } /** * Create a prompt() Javascript function * @@ -744,6 +789,16 @@ class JsBaseEngineHelper extends AppHelper { function slider() { trigger_error(sprintf(__('%s does not have slider() implemented', true), get_class($this)), E_USER_WARNING); } +/** + * serializeForm + * + * @return string Completed form serialization script + **/ + function serializeForm() { + trigger_error( + sprintf(__('%s does not have serializeForm() implemented', true), get_class($this)), E_USER_WARNING + ); + } /** * Parse an options assoc array into an Javascript object literal. * Similar to object() but treats any non-integer value as a string, diff --git a/cake/tests/cases/libs/view/helpers/js.test.php b/cake/tests/cases/libs/view/helpers/js.test.php index 33ca8d540..9fe7ac005 100644 --- a/cake/tests/cases/libs/view/helpers/js.test.php +++ b/cake/tests/cases/libs/view/helpers/js.test.php @@ -20,7 +20,7 @@ * @since CakePHP(tm) v 1.3 * @license http://www.opensource.org/licenses/opengroup.php The Open Group Test Suite License */ -App::import('Helper', array('Js', 'Html')); +App::import('Helper', array('Js', 'Html', 'Form')); App::import('Core', array('View', 'ClassRegistry')); Mock::generate('JsBaseEngineHelper', 'TestJsEngineHelper', array('methodOne')); @@ -80,6 +80,8 @@ class JsHelperTestCase extends CakeTestCase { function startTest() { $this->Js =& new JsHelper('JsBase'); $this->Js->Html =& new HtmlHelper(); + $this->Js->Form =& new FormHelper(); + $this->Js->Form->Html =& new HtmlHelper(); $this->Js->JsBaseEngine =& new JsBaseEngineHelper(); $view =& new JsHelperMockView(); @@ -104,6 +106,8 @@ class JsHelperTestCase extends CakeTestCase { $this->Js =& new JsHelper(array('TestJs')); $this->Js->TestJsEngine =& new TestJsEngineHelper($this); $this->Js->Html =& new HtmlHelper(); + $this->Js->Form =& new FormHelper(); + $this->Js->Form->Html =& new HtmlHelper(); } /** * test object construction @@ -112,16 +116,16 @@ class JsHelperTestCase extends CakeTestCase { **/ function testConstruction() { $js =& new JsHelper(); - $this->assertEqual($js->helpers, array('Html', 'JqueryEngine')); + $this->assertEqual($js->helpers, array('Html', 'Form', 'JqueryEngine')); $js =& new JsHelper(array('mootools')); - $this->assertEqual($js->helpers, array('Html', 'mootoolsEngine')); + $this->assertEqual($js->helpers, array('Html', 'Form', 'mootoolsEngine')); $js =& new JsHelper('prototype'); - $this->assertEqual($js->helpers, array('Html', 'prototypeEngine')); + $this->assertEqual($js->helpers, array('Html', 'Form', 'prototypeEngine')); $js =& new JsHelper('MyPlugin.Dojo'); - $this->assertEqual($js->helpers, array('Html', 'MyPlugin.DojoEngine')); + $this->assertEqual($js->helpers, array('Html', 'Form', 'MyPlugin.DojoEngine')); } /** * test that methods dispatch internally and to the engine class @@ -264,7 +268,7 @@ class JsHelperTestCase extends CakeTestCase { '/a' ); $this->assertTags($result, $expected); - + $options = array( 'confirm' => 'Are you sure?', 'update' => '#content', @@ -288,6 +292,52 @@ CODE; '/a' ); $this->assertTags($result, $expected); + + $options = array('id' => 'something', 'htmlAttributes' => array('arbitrary' => 'value', 'batman' => 'robin')); + $result = $this->Js->link('test link', '/posts/view/1', $options); + $expected = array( + 'a' => array('id' => $options['id'], 'href' => '/posts/view/1', 'arbitrary' => 'value', + 'batman' => 'robin'), + 'test link', + '/a' + ); + $this->assertTags($result, $expected); + } +/** + * test that link() and no buffering returns an and