From cc6b2ff8f88d7ef6dc2f07f8e0a4957c82d891b6 Mon Sep 17 00:00:00 2001 From: Chuck Hagenbuch Date: Sun, 22 Feb 2009 21:05:36 -0500 Subject: [PATCH] - add the rest of the Url helper methods - port initial Form helpers - add FormBuilder --- framework/View/lib/Horde/View/Base.php | 5 + framework/View/lib/Horde/View/Helper/Form.php | 123 +++++ .../View/lib/Horde/View/Helper/Form/Builder.php | 88 ++++ .../Horde/View/Helper/Form/InstanceTag/Base.php | 152 ++++++ .../Horde/View/Helper/Form/InstanceTag/Form.php | 148 ++++++ framework/View/lib/Horde/View/Helper/FormTag.php | 179 +++++++ framework/View/lib/Horde/View/Helper/Tag.php | 2 +- framework/View/lib/Horde/View/Helper/Url.php | 265 ++++++++++- .../View/test/Horde/View/Helper/FormTagTest.php | 179 +++++++ framework/View/test/Horde/View/Helper/FormTest.php | 527 +++++++++++++++++++++ framework/View/test/Horde/View/Helper/UrlTest.php | 134 ++++++ 11 files changed, 1784 insertions(+), 18 deletions(-) create mode 100644 framework/View/lib/Horde/View/Helper/Form.php create mode 100644 framework/View/lib/Horde/View/Helper/Form/Builder.php create mode 100644 framework/View/lib/Horde/View/Helper/Form/InstanceTag/Base.php create mode 100644 framework/View/lib/Horde/View/Helper/Form/InstanceTag/Form.php create mode 100644 framework/View/lib/Horde/View/Helper/FormTag.php create mode 100644 framework/View/test/Horde/View/Helper/FormTagTest.php create mode 100644 framework/View/test/Horde/View/Helper/FormTest.php create mode 100644 framework/View/test/Horde/View/Helper/UrlTest.php diff --git a/framework/View/lib/Horde/View/Base.php b/framework/View/lib/Horde/View/Base.php index e08fee3e9..8eff39fc5 100644 --- a/framework/View/lib/Horde/View/Base.php +++ b/framework/View/lib/Horde/View/Base.php @@ -14,6 +14,11 @@ abstract class Horde_View_Base { /** + * @var string + */ + public static $defaultFormBuilder = 'Horde_View_Helper_Form_Builder'; + + /** * Path stack for templates. * * @var array diff --git a/framework/View/lib/Horde/View/Helper/Form.php b/framework/View/lib/Horde/View/Helper/Form.php new file mode 100644 index 000000000..761fa8abf --- /dev/null +++ b/framework/View/lib/Horde/View/Helper/Form.php @@ -0,0 +1,123 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ + +/** + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ +class Horde_View_Helper_Form extends Horde_View_Helper_Base +{ + private $_instanceTag = 'Horde_View_Helper_Form_InstanceTag_Form'; + + public function formFor($objectName) + { + $args = func_get_args(); + $options = (is_array(end($args))) ? array_pop($args) : array(); + + if (isset($options['url'])) { + $urlOptions = $options['url']; + unset($options['url']); + } else { + $urlOptions = array(); + } + + if (isset($options['html'])) { + $htmlOptions = $options['html']; + unset($options['url']); + } else { + $htmlOptions = array(); + } + echo $this->formTag($urlOptions, $htmlOptions); + + $options['end'] = ''; + + array_push($args, $options); + return call_user_func_array(array($this, 'fieldsFor'), $args); + } + + public function fieldsFor($objectName) + { + $args = func_get_args(); + $options = (is_array(end($args))) ? array_pop($args) : array(); + $object = isset($args[1]) ? $args[1] : null; + + $builder = isset($options['builder']) ? $options['builder'] + : Horde_View_Base::$defaultFormBuilder; + + return new $builder($objectName, $object, $this->_view, $options); + } + + public function textField($objectName, $method, $options = array()) + { + $object = isset($options['object']) ? $options['object'] : null; + unset($options['object']); + $tag = new $this->_instanceTag($objectName, $method, $this->_view, $object); + return $tag->toInputFieldTag('text', $options); + } + + public function passwordField($objectName, $method, $options = array()) + { + $object = isset($options['object']) ? $options['object'] : null; + unset($options['object']); + $tag = new $this->_instanceTag($objectName, $method, $this->_view, $object); + return $tag->toInputFieldTag('password', $options); + } + + public function hiddenField($objectName, $method, $options = array()) + { + $object = isset($options['object']) ? $options['object'] : null; + unset($options['object']); + $tag = new $this->_instanceTag($objectName, $method, $this->_view, $object); + return $tag->toInputFieldTag('hidden', $options); + } + + public function fileField($objectName, $method, $options = array()) + { + $object = isset($options['object']) ? $options['object'] : null; + unset($options['object']); + $tag = new $this->_instanceTag($objectName, $method, $this->_view, $object); + return $tag->toInputFieldTag('file', $options); + } + + public function checkBox($objectName, $method, $options = array(), + $checkedValue = '1', $uncheckedValue = '0') + { + $object = isset($options['object']) ? $options['object'] : null; + unset($options['object']); + $tag = new $this->_instanceTag($objectName, $method, $this->_view, $object); + return $tag->toCheckBoxTag($options, $checkedValue, $uncheckedValue); + } + + public function radioButton($objectName, $method, $tagValue, $options = array()) + { + $object = isset($options['object']) ? $options['object'] : null; + unset($options['object']); + $tag = new $this->_instanceTag($objectName, $method, $this->_view, $object); + return $tag->toRadioButtonTag($tagValue, $options); + } + + public function textArea($objectName, $method, $options = array()) + { + $object = isset($options['object']) ? $options['object'] : null; + unset($options['object']); + $tag = new $this->_instanceTag($objectName, $method, $this->_view, $object); + return $tag->toTextAreaTag($options); + } + +} diff --git a/framework/View/lib/Horde/View/Helper/Form/Builder.php b/framework/View/lib/Horde/View/Helper/Form/Builder.php new file mode 100644 index 000000000..9dbe20e4b --- /dev/null +++ b/framework/View/lib/Horde/View/Helper/Form/Builder.php @@ -0,0 +1,88 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ + +/** + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ +class Horde_View_Helper_Form_Builder +{ + private $_objectName; + private $_object; + private $_view; + private $_options; + private $_end; + + public function __construct($objectName, $object, $view, $options) + { + $this->_objectName = $objectName; + $this->_object = $object; + $this->_view = $view; + + $this->_end = isset($options['end']) ? $options['end'] : ''; + unset($options['end']); + $this->_options = $options; + } + + public function __call($method, $args) + { + if (empty($args)) { + throw new InvalidArgumentException('No object property specified'); + } + $objectProperty = $args[0]; + $options = array_merge(isset($args[1]) ? $args[1] : array(), + array('object' => $this->_object)); + + return $this->_view->{$method}($this->_objectName, $objectProperty, $options); + } + + public function fieldsFor($name) { + $name = "{$this->_objectName}[$name]"; + $args = func_get_args(); + $args[0] = $name; + return call_user_func_array(array($this->_view, 'fieldsFor'), $args); + } + + public function checkBox($method, $options = array(), $checkedValue = '1', $uncheckedValue = '0') + { + $options = array_merge($options, array('object' => $this->_object)); + return $this->_view->checkBox($this->_objectName, $method, $options, $checkedValue, $uncheckedValue); + } + + public function radioButton($method, $tagValue, $options = array()) + { + $options = array_merge($options, array('object' => $this->_object)); + return $this->_view->radioButton($this->_objectName, $method, $tagValue, $options); + } + + // @todo error_message_on + // @todo error_messages + + public function submit($value = 'Save changes', $options = array()) + { + $options = array_merge(array('id' => "{$this->_objectName}_submit"), $options); + return $this->_view->submitTag($value, $options); + } + + public function end() + { + echo $this->_end; + } + +} diff --git a/framework/View/lib/Horde/View/Helper/Form/InstanceTag/Base.php b/framework/View/lib/Horde/View/Helper/Form/InstanceTag/Base.php new file mode 100644 index 000000000..33ae0b577 --- /dev/null +++ b/framework/View/lib/Horde/View/Helper/Form/InstanceTag/Base.php @@ -0,0 +1,152 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ + +/** + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ +class Horde_View_Helper_Form_InstanceTag_Base extends Horde_View_Helper_Tag +{ + protected $_defaultFieldOptions = array('size' => 30); + protected $_defaultRadioOptions = array(); + protected $_defaultTextAreaOptions = array('cols' => 40, 'rows' => 20); + protected $_defaultDateOptions = array('discardType' => true); + + protected $objectName; + protected $objectProperty; + protected $object; + protected $autoIndex; + + /** + * @param array $values Values to cycle through + */ + public function __construct($objectName, $objectProperty, $view, $object = null) + { + $this->_view = $view; + $this->objectProperty = $objectProperty; + $this->object = $object; + + if (strpos($objectName, '[]')) { + $objectName = rtrim($objectName, '[]'); + if (! isset($object)) { + $object = $view->{$objectName}; + } + if (isset($object) && isset($object->id_before_type_cast)) { + $this->autoIndex = $object->id_before_type_cast; + } else { + $msg = "object[] naming but object param and @object var don't exist or don't respond to id_before_type_cast"; + throw new InvalidArgumentException($msg); + } + } + + $this->objectName = $objectName; + } + + public function object() + { + if (isset($this->object)) { + return $this->object; + } else { + return $this->_view->{$this->objectName}; + } + } + + public function value($object) + { + if (is_object($object)) { + return $object->{$this->objectProperty}; + } else { + return null; + } + } + + protected function valueBeforeTypeCast($object) + { + if (is_object($object)) { + if (isset($object->{"{$this->objectProperty}_before_type_cast"})) { + return $object->{"{$this->objectProperty}_before_type_cast"}; + } else { + if (isset($object->{$this->objectProperty})) { + return $object->{$this->objectProperty}; + } else { + return null; + } + } + } else { + return null; + } + } + + protected function addDefaultNameAndId($options) + { + if (isset($options['index'])) { + if (! isset($options['name'])) { + $options['name'] = $this->tagNameWithIndex($options['index']); + } + if (! isset($options['id'])) { + $options['id'] = $this->tagIdWithIndex($options['index']); + } + unset($options['index']); + } else if (isset($this->autoIndex)) { + if (! isset($options['name'])) { + $options['name'] = $this->tagNameWithIndex($this->autoIndex); + } + if (! isset($options['id'])) { + $options['id'] = $this->tagIdWithIndex($this->autoIndex); + } + } else { + if (! isset($options['name'])) { + $options['name'] = $this->tagName() + . (isset($options['multiple']) ? '[]' : ''); + } + if (! isset($options['id'])) { + $options['id'] = $this->tagId(); + } + } + return $options; + } + + protected function tagName() + { + return "{$this->objectName}[$this->objectProperty]"; + } + + protected function tagNameWithIndex($index) + { + return "{$this->objectName}[$index][$this->objectProperty]"; + } + + protected function tagId() + { + return $this->sanitizedObjectName() . "_{$this->objectProperty}"; + } + + protected function tagIdWithIndex($index) + { + return $this->sanitizedObjectName() . "_{$index}_{$this->objectProperty}"; + } + + protected function sanitizedObjectName() + { + $name = preg_replace('/[^-a-zA-Z0-9:.]/', '_', $this->objectName); + $name = preg_replace('/_$/', '', $name); + return $name; + } + +} diff --git a/framework/View/lib/Horde/View/Helper/Form/InstanceTag/Form.php b/framework/View/lib/Horde/View/Helper/Form/InstanceTag/Form.php new file mode 100644 index 000000000..2a4f100c9 --- /dev/null +++ b/framework/View/lib/Horde/View/Helper/Form/InstanceTag/Form.php @@ -0,0 +1,148 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ + +/** + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ +class Horde_View_Helper_Form_InstanceTag_Form extends Horde_View_Helper_Form_InstanceTag_Base +{ + public function toInputFieldTag($fieldType, $options = array()) + { + if (! isset($options['size'])) { + $options['size'] = isset($options['maxlength']) ? $options['maxlength'] + : $this->_defaultFieldOptions['size']; + } + $options = array_merge($this->_defaultFieldOptions, $options); + + if ($fieldType == 'hidden') { + unset($options['size']); + } + $options['type'] = $fieldType; + + if ($fieldType != 'file') { + if (! isset($options['value'])) { + $options['value'] = $this->valueBeforeTypeCast($this->object()); + } + } + $options = $this->addDefaultNameAndId($options); + return $this->tag('input', $options); + } + + public function toRadioButtonTag($tagValue, $options = array()) + { + $options = array_merge($this->_defaultRadioOptions, $options); + $options['type'] = 'radio'; + $options['value'] = $tagValue; + if (isset($options['checked'])) { + $cv = $options['checked']; + unset($options['checked']); + $checked = ($cv == true || $cv == 'checked'); + } else { + $checked = $this->isRadioButtonChecked($this->value($this->object()), $tagValue); + } + if ($checked) { + $options['checked'] = 'checked'; + } + + $prettyTagValue = strval($tagValue); + $prettyTagValue = preg_replace('/\s/', '_', $prettyTagValue); + $prettyTagValue = preg_replace('/\W/', '', $prettyTagValue); + $prettyTagValue = strtolower($prettyTagValue); + + if (! isset($options['id'])) { + if (isset($this->autoIndex)) { + $options['id'] = "{$this->objectName}_{$this->autoIndex}_{$this->objectProperty}_$prettyTagValue"; + } else { + $options['id'] = "{$this->objectName}_{$this->objectProperty}_$prettyTagValue"; + } + } + + $options = $this->addDefaultNameAndId($options); + return $this->tag('input', $options); + } + + public function toTextAreaTag($options = array()) + { + $options = array_merge($this->_defaultTextAreaOptions, $options); + $options = $this->addDefaultNameAndId($options); + + if (isset($options['size'])) { + $size = $options['size']; + unset($options['size']); + + list($options['cols'], $options['rows']) = explode('x', $size); + } + + if (isset($options['value'])) { + $value = $options['value']; + unset($options['value']); + } else { + $value = $this->valueBeforeTypeCast($this->object(), $options); + } + + return $this->contentTag('textarea', htmlentities($value, ENT_QUOTES, 'utf-8'), $options); + } + + public function toCheckBoxTag($options = array(), $checkedValue = '1', $uncheckedValue = '0') + { + $options['type'] = 'checkbox'; + $options['value'] = $checkedValue; + if (isset($options['checked'])) { + $cv = $options['checked']; + unset($options['checked']); + $checked = ($cv == true || $cv == 'checked'); + } else { + $checked = $this->isCheckBoxChecked($this->value($this->object()), $checkedValue); + } + if ($checked) { + $options['checked'] = 'checked'; + } + $options = $this->addDefaultNameAndId($options); + + // hidden must output first in PHP to not overwrite checkbox value + $tags = $this->tag('input', array('name' => $options['name'], + 'type' => 'hidden', + 'value' => $uncheckedValue)). + $this->tag('input', $options); + return $tags; + } + + protected function isCheckBoxChecked($value, $checkedValue) + { + switch (gettype($value)) { + case 'boolean': + return $value; + case 'NULL': + return false; + case 'integer': + return $value != 0; + case 'string': + return $value == $checkedValue; + default: + return intval($value) != 0; + } + } + + protected function isRadioButtonChecked($value, $checkedValue) + { + return (strval($value) == strval($checkedValue)); + } + +} diff --git a/framework/View/lib/Horde/View/Helper/FormTag.php b/framework/View/lib/Horde/View/Helper/FormTag.php new file mode 100644 index 000000000..18e2a91ef --- /dev/null +++ b/framework/View/lib/Horde/View/Helper/FormTag.php @@ -0,0 +1,179 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ + +/** + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage Helper + */ +class Horde_View_Helper_FormTag extends Horde_View_Helper_Base +{ + public function formTag($urlForOptions = array(), $options = array()) // , *parameters_for_url + { + $htmlOptions = $this->htmlOptionsForForm($urlForOptions, $options ); // , *parameters_for_url + return $this->formTagHtml($htmlOptions); + } + + public function endFormTag() + { + return ''; + } + + public function selectTag($name, $optionTags = null, $options = array()) + { + return $this->contentTag('select', $optionTags, + array_merge(array('name' => $name, 'id' => $name), $options)); + } + + public function textFieldTag($name, $value = null, $options = array()) + { + return $this->tag('input', array_merge(array('type' => 'text', + 'name' => $name, + 'id' => $name, + 'value' => $value), + $options)); + } + + public function hiddenFieldTag($name, $value = null, $options = array()) + { + return $this->textFieldTag($name, $value, array_merge($options, array('type' => 'hidden'))); + } + + public function fileFieldTag($name, $options = array()) + { + return $this->textFieldTag($name, null, array_merge($options, array('type' => 'file'))); + } + + public function passwordFieldTag($name = 'password', $value = null, $options = array()) + { + return $this->textFieldTag($name, $value, array_merge($options, array('type' => 'password'))); + } + + public function textAreaTag($name, $content = null, $options = array()) + { + if (isset($options['size'])) { + $size = $options['size']; + unset($options['size']); + if (strpos($size, 'x') !== false) { + list($options['cols'], $options['rows']) = explode('x', $size); + } + } + + return $this->contentTag('textarea', $content, + array_merge(array('name' => $name, 'id' => $name), $options)); + } + + public function checkBoxTag($name, $value = '1', $checked = false, $options = array()) + { + $htmlOptions = array_merge(array('type' => 'checkbox', + 'name' => $name, + 'id' => $name, + 'value' => $value), $options); + if ($checked) { + $htmlOptions['checked'] = 'checked'; + } + + return $this->tag('input', $htmlOptions); + } + + public function radioButtonTag($name, $value, $checked = false, $options = array()) + { + $prettyTagValue = preg_replace('/\s/', '_', $value); + $prettyTagValue = strtolower(preg_replace('/(?!-)\W/', '', $prettyTagValue)); + + $htmlOptions = array_merge(array('type' => 'radio', + 'name' => $name, + 'id' => "{$name}_{$prettyTagValue}", + 'value' => $value), $options); + if ($checked) { + $htmlOptions['checked'] = 'checked'; + } + + return $this->tag('input', $htmlOptions); + } + + public function submitTag($value = 'Save changes', $options = array()) + { + if (isset($options['disableWith'])) { + $disableWith = $options['disableWith']; + unset($options['disableWith']); + + $options['onclick'] = implode(';', array( + "this.setAttribute('originalValue', this.value)", + "this.disabled=true", + "this.value='$disableWith'", + "{$options['onclick']}", + "result = (this.form.onsubmit ? (this.form.onsubmit() ? this.form.submit() : false) : this.form.submit())", + "if (result == false) { this.value = this.getAttribute('originalValue'); this.disabled = false }", + "return result" + )); + } + + return $this->tag('input', array_merge(array('type' => 'submit', 'name' => 'commit', 'value' => $value), + $options)); + } + + public function imageSubmitTag($source, $options = array()) + { + // source is passed to Horde_View_Helper_Asset->imagePath + return $this->tag('input', array_merge(array('type' => 'image', + 'src' => $this->imagePath($source)), + $options)); + } + + private function extraTagsForForm($htmlOptions) + { + $method = isset($htmlOptions['method']) ? strtolower($htmlOptions['method']) : ''; + if ($method == 'get') { + $htmlOptions['method'] = 'get'; + return array('', $htmlOptions); + } else if ($method == 'post' || $method == '') { + $htmlOptions['method'] = 'post'; + return array('', $htmlOptions); + } else { + $htmlOptions['method'] = 'post'; + $extraTags = $this->contentTag('div', + $this->tag('input', array('type' => 'hidden', 'name' => '_method', + 'value' => $method)), array('style' => 'margin:0;padding:0')); + return array($extraTags, $htmlOptions); + } + + } + + private function formTagHtml($htmlOptions) + { + list($extraTags, $htmlOptions) = $this->extraTagsForForm($htmlOptions); + return $this->tag('form', $htmlOptions, true) . $extraTags; + } + + /** @todo url_for */ + private function htmlOptionsForForm($urlForOptions, $options) + { + if (isset($options['multipart'])) { + unset($options['multipart']); + $options['enctype'] = 'multipart/form-data'; + } + + $options['action'] = $this->urlFor($urlForOptions); // , *parameters_for_url + // @todo : + // html_options["action"] = url_for(url_for_options, *parameters_for_url) + + return $options; + } + +} diff --git a/framework/View/lib/Horde/View/Helper/Tag.php b/framework/View/lib/Horde/View/Helper/Tag.php index 289203df8..837bdc4e8 100644 --- a/framework/View/lib/Horde/View/Helper/Tag.php +++ b/framework/View/lib/Horde/View/Helper/Tag.php @@ -112,7 +112,7 @@ class Horde_View_Helper_Tag extends Horde_View_Helper_Base */ public function escapeOnce($html) { - return $this->_fixDoubleEscape(htmlspecialchars($html)); + return $this->_fixDoubleEscape($this->_view->escape($html)); } /** diff --git a/framework/View/lib/Horde/View/Helper/Url.php b/framework/View/lib/Horde/View/Helper/Url.php index 2fe14808d..a0af25ed5 100644 --- a/framework/View/lib/Horde/View/Helper/Url.php +++ b/framework/View/lib/Horde/View/Helper/Url.php @@ -23,16 +23,78 @@ * @package Horde_View * @subpackage Helper */ -class Horde_View_Helper_Url extends Horde_View_Helper +class Horde_View_Helper_Url extends Horde_View_Helper_Base { /** - * Creates a link tag of the given +name+ using a URL created by the set - * of +options+. See the valid options in the documentation for - * url_for. It's also possible to pass a string instead - * of an options hash to get a link tag that uses the value of the string as the - * href for the link, or use +:back+ to link to the referrer - a JavaScript back - * link will be used in place of a referrer if none exists. If nil is passed as - * a name, the link itself will become the name. + * Returns the URL for the set of +options+ provided. This takes the + * same options as url_for in ActionController (see the + * documentation for ActionController::Base#url_for). Note that by default + * :only_path is true so you'll get the relative /controller/action + * instead of the fully qualified URL like http://example.com/controller/action. + * + * When called from a view, url_for returns an HTML escaped url. If you + * need an unescaped url, pass :escape => false in the +options+. + * + * ==== Options + * * :anchor -- specifies the anchor name to be appended to the path. + * * :only_path -- if true, returns the relative URL (omitting the protocol, host name, and port) (true by default unless :host is specified) + * * :trailing_slash -- if true, adds a trailing slash, as in "/archive/2005/". Note that this + * is currently not recommended since it breaks caching. + * * :host -- overrides the default (current) host if provided + * * :protocol -- overrides the default (current) protocol if provided + * * :user -- Inline HTTP authentication (only plucked out if :password is also present) + * * :password -- Inline HTTP authentication (only plucked out if :user is also present) + * * :escape -- Determines whether the returned URL will be HTML escaped or not (true by default) + * + * ==== Relying on named routes + * + * If you instead of a hash pass a record (like an Active Record or Active Resource) as the options parameter, + * you'll trigger the named route for that record. The lookup will happen on the name of the class. So passing + * a Workshop object will attempt to use the workshop_path route. If you have a nested route, such as + * admin_workshop_path you'll have to call that explicitly (it's impossible for url_for to guess that route). + * + * ==== Examples + * <%= url_for(:action => 'index') %> + * # => /blog/ + * + * <%= url_for(:action => 'find', :controller => 'books') %> + * # => /books/find + * + * <%= url_for(:action => 'login', :controller => 'members', :only_path => false, :protocol => 'https') %> + * # => https://www.railsapplication.com/members/login/ + * + * <%= url_for(:action => 'play', :anchor => 'player') %> + * # => /messages/play/#player + * + * <%= url_for(:action => 'checkout', :anchor => 'tax&ship') %> + * # => /testing/jump/#tax&ship + * + * <%= url_for(:action => 'checkout', :anchor => 'tax&ship', :escape => false) %> + * # => /testing/jump/#tax&ship + * + * <%= url_for(Workshop.new) %> + * # relies on Workshop answering a new_record? call (and in this case returning true) + * # => /workshops + * + * <%= url_for(@workshop) %> + * # calls @workshop.to_s + * # => /workshops/5 + * + * @return string + */ + public function urlFor($first = array(), $second = array()) + { + return is_string($first) ? $first : $this->controller->getUrlWriter()->urlFor($first, $second); + } + + /** + * Creates a link tag of the given +name+ using a URL created by the set of + * +options+. See the valid options in the documentation for url_for. It's + * also possible to pass a string instead of an options hash to get a link + * tag that uses the value of the string as the href for the link, or use + * +:back+ to link to the referrer - a JavaScript back link will be used in + * place of a referrer if none exists. If nil is passed as a name, the link + * itself will become the name. * * ==== Options * * :confirm => 'question?' -- This will add a JavaScript confirm @@ -56,14 +118,35 @@ class Horde_View_Helper_Url extends Horde_View_Helper * Note that if the user has JavaScript disabled, the request will fall back * to using GET. If :href=>'#' is used and the user has JavaScript disabled * clicking the link will have no effect. If you are relying on the POST - * behavior, your should check for it in your controller's action by using the - * request object's methods for post?, delete? or put?. + * behavior, your should check for it in your controller's action by using + * the request object's methods for post?, delete? or put?. + * + * You can mix and match the +html_options+ with the exception of :popup and + * :method which will raise an ActionView::ActionViewError exception. + * + * ==== Examples + * link_to "Visit Other Site", "http://www.rubyonrails.org/", :confirm => "Are you sure?" + * # => Visit Other Site + * + * link_to "Help", { :action => "help" }, :popup => true + * # => Help + * + * link_to "View Image", { :action => "view" }, :popup => ['new_window_name', 'height=300,width=600'] + * # => View Image + * + * link_to "Delete Image", { :action => "delete", :id => @image.id }, :confirm => "Are you sure?", :method => :delete + * # => Delete Image */ - public function linkTo($name, $url, $htmlOptions = array()) + public function linkTo($name, $options = array(), $htmlOptions = array()) { + $url = $this->urlFor($options); + if ($htmlOptions) { $href = isset($htmlOptions['href']) ? $htmlOptions['href'] : null; - // @todo convert_otpions_to_javascript!(html_options, url) + // @todo convert_options_to_javascript!(html_options, url) $tagOptions = $this->tagOptions($htmlOptions); } else { $tagOptions = null; @@ -71,7 +154,7 @@ class Horde_View_Helper_Url extends Horde_View_Helper $hrefAttr = isset($href) ? null : 'href="' . $url . '"'; $nameOrUrl = isset($name) ? $name : $url; - return '' . $this->escape($nameOrUrl) . ''; + return '' . $nameOrUrl . ''; } /** @@ -175,13 +258,161 @@ class Horde_View_Helper_Url extends Horde_View_Helper } /** - * True if the current request URI is the same as the current URL. + * Creates a mailto link tag to the specified +email_address+, which is + * also used as the name of the link unless +name+ is specified. Additional + * HTML attributes for the link can be passed in +html_options+. + * + * mail_to has several methods for hindering email harvestors and customizing + * the email itself by passing special keys to +html_options+. + * + * ==== Options + * * encode - This key will accept the strings "javascript" or "hex". + * Passing "javascript" will dynamically create and encode the mailto: link then + * eval it into the DOM of the page. This method will not show the link on + * the page if the user has JavaScript disabled. Passing "hex" will hex + * encode the +email_address+ before outputting the mailto: link. + * * replace_at - When the link +name+ isn't provided, the + * +email_address+ is used for the link label. You can use this option to + * obfuscate the +email_address+ by substituting the @ sign with the string + * given as the value. + * * replace_dot - When the link +name+ isn't provided, the + * +email_address+ is used for the link label. You can use this option to + * obfuscate the +email_address+ by substituting the . in the email with the + * string given as the value. + * * subject - Preset the subject line of the email. + * * body - Preset the body of the email. + * * cc - Carbon Copy addition recipients on the email. + * * bcc - Blind Carbon Copy additional recipients on the email. + * + * ==== Examples + * mailTo("me@domain.com") + * # => me@domain.com * - * @TODO Get REQUEST_URI from somewhere other than the global environment. + * mailTo("me@domain.com", "My email", array('encode' => "javascript")) + * # => + * + * mailTo("me@domain.com", "My email", array('encode' => "hex")) + * # => My email + * + * mailTo("me@domain.com", null, array('replaceAt' => "_at_", 'replaceDot' => "_dot_", 'class' => "email")) + * # => + * + * mailTo("me@domain.com", "My email", array('cc' => "ccaddress@domain.com", + * 'subject' => "This is an example email")) + * # => My email + */ + public function mailTo($emailAddress, $name = null, $htmlOptions = array()) + { + // extra options "cc", "bcc", "subject", "body" + $extras = ''; + $extraParts = array('cc', 'bcc', 'body', 'subject'); + foreach ($extraParts as $partName) { + if (isset($htmlOptions[$partName])) { + $partValue = str_replace('+', '%20', urlencode($htmlOptions[$partName])); + $extras .= "{$partName}={$partValue}&"; + } + unset($htmlOptions[$partName]); + } + if (! empty($extras)) { + $extras = '?' . rtrim($extras, '&'); + } + + // obfuscation options "replaceAt" and "replaceDot" + $emailAddressObfuscated = $emailAddress; + foreach (array('replaceAt' => '@', 'replaceDot' => '.') as $option => $find) { + if (isset($htmlOptions[$option])) { + $emailAddressObfuscated = str_replace($find, + $htmlOptions[$option], + $emailAddressObfuscated); + } + unset($htmlOptions[$option]); + } + + $string = ''; + + $encode = isset($htmlOptions['encode']) ? $htmlOptions['encode'] : null; + unset($htmlOptions['encode']); + + if ($encode == 'javascript') { + $name = isset($name) ? $name : $emailAddress; + $htmlOptions = array_merge($htmlOptions, + array('href' => "mailto:{$emailAddress}{$extras}")); + $tag = $this->contentTag('a', $name, $htmlOptions); + + foreach (str_split("document.write('$tag');") as $c) { + $string .= sprintf("%%%x", ord($c)); + } + + return ""; + } elseif ($encode == 'hex') { + $emailAddressEncoded = ''; + foreach (str_split($emailAddressObfuscated) as $c) { + $emailAddressEncoded .= sprintf("&#%d;", ord($c)); + } + + foreach (str_split('mailto:') as $c) { + $string .= sprintf("&#%d;", ord($c)); + } + + foreach (str_split($emailAddress) as $c) { + if (preg_match('/\w/', $c)) { + $string .= sprintf("%%%x", ord($c)); + } else { + $string .= $c; + } + } + $name = isset($name) ? $name : $emailAddressEncoded; + $htmlOptions = array_merge($htmlOptions, + array('href' => $string . $extras)); + return $this->contentTag('a', $name, $htmlOptions); + + } else { + $name = isset($name) ? $name : $emailAddressObfuscated; + $htmlOptions = array_merge($htmlOptions, + array('href' => "mailto:{$emailAddress}{$extras}")); + return $this->contentTag('a', $name, $htmlOptions); + } + } + + /** + * True if the current request URI was generated by the given +options+. + * + * ==== Examples + * Let's say we're in the /shop/checkout action. + * + * current_page?(:action => 'process') + * # => false + * + * current_page?(:controller => 'shop', :action => 'checkout') + * # => true + * + * current_page?(:action => 'checkout') + * # => true + * + * current_page?(:controller => 'library', :action => 'checkout') + * # => false + * + * @todo finish implementation */ - public function isCurrentPage($url) + public function isCurrentPage($options) { - return $url == $_SERVER['REQUEST_URI']; + $urlString = htmlentities($this->urlFor($options)); + if (preg_match('/^\w+:\/\//', $urlString)) { + // @todo implement + // url_string == "#{request.protocol}#{request.host_with_port}#{request.request_uri}" + throw new Horde_View_Exception('not implemented'); + } else { + if ($this->controller) { + // @todo prepending "/" is a hack, need to fix request object + $request = $this->controller->getRequest(); + $requestUri = '/' . ltrim($request->getUri(), '/'); + } else { + // @todo accessing $_REQUEST directly is a hack + $requestUri = $_SERVER['REQUEST_URI']; + } + + return $urlString == $requestUri; + } } } diff --git a/framework/View/test/Horde/View/Helper/FormTagTest.php b/framework/View/test/Horde/View/Helper/FormTagTest.php new file mode 100644 index 000000000..3398abd1b --- /dev/null +++ b/framework/View/test/Horde/View/Helper/FormTagTest.php @@ -0,0 +1,179 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage UnitTests + */ + +/** + * @group view + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage UnitTests + */ +class Horde_View_Helper_FormTagTest extends Horde_Test_Functional +{ + public function setUp() + { + $this->view = new Horde_View(); + $this->view->addHelper('FormTag'); + $this->view->addHelper('Tag'); + $this->view->addHelper(new Horde_View_Helper_FormTagTest_MockUrlHelper($this->view)); + } + + public function testFormTag() + { + $actual = $this->view->formTag(); + $expected = '
'; + $this->assertEquals($expected, $actual); + } + + public function testFormTagWithExplicitUrl() + { + $actual = $this->view->formTag('/controller/action'); + $expected = ''; + $this->assertEquals($expected, $actual); + } + + public function testFormTagMultipart() + { + $actual = $this->view->formTag(array(), array('multipart' => true)); + $expected = ''; + $this->assertEquals($expected, $actual); + } + + public function testFormTagWithMethod() + { + $actual = $this->view->formTag(array(), array('method' => 'put')); + $expected = '
'; + $this->assertEquals($expected, $actual); + } + + public function testCheckBoxTag() + { + $actual = $this->view->checkBoxTag('admin'); + $expected = ''; + $this->assertDomEquals($expected, $actual); + } + + public function testHiddenFieldTag() + { + $actual = $this->view->hiddenFieldTag('id', 3); + $expected = ''; + $this->assertDomEquals($expected, $actual); + } + + public function testFileFieldTag() + { + $actual = $this->view->fileFieldTag('id'); + $expected = ''; + $this->assertDomEquals($expected, $actual); + } + + public function testPasswordFieldTag() + { + $actual = $this->view->passwordFieldTag(); + $expected = ''; + $this->assertDomEquals($expected, $actual); + } + + public function testRadioButtonTag() + { + $actual = $this->view->radioButtonTag('people', 'david'); + $expected = ''; + $this->assertDomEquals($expected, $actual); + + $actual = $this->view->radioButtonTag('num_people', 5); + $expected = ''; + $this->assertDomEquals($expected, $actual); + + $actual = $this->view->radioButtonTag('gender', 'm') + . $this->view->radioButtonTag('gender', 'f'); + $expected = '' + . ''; + $this->assertEquals($expected, $actual); // @todo assertDomEquals + + $actual = $this->view->radioButtonTag('opinion', '-1') + . $this->view->radioButtonTag('opinion', '1'); + $expected = '' + . ''; + $this->assertEquals($expected, $actual); // @todo assertDomEquals + } + + public function testSelectTag() + { + $actual = $this->view->selectTag('people', ''); + $expected = ''; + $this->assertDomEquals($expected, $actual); + } + + public function testTextAreaTagSizeString() + { + $actual = $this->view->textAreaTag('body', 'hello world', array('size' => '20x40')); + $expected = ''; + $this->assertDomEquals($expected, $actual); + } + + public function testTextAreaTagShouldDisregardSizeIfGivenAsAnInteger() + { + $actual = $this->view->textAreaTag('body', 'hello world', array('size' => 20)); + $expected = ''; + $this->assertDomEquals($expected, $actual); + } + + public function testTextFieldTag() + { + $actual = $this->view->textFieldTag('title', 'Hello!'); + $expected = ''; + $this->assertDomEquals($expected, $actual); + } + + public function testTextFieldTagClassString() + { + $actual = $this->view->textFieldTag('title', 'Hello!', array('class' => 'admin')); + $expected = ''; + $this->assertDomEquals($expected, $actual); + } + + public function testBooleanOptions() + { + $this->assertDomEquals('', + $this->view->checkBoxTag("admin", 1, true, array('disabled' => true, 'readonly' => "yes"))); + + $this->assertDomEquals('', + $this->view->checkBoxTag('admin', 1, true, array('disabled' => false, 'readonly' => null))); + + $this->assertDomEquals('', + $this->view->selectTag('people', '', array('multiple' => true))); + + $this->assertDomEquals('', + $this->view->selectTag('people', '', array('multiple' => null))); + } + + public function testSubmitTag() + { + $expected = ''; + $actual = $this->view->submitTag('Save', array('disableWith' => 'Saving...', 'onclick' => "alert('hello!')")); + $this->assertDomEquals($expected, $actual); + } + +} + +class Horde_View_Helper_FormTagTest_MockUrlHelper extends Horde_View_Helper_Url +{ + public function urlFor($first = array(), $second = array()) + { + return $first ? parent::urlFor($first, $second) : 'http://www.example.com'; + } +} diff --git a/framework/View/test/Horde/View/Helper/FormTest.php b/framework/View/test/Horde/View/Helper/FormTest.php new file mode 100644 index 000000000..a64be7bff --- /dev/null +++ b/framework/View/test/Horde/View/Helper/FormTest.php @@ -0,0 +1,527 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage UnitTests + */ + +/** + * @group view + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage UnitTests + */ +class Horde_View_Helper_FormTest extends Horde_Test_Case +{ + public function setUp() + { + $this->view = new Horde_View(); + $this->view->addHelper(new Horde_View_Helper_Form($this->view)); + $this->view->addHelper(new Horde_View_Helper_FormTag($this->view)); + $this->view->addHelper(new Horde_View_Helper_Tag($this->view)); + $this->view->addHelper(new Horde_View_Helper_FormTest_MockUrlHelper($this->view)); + + $this->post = (object)array('title', 'authorName', 'body', + 'secret', 'writtenOn', 'cost'); + $this->post->title = 'Hello World'; + $this->post->authorName = ''; + $this->post->body = 'Back to the hill and over it again!'; + $this->post->secret = 1; + $this->post->writtenOn = mktime(2004, 6, 15); + $this->post->id = 123; + $this->post->id_before_type_cast = 123; + + $this->view->post = $this->post; + } + + public function testTextField() + { + $this->assertEquals( + '', + $this->view->textField('post', 'title')); + + $this->assertEquals( + '', + $this->view->passwordField('post', 'title')); + + $this->assertEquals( + '', + $this->view->passwordField("person", "name")); + } + + public function testTextFieldWithEscapes() + { + $this->post->title = 'Hello World'; + $this->assertEquals( + '', + $this->view->textField('post', 'title')); + } + + public function testTextFieldWithOptions() + { + $expected = ''; + $this->assertEquals($expected, $this->view->textField('post', 'title', array('size' => 35))); + } + + public function testTextFieldAssumingSize() + { + $expected = ''; + $this->assertEquals($expected, $this->view->textField('post', 'title', array('maxlength' => 35))); + } + + public function testTextFieldDoesntChangeParamValues() + { + $objectName = 'post[]'; + $expected = ''; + $this->assertEquals($expected, $this->view->textField($objectName, 'title')); + $this->assertEquals($objectName, 'post[]'); + } + + public function testCheckBox() + { + $this->assertEquals( + '', + $this->view->checkBox('post', 'secret')); + + $this->post->secret = 0; + + $this->assertEquals( + '', + $this->view->checkBox('post', 'secret')); + + $this->assertEquals( + '', + $this->view->checkBox('post', 'secret', array('checked' => 'checked'))); + + $this->post->secret = true; + + $this->assertEquals( + '', + $this->view->checkBox('post', 'secret')); + } + + public function testCheckBoxWithExplicitCheckedAndUncheckedValues() + { + $this->post->secret = 'on'; + + $this->assertEquals( + '', + $this->view->checkBox('post', 'secret', array(), 'on', 'off')); + } + + public function testRadioButton() + { + $this->assertEquals( + '', + $this->view->radioButton('post', 'title', 'Hello World')); + + $this->assertEquals( + '', + $this->view->radioButton('post', 'title', 'Goodbye World')); + } + + public function testRadioButtonIsCheckedWithIntegers() + { + $this->assertEquals( + '', + $this->view->radioButton('post', 'secret', '1')); + } + + public function testRadioButtonRespectsPassedInId() + { + $this->assertEquals( + '', + $this->view->radioButton('post', 'secret', '1', array('id' => 'foo'))); + } + + public function testTextArea() + { + $this->assertEquals( + '', + $this->view->textArea('post', 'body')); + } + + public function testTextAreaWithEscapes() + { + $this->post->body = "Back to the hill and over it again!"; + $this->assertEquals( + '', + $this->view->textArea('post', 'body')); + } + + public function testTextAreaWithAlternateValue() + { + $this->assertEquals( + '', + $this->view->textArea('post', 'body', array('value' => 'Testing alternate values.'))); + } + + public function testTextAreaWithSizeOption() + { + $this->assertEquals( + '', + $this->view->textArea('post', 'body', array('size' => '183x820'))); + } + + public function testExplicitName() + { + $this->assertEquals( + '', + $this->view->textField("post", "title", array("name" => "dont guess"))); + + $this->assertEquals( + '', + $this->view->textArea("post", "body", array("name" => "really!"))); + + $this->assertEquals( + '', + $this->view->checkBox("post", "secret", array("name" => "i mean it"))); + } + + public function testExplicitId() + { + $this->assertEquals( + '', + $this->view->textField("post", "title", array("id" => "dont guess"))); + + $this->assertEquals( + '', + $this->view->textArea("post", "body", array("id" => "really!"))); + + $this->assertEquals( + '', + $this->view->checkBox("post", "secret", array("id" => "i mean it"))); + } + + public function testAutoIndex() + { + $pid = $this->post->id; + + $this->assertEquals( + "", + $this->view->textField("post[]", "title")); + + $this->assertEquals( + "", + $this->view->textArea("post[]", "body")); + + $this->assertEquals( + "", + $this->view->checkBox('post[]', 'secret')); + + $this->assertEquals( + "", + $this->view->radioButton('post[]', 'title', 'Hello World')); + + $this->assertEquals( + "", + $this->view->radioButton('post[]', 'title', 'Goodbye World')); + } + + public function testFormFor() + { + ob_start(); + $form = $this->view->formFor('post', $this->post, array('html' => array('id' => 'create-post'))); + echo $form->textField('title'); + echo $form->textArea('body'); + echo $form->checkBox('secret'); + echo $form->submit('Create post'); + $form->end(); + + $expected = + '' . + '' . + '' . + '' . + '' . + '' . + ""; + + $this->assertEquals($expected, ob_get_clean()); + } + + public function testFormForWithMethod() + { + ob_start(); + $form = $this->view->formFor('post', $this->post, array('html' => array('id' => 'create-post', + 'method' => 'put'))); + echo $form->textField('title'); + echo $form->textArea('body'); + echo $form->checkBox('secret'); + $form->end(); + + $expected = + '
' . + '
' . + '' . + '' . + '' . + '' . + "
"; + + $this->assertEquals($expected, ob_get_clean()); + } + + public function testFormForWithoutObject() + { + ob_start(); + $form = $this->view->formFor('post', array('html' => array('id' => 'create-post'))); + echo $form->textField('title'); + echo $form->textArea('body'); + echo $form->checkBox('secret'); + $form->end(); + + $expected = + '
' . + '' . + '' . + '' . + '' . + "
"; + + $this->assertEquals($expected, ob_get_clean()); + } + + public function testFormForWithIndex() + { + ob_start(); + $form = $this->view->formFor('post[]', $this->post); + echo $form->textField('title'); + echo $form->textArea('body'); + echo $form->checkBox('secret'); + $form->end(); + + $expected = + '
' . + '' . + '' . + '' . + '' . + '
'; + + $this->assertEquals($expected, ob_get_clean()); + } + + public function testFieldsFor() + { + ob_start(); + $fields = $this->view->fieldsFor('post', $this->post); + echo $fields->textField('title'); + echo $fields->textArea('body'); + echo $fields->checkBox('secret'); + $fields->end(); + + $expected = + '' . + '' . + '' . + ''; + + $this->assertEquals($expected, ob_get_clean()); + } + + public function testNestedFieldsFor() + { + ob_start(); + $form = $this->view->formFor('post', $this->post); + $fields = $form->fieldsFor('comment', $this->post); + echo $fields->textField('title'); + $fields->end(); + $form->end(); + + $expected = + '
' . + '' . + '
'; + + $this->assertEquals($expected, ob_get_clean()); + } + + public function testFieldsForWithoutObject() + { + ob_start(); + $fields = $this->view->fieldsFor('post'); + echo $fields->textField('title'); + echo $fields->textArea('body'); + echo $fields->checkBox('secret'); + $fields->end(); + + $expected = + '' . + '' . + '' . + ''; + + $this->assertEquals($expected, ob_get_clean()); + } + + public function testFieldsForobjectWithBracketedName() + { + ob_start(); + $fields = $this->view->fieldsFor('author[post]', $this->post); + echo $fields->textField('title'); + $fields->end(); + + $this->assertEquals( + '', + ob_get_clean()); + } + + public function testFormbuilderDoesNotHaveFormForMethod() + { + $methods = get_class_methods('Horde_View_Helper_Form_Builder'); + $this->assertTrue(empty($methods['formFor'])); + } + + public function testFormForAndFieldsFor() + { + ob_start(); + $postForm = $this->view->formFor('post', $this->post, array('html' => array('id' => 'create-post'))); + echo $postForm->textField('title'); + echo $postForm->textArea('body'); + + $parentFields = $this->view->fieldsFor('parent_post', $this->post); + echo $parentFields->checkBox('secret'); + $parentFields->end(); + $postForm->end(); + + $expected = + '
' . + '' . + '' . + '' . + '' . + '
'; + + $this->assertEquals($expected, ob_get_clean()); + } + + public function testFormForWithCustomBuilder() + { + ob_start(); + $form = $this->view->formFor('post', $this->post, array('builder' => 'Horde_View_Helper_FormTest_BuilderMock')); + echo $form->textField('bar'); + echo $form->foo(); + $form->end(); + + $expected = + '
' . + '' . + ''; + + $this->assertEquals($expected, ob_get_clean()); + } + + public function testDefaultFormBuilder() + { + $oldDefaultFormBuilder = Horde_View_Base::$defaultFormBuilder; + Horde_View_Base::$defaultFormBuilder = 'Horde_View_Helper_FormTest_BuilderMock'; + + try { + ob_start(); + $form = $this->view->formFor('post', $this->post); + echo $form->textField('bar'); + echo $form->foo(); + $form->end(); + + $expected = + '
' . + '' . + ''; + + $this->assertEquals($expected, ob_get_clean()); + } catch (Exception $e) {} + + Horde_View_Base::$defaultFormBuilder = $oldDefaultFormBuilder; + } + + // @todo test_default_form_builder_with_active_record_helpers + // @todo test_remote_form_for_with_labelled_builder + + public function testFieldsForWithCustomBuilder() + { + ob_start(); + $fields = $this->view->fieldsFor('post', $this->post, array('builder' => 'Horde_View_Helper_FormTest_BuilderMock')); + echo $fields->textField('bar'); + echo $fields->foo(); + $fields->end(); + + $this->assertEquals( + '', + ob_get_clean()); + } + + public function testFormForWithHtmlOptionsAddsOptionsToFormTag() + { + ob_start(); + $form = $this->view->formFor('post', $this->post, array('html' => array('id' => 'some_form', + 'class' => 'some_class'))); + $form->end(); + + $this->assertEquals( + '
', + ob_get_clean()); + } + + + public function testFormForWithHiddenFieldMadOnly() + { + ob_start(); + $form = $this->view->formFor('post', $this->post); + echo $form->hiddenField('title'); + $form->end(); + + $expected = + '
' . + '' . + '
'; + + $this->assertEquals($expected, ob_get_clean()); + } + + public function testFormForWithFileFieldMadOnly() + { + ob_start(); + $form = $this->view->formFor('post', $this->post); + echo $form->fileField('title'); + $form->end(); + + $expected = + '
' . + '' . + '
'; + + $this->assertEquals($expected, ob_get_clean()); + } + + // @todo test_form_for_with_string_url_option + // @todo test_form_for_with_hash_url_option + // @todo test_remote_form_for_with_html_options_adds_options_to_form_tag +} + +class Horde_View_Helper_FormTest_MockUrlHelper extends Horde_View_Helper_Base +{ + public function urlFor($options) + { + return 'http://www.example.com'; + } +} + +class Horde_View_Helper_FormTest_BuilderMock extends Horde_View_Helper_Form_Builder +{ + public function foo() + { + return ''; + } +} diff --git a/framework/View/test/Horde/View/Helper/UrlTest.php b/framework/View/test/Horde/View/Helper/UrlTest.php new file mode 100644 index 000000000..b1d948972 --- /dev/null +++ b/framework/View/test/Horde/View/Helper/UrlTest.php @@ -0,0 +1,134 @@ + + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage UnitTests + */ + +/** + * @group view + * @author Mike Naberezny + * @author Derek DeVries + * @author Chuck Hagenbuch + * @license http://opensource.org/licenses/bsd-license.php + * @category Horde + * @package Horde_View + * @subpackage UnitTests + */ +class Horde_View_Helper_UrlTest extends Horde_Test_Case +{ + public function setUp() + { + $controller = new Horde_View_Helper_UrlTest_MockController(); + $this->view = new Horde_View(); + $this->view->controller = $controller; + $this->view->addHelper('Url'); + $this->view->addHelper('Tag'); + } + + public function testLinkTagWithStraightUrl() + { + $this->assertEquals('Hello', + $this->view->linkTo('Hello', 'http://www.example.com')); + } + + public function testLinkTagWithQuery() + { + $this->assertEquals('Hello', + $this->view->linkTo('Hello', 'http://www.example.com?q1=v1&q2=v2')); + } + + public function testLinkTagWithQueryAndNoName() + { + $this->assertEquals("http://www.example.com?q1=v1&q2=v2", + $this->view->linkTo(null, 'http://www.example.com?q1=v1&q2=v2')); + } + + public function testLinkTagWithImg() + { + $this->assertEquals("", + $this->view->linkTo("", "http://www.example.com")); + } + + public function testLinkToUnless() + { + $this->assertEquals('Showing', + $this->view->linkToUnless(true, 'Showing', array('action' => 'show', 'controller' => 'weblog'))); + $this->assertEquals("Listing", // @todo http://www.example.com + $this->view->linkToUnless(false, 'Listing', array('action' => 'list', 'controller' => 'weblog'))); + $this->assertEquals('Showing', + $this->view->linkToUnless(true, 'Showing', array('action' => 'show', 'controller' => 'weblog', 'id' => 1))); + } + + public function testLinkToIf() + { + $this->assertEquals('Showing', + $this->view->linkToIf(false, 'Showing', array('action' => 'show', 'controller' => 'weblog'))); + $this->assertEquals("Listing", // @todo http://www.example.com + $this->view->linkToIf(true, 'Listing', array('action' => 'list', 'controller' => 'weblog'))); + $this->assertEquals('Showing', + $this->view->linkToIf(false, 'Showing', array('action' => 'show', 'controller' => 'weblog', 'id' => 1))); + } + + public function testMailTo() + { + $this->assertEquals("david@loudthinking.com", + $this->view->mailTo("david@loudthinking.com")); + $this->assertEquals("David Heinemeier Hansson", + $this->view->mailTo("david@loudthinking.com", "David Heinemeier Hansson")); + $this->assertEquals("David Heinemeier Hansson", + $this->view->mailTo("david@loudthinking.com", "David Heinemeier Hansson", array("class" => "admin"))); + } + + + public function testMailToWithJavascript() + { + $this->assertEquals("", + $this->view->mailTo("me@domain.com", "My email", array('encode' => 'javascript'))); + } + + public function testMailWithOptions() + { + $this->assertEquals('My email', + $this->view->mailTo("me@example.com", "My email", array('cc' => "ccaddress@example.com", 'bcc' => "bccaddress@example.com", 'subject' => "This is an example email", 'body' => "This is the body of the message."))); + } + + public function testMailToWithImg() + { + $this->assertEquals('', + $this->view->mailTo('feedback@example.com', '')); + } + + public function testMailToWithHex() + { + $this->assertEquals("My email", + $this->view->mailTo("me@domain.com", "My email", array('encode' => "hex"))); + $this->assertEquals("me@domain.com", + $this->view->mailTo("me@domain.com", null, array('encode' => "hex"))); + } + + public function testMailToWithReplaceOptions() + { + $this->assertEquals("wolfgang(at)stufenlos(dot)net", + $this->view->mailTo("wolfgang@stufenlos.net", null, array('replaceAt' => "(at)", 'replaceDot' => "(dot)"))); + $this->assertEquals("me(at)domain.com", + $this->view->mailTo("me@domain.com", null, array('encode' => "hex", 'replaceAt' => "(at)"))); + $this->assertEquals("My email", + $this->view->mailTo("me@domain.com", "My email", array('encode' => "hex", 'replaceAt' => "(at)"))); + $this->assertEquals("me(at)domain(dot)com", + $this->view->mailTo("me@domain.com", null, array('encode' => "hex", 'replaceAt' => "(at)", 'replaceDot' => "(dot)"))); + } + +} + +class Horde_View_Helper_UrlTest_MockController extends Horde_Controller_Base +{ + public function getControllerName() { return 'mock'; } +} -- 2.11.0