Rev 22 | Blame | Compare with Previous | Last modification | View Log | Download
<?php namespace ProcessWire;/*** An Inputfield for handling "textarea" form inputs** ProcessWire 3.x, Copyright 2022 by Ryan Cramer* https://processwire.com** @property int $rows Number of rows for textarea (default=5)* @property int $contentType Content type, applicable when used with FieldtypeTextarea. See FieldtypeTextarea contentType constants (default=contentTypeUnknown)**/class InputfieldTextarea extends InputfieldText {/*** Default value for rows attribute**/const defaultRows = 5;/*** Get module info** @return array**/public static function getModuleInfo() {return array('title' => __('Textarea', __FILE__), // Module Title'summary' => __('Multiple lines of text', __FILE__), // Module Summary'version' => 103,'permanent' => true,);}/*** Init Inputfield**/public function init() {parent::init();$this->setAttribute('rows', self::defaultRows);$this->setAttribute('maxlength', $this->getDefaultMaxlength());$this->set('contentType', FieldtypeTextarea::contentTypeUnknown);}/*** Get the default maxlength attribute value** @return mixed**/public function getDefaultMaxlength() {return $this->hasFieldtype === false ? 1024*32 : 0;}/*** Get all attributes in an associative array** @return array**/public function getAttributes() {$attrs = parent::getAttributes();if(isset($attrs['maxlength'])) {if($attrs['maxlength'] > 0) {// we only allow maxlength attribute for use outside of PW fields// otherwise we only use data-maxlength attribute$attrs['data-maxlength'] = $attrs['maxlength'];if($this->hasFieldtype !== false) unset($attrs['maxlength']);} else {unset($attrs['maxlength']);}}return $attrs;}/*** Return the length of the given value (not including markup)** @param string $value* @param bool $countWords Optionally return a word count rather than character count.* @return int**/protected function getValueLength($value, $countWords = false) {if($this->isContentTypeHTML()) $value = strip_tags($value);$value = $this->wire()->sanitizer->textarea($value, array('stripTags' => false));return parent::getValueLength($value, $countWords);}/*** Render Inputfield** @return string**/public function ___render() {$attrs = $this->getAttributes();$value = $attrs['value'];unset($attrs['value'], $attrs['size'], $attrs['type']);return"<textarea " . $this->getAttributesString($attrs) . ">" .htmlspecialchars($value, ENT_QUOTES, "UTF-8") ."</textarea>";}/*** Prepare the 'value' attribute** @param string $value* @return string* @throws WireException**/protected function setAttributeValue($value) {$maxlength = $this->attr('maxlength');$value = (string) $value;if($maxlength > 0 && $this->hasFieldtype === false) {$value = $this->wire()->sanitizer->textarea($value, array('maxLength' => $maxlength,'maxBytes' => $maxlength*4,'stripTags' => false,'trim' => $this->noTrim ? false : true));} else {if(strpos($value, "\r\n") !== false) {$value = str_replace("\r\n", "\n", $value);}}if($this->stripTags) $value = strip_tags($value);return $this->noTrim ? $value : trim($value);}/*** Process input** @param WireInputData $input* @return self|Inputfield**/public function ___processInput(WireInputData $input) {$maxlength = $this->attr('maxlength');if($this->hasFieldtype !== false && $maxlength > 0) {// we want to apply our own maxlength logic that doesn't truncate$this->attr('maxlength', 0);$result = parent::___processInput($input);$this->attr('maxlength', $maxlength); // restore$value = $this->attr('value');$length = function_exists('mb_strlen') ? mb_strlen($value) : strlen($value);if($length > $maxlength) {$this->error(sprintf($this->_('Value exceeds maximum recommended length of %1$d characters (length=%2$d).'),$maxlength, $length));}} else {$result = parent::___processInput($input);}return $result;}/*** Render just the value (not input) in text/markup for presentation purposes** @return string of text or markup where applicable**/public function ___renderValue() {if($this->isContentTypeHTML()) {$out ="<div class='InputfieldTextareaContentTypeHTML'>" .$this->wire()->sanitizer->purify($this->val()) ."</div>";} else {$out = nl2br(htmlentities($this->val(), ENT_QUOTES, "UTF-8"));}return $out;}/*** Is current content-type an HTML content-type?** @return bool**/public function isContentTypeHTML() {$contentTypes = array(FieldtypeTextarea::contentTypeHTML,FieldtypeTextarea::contentTypeImageHTML);return in_array($this->contentType, $contentTypes);}/*** Configure Inputfield** @return InputfieldWrapper**/public function ___getConfigInputfields() {$inputfields = parent::___getConfigInputfields();$removes = array('size', 'pattern');foreach($removes as $name) {$f = $inputfields->getChildByName($name);if($f) $inputfields->remove($f);}/** @var InputfieldInteger $field */$field = $this->wire()->modules->get('InputfieldInteger');$field->setAttribute('name', 'rows');$field->label = $this->_('Rows');$field->setAttribute('value', $this->attr('rows') > 0 ? $this->attr('rows') : self::defaultRows);$field->setAttribute('size', 3);$field->description = $this->_('The number of rows initially shown for this field.');if($field->attr('value') == self::defaultRows) $field->collapsed = Inputfield::collapsedYes;$inputfields->append($field);return $inputfields;}/*** Get config fields allowed for context** @param Field $field* @return array**/public function ___getConfigAllowContext($field) {return array_merge(parent::___getConfigAllowContext($field), array('rows'));}}