diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..187adb2 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +/nbproject/ \ No newline at end of file diff --git a/Test/Case/View/Helper/Bs3FormHelperTest.php b/Test/Case/View/Helper/Bs3FormHelperTest.php index 5f7ad61..59d0d89 100644 --- a/Test/Case/View/Helper/Bs3FormHelperTest.php +++ b/Test/Case/View/Helper/Bs3FormHelperTest.php @@ -1095,4 +1095,138 @@ public function testInputGroup() { ); $this->assertTags($result, $expected); } + +/** + * testPostLink method + * + * @return void + */ + public function testPostLink() { + $result = $this->Form->postLink('Delete', '/posts/delete/1', array(), array('confirm' => 'Confirm?')); + $expected = array( + array('form' => array('method' => 'post', 'action' => '/posts/delete/1','name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;')), + array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), + '/form', + array('a' => array('href' => '#', 'onclick' => 'event.returnValue = false; return false;', 'data-toggle' => 'modal', 'data-target' => 'preg:/#post_\w+-modal/')), + 'Delete', + '/a', + array('div' => array('class' => 'modal fade text-left','id' => 'preg:/post_\w+\-modal/','tabindex' => '-1','role' => 'dialog','aria-labelledby' => 'preg:/#post_\w+-label/','aria-hidden' => 'true')), + array('div' => array('class' => 'modal-dialog')), + array('div' => array('class' => 'modal-content')), + array('div' => array('class' => 'modal-header')), + array('button' => array('type' => 'button','class' => 'close','data-dismiss' => 'modal','aria-hidden' => 'true')), + '×', + '/button', + array('h4' => array('class' => 'modal-title','id' => 'preg:/#post_\w+-label/')), + 'Confirmation Dialog', + '/h4', + '/div', + array('div' => array('class' => 'modal-body')), + 'Confirm?', + '/div', + array('div' => array('class' => 'modal-footer')), + array('button' => array('type' => 'button','class' => 'btn btn-default','data-dismiss' => 'modal')), + 'No', + '/button', + array('a' => array('href' => '#','class' => 'btn btn-primary','onclick' => 'preg:/document\.post_\w+\.submit\(\)\;/')), + 'Yes', + '/a', + '/div', + '/div', + '/div', + '/div' + ); + $this->assertTags($result, $expected); + + $result = $this->Form->postLink('Delete', '/posts/delete/1', array('escape' => false), '\'Confirm\' this "deletion"?'); + $expected = array( + array('form' => array('method' => 'post', 'action' => '/posts/delete/1','name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;')), + array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), + '/form', + array('a' => array('href' => '#', 'onclick' => 'event.returnValue = false; return false;', 'data-toggle' => 'modal', 'data-target' => 'preg:/#post_\w+-modal/')), + 'Delete', + '/a', + array('div' => array('class' => 'modal fade text-left','id' => 'preg:/post_\w+\-modal/','tabindex' => '-1','role' => 'dialog','aria-labelledby' => 'preg:/#post_\w+-label/','aria-hidden' => 'true')), + array('div' => array('class' => 'modal-dialog')), + array('div' => array('class' => 'modal-content')), + array('div' => array('class' => 'modal-header')), + array('button' => array('type' => 'button','class' => 'close','data-dismiss' => 'modal','aria-hidden' => 'true')), + '×', + '/button', + array('h4' => array('class' => 'modal-title','id' => 'preg:/#post_\w+-label/')), + 'Confirmation Dialog', + '/h4', + '/div', + array('div' => array('class' => 'modal-body')), + '\'Confirm\' this "deletion"?', + '/div', + array('div' => array('class' => 'modal-footer')), + array('button' => array('type' => 'button','class' => 'btn btn-default','data-dismiss' => 'modal')), + 'No', + '/button', + array('a' => array('href' => '#','class' => 'btn btn-primary','onclick' => 'preg:/document\.post_\w+\.submit\(\)\;/')), + 'Yes', + '/a', + '/div', + '/div', + '/div', + '/div' + ); + $this->assertTags($result, $expected); + + $result = $this->Form->postLink('Delete', '/posts/delete', array('data' => array('id' => 1))); + $this->assertContains('', $result); + + $result = $this->Form->postLink('Delete', '/posts/delete/1', array('target' => '_blank')); + $expected = array( + array('form' => array('method' => 'post', 'target' => '_blank', 'action' => '/posts/delete/1','name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;')), + array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), + '/form', + array('a' => array('href' => '#', 'onclick' => 'preg:/document\.post_\w+\.submit\(\)\; event\.returnValue \= false\; return false\;/')), + 'Delete', + '/a', + ); + $this->assertTags($result, $expected); + + $result = $this->Form->postLink( + 'Title', + array('controller' => 'items', 'action' => 'delete', 10), + array('class' => 'btn btn-danger', 'escape' => false), + array('text' => 'Confirm thing', 'title' => 'Thing Title') + ); + $expected = array( + array('form' => array('method' => 'post', 'action' => '/items/delete/10','name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;')), + array('input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'POST')), + '/form', + array('a' => array('href' => '#', 'class' => 'btn btn-danger','onclick' => 'event.returnValue = false; return false;', 'data-toggle' => 'modal', 'data-target' => 'preg:/#post_\w+-modal/')), + 'Title', + '/a', + array('div' => array('class' => 'modal fade text-left','id' => 'preg:/post_\w+\-modal/','tabindex' => '-1','role' => 'dialog','aria-labelledby' => 'preg:/#post_\w+-label/','aria-hidden' => 'true')), + array('div' => array('class' => 'modal-dialog')), + array('div' => array('class' => 'modal-content')), + array('div' => array('class' => 'modal-header')), + array('button' => array('type' => 'button','class' => 'close','data-dismiss' => 'modal','aria-hidden' => 'true')), + '×', + '/button', + array('h4' => array('class' => 'modal-title','id' => 'preg:/#post_\w+-label/')), + 'Thing Title', + '/h4', + '/div', + array('div' => array('class' => 'modal-body')), + 'Confirm thing', + '/div', + array('div' => array('class' => 'modal-footer')), + array('button' => array('type' => 'button','class' => 'btn btn-default','data-dismiss' => 'modal')), + 'No', + '/button', + array('a' => array('href' => '#','class' => 'btn btn-primary','onclick' => 'preg:/document\.post_\w+\.submit\(\)\;/')), + 'Yes', + '/a', + '/div', + '/div', + '/div', + '/div' + ); + $this->assertTags($result, $expected); + } } diff --git a/View/Helper/Bs3FormHelper.php b/View/Helper/Bs3FormHelper.php index 08f171a..482473a 100644 --- a/View/Helper/Bs3FormHelper.php +++ b/View/Helper/Bs3FormHelper.php @@ -924,6 +924,131 @@ protected function _detectFormStyle($options) { return $options; } + +/** +* Creates an HTML link, but access the URL using the method you specify (defaults to POST). +* Requires javascript to be enabled in browser. +* +* This method creates a `
` element. So do not use this method inside an existing form. +* Instead you should add a submit button using FormHelper::submit() +* +* ### Options: +* +* - `data` - Array with key/value to pass in input hidden +* - `method` - Request method to use. Set to 'delete' to simulate HTTP/1.1 DELETE request. Defaults to 'post'. +* - `confirm` - Can be used instead of $confirmMessage. +* - `inline` - Whether or not the associated form tag should be output inline. +* Set to false to have the form tag appended to the 'postLink' view block. +* Defaults to true. +* - `block` - Choose a custom block to append the form tag to. Using this option +* will override the inline option. +* - Other options are the same of HtmlHelper::link() method. +* - The option `onclick` will be replaced. +* +* @param string $title The content to be wrapped by tags. +* @param string|array $url Cake-relative URL or array of URL parameters, or external URL (starts with http://) +* @param array $options Array of HTML attributes. +* @param array $confirmMessage Options for modal dialog (text and title). +* @return string An `` element. +* @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::postLink +*/ + public function postLink($title, $url = null, $options = array(), $confirmMessage = array()) { + $options = (array) $options + array('inline' => true, 'block' => null); + if (!$options['inline'] && empty($options['block'])) { + $options['block'] = __FUNCTION__; + } + unset($options['inline']); + + $requestMethod = 'POST'; + if (!empty($options['method'])) { + $requestMethod = strtoupper($options['method']); + unset($options['method']); + } + + if(is_string($confirmMessage)) { + $confirmMessage = array('text' => $confirmMessage); + } + if (!empty($confirmMessage['confirm'])) { + $confirmMessage['text'] = $confirmMessage['confirm']; + unset($confirmMessage['confirm']); + } + + $formName = str_replace('.', '', uniqid('post_', true)); + $formUrl = $this->url($url); + $formOptions = array( + 'name' => $formName, + 'id' => $formName, + 'style' => 'display:none;', + 'method' => 'post', + ); + if (isset($options['target'])) { + $formOptions['target'] = $options['target']; + unset($options['target']); + } + + $this->_lastAction($url); + + $out = $this->Html->useTag('form', $formUrl, $formOptions); + $out .= $this->Html->useTag('hidden', '_method', array( + 'value' => $requestMethod + )); + $out .= $this->_csrfField(); + + $fields = array(); + if (isset($options['data']) && is_array($options['data'])) { + foreach (Hash::flatten($options['data']) as $key => $value) { + $fields[$key] = $value; + $out .= $this->hidden($key, array('value' => $value, 'id' => false)); + } + unset($options['data']); + } + $out .= $this->secure($fields); + $out .= $this->Html->useTag('formend'); + + if ($options['block']) { + $this->_View->append($options['block'], $out); + $out = ''; + } + unset($options['block']); + + $url = '#'; + $onClick = 'document.' . $formName . '.submit();'; + $append = ''; + $options['onclick'] = ''; + + if (!empty($confirmMessage['text'])) { + if (empty($confirmMessage['title'])) + $confirmMessage['title'] = __('Confirmation Dialog'); + $options['data-toggle'] = 'modal'; + $options['data-target'] = "#$formName-modal"; + $append .= "
"; + $append .= ''; + $append .= '
'; + } else { + $options['onclick'] = $onClick . ' '; + } + $options['onclick'] .= 'event.returnValue = false; return false;'; + + $out .= $this->Html->link($title, $url, $options) . $append; + return $out; + } + /** * Overrides parent method to remove undesirable properties when dealing with bare inputs