Rev 1 | Blame | Compare with Previous | Last modification | View Log | Download
<?php namespace ProcessWire;/*** ProcessWire Checkboxes Inputfield** ProcessWire 3.x, Copyright 2021 by Ryan Cramer* https://processwire.com** @property bool $table Whether or not to display as a table* @property string $thead Pipe "|" separated list of table headings. Do the same for the addOption() labels.* @property int|bool $optionColumns Specify 1 for inline list of options, or qty of columns to list options in.* @property string $optionWidth Alternative to optionColumns, specify option width like '222px', '22em', etc. or '1' for auto. 3.0.184+**/class InputfieldCheckboxes extends InputfieldSelectMultiple implements InputfieldHasArrayValue {public static function getModuleInfo() {return array('title' => __('Checkboxes', __FILE__), // Module Title'summary' => __('Multiple checkbox toggles', __FILE__), // Module Summary'version' => 108,'permanent' => true,);}/*** Init**/public function init() {$this->set('table', false);$this->set('thead', '');$this->set('optionColumns', 0);$this->set('optionWidth', '');parent::init();$this->set('size', null); // cancel 'size' attribute used by select multiple}/*** Render** @return string**/public function ___render() {$sanitizer = $this->wire()->sanitizer;$this->checkDefaultValue();$out = '';$table = null;$columns = (int) $this->optionColumns;$inline = $columns === 1 || $columns > 10;$liAttr = '';$ulClass = '';$inputClass = $sanitizer->entities($this->attr('class'));$entityEncode = $this->getSetting('entityEncodeText') === false ? false : true;$options = $this->getOptions();$optionWidth = $this->optionWidth ? $this->getOptionWidthCSS($this->optionWidth, $options) : '';if($this->table) {/** @var MarkupAdminDataTable $table */$table = $this->modules->get("MarkupAdminDataTable");$table->setEncodeEntities(false);$table->setSortable(false);$table->addClass('pw-no-select');if($this->thead) $table->headerRow(explode('|', htmlspecialchars($this->thead, ENT_QUOTES, 'UTF-8')));} else if($optionWidth) {$liAttr = " style='width:$optionWidth'";$ulClass = 'InputfieldCheckboxesWidth';} else if($columns) {if($inline) {$ulClass = 'InputfieldCheckboxesFloated';} else {$liWidth = round(100 / $columns)-1; // 1% padding-right added from stylesheet$liAttr = " style='width: {$liWidth}%;'";$ulClass = 'InputfieldCheckboxesColumns';}$classes = InputfieldWrapper::getClasses();$ulClass .= " " . $classes['list_clearfix'];} else {$ulClass = 'InputfieldCheckboxesStacked';}if(!$table) $out = "<ul class='$ulClass'>";foreach($options as $key => $value) {$checked = '';if($this->isOptionSelected($key)) $checked = " checked='checked'";$id = $sanitizer->name($key);if(!strlen(trim($id, '_'))) $id = trim(base64_encode($key), '=/.');$id = $this->id . '_' . $id;$attrs = $this->getOptionAttributes($key);$disabled = empty($attrs['disabled']) ? '' : " disabled='disabled'";unset($attrs['checked'], $attrs['selected'], $attrs['disabled']);$attrs = $this->getOptionAttributesString($attrs);if($attrs) $attrs = ' ' . $attrs;if($entityEncode) $value = $this->entityEncode($value, true);$input ="<label$attrs>" ."<input$checked$disabled " ."type='checkbox' " ."name='{$this->name}[]' " ."id='$id' " ."class='$inputClass' " ."value='" . htmlspecialchars($key, ENT_QUOTES, 'UTF-8') . "' />";if($table) {$value = explode("|", nl2br($value));$value[0] = "$input<span class='pw-no-select'>$value[0]</span></label>";$table->row($value);} else {$out .= "<li$liAttr>$input<span class='pw-no-select'>$value</span></label></li>";}}if($table) $out .= $table->render();else $out .= "</ul>";return $out;}/*** Get CSS width and unit for option width** @param string|int $optionWidth* @param array $options* @return string**/public function getOptionWidthCSS($optionWidth, array &$options) {if(!$optionWidth) return '';if(!preg_match('/^(\d+)\s*([a-z]{1,4}|%|);?$/i', $optionWidth, $matches)) return '';$unit = empty($matches[2]) ? 'px' : $matches[2];$optionWidth = $matches[1] . $unit;if($optionWidth === '1px') { // 1 or 1px means "calculate at runtime"$optionWidth = 10;foreach($options as $label) {if(strlen($label) > $optionWidth) $optionWidth = strlen($label);}if($optionWidth > 20) {// use without adjustment} else if($optionWidth > 10) {$optionWidth += 2;} else {$optionWidth = 10; // minimum option width}$optionWidth .= 'ch';}return $optionWidth;}public function set($key, $value) {if($key == 'optionColumns') {$value = (int) $value;if($value < 0) $value = 0;if($value > 10) $value = 10;}return parent::set($key, $value);}public function ___getConfigInputfields() {$modules = $this->wire()->modules;$inputfields = parent::___getConfigInputfields();/** @var InputfieldInteger $f */$f = $modules->get('InputfieldText');$f->label = $this->_('Option column width');$f->description =$this->_('Use this setting to have options display in fixed width columns that float or collapse according to viewport width.') . ' ' .$this->_('Enter a CSS width number and unit such as `100px` or `10em`, for example. If no unit is specified, `px` (pixels) is assumed.') . ' ' .$this->_('Enter the number `1` to automatically calculate an appropriate width at runtime.');$f->notes = $this->_('For best appearance, enter a width that can fit the longest option without word wrapping, or enter `1` to for auto width.');$f->attr('name', 'optionWidth');$f->attr('value', $this->optionWidth);if(!$this->optionWidth) $f->collapsed = Inputfield::collapsedYes;$inputfields->add($f);/** @var InputfieldInteger $f */$f = $modules->get('InputfieldInteger');$f->label = $this->_('Option column quantity');$f->description =$this->_('If you want the options to display in columns, enter the number of columns you want to use (up to 10).') . ' ' .$this->_('To display options inline side-by-side enter the number `1`.');$f->notes = $this->_('Note that the “option column width” setting is preferable for responsive behavior.');$f->attr('name', 'optionColumns');$f->attr('value', (int) $this->optionColumns);if(!$this->optionColumns) $f->collapsed = Inputfield::collapsedYes;$inputfields->add($f);return $inputfields;}}