248 lines
6 KiB
Text
248 lines
6 KiB
Text
|
<?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'));
|
||
|
}
|
||
|
|
||
|
}
|