Blame | Last modification | View Log | Download
<?php namespace ProcessWire;/*** An Inputfield for handling a single checkbox** ProcessWire 3.x, Copyright 2020 by Ryan Cramer* https://processwire.com** Note: if you want a checkbox already checked, you need to add a setAttribute('checked', 'checked');** @property string $checkedValue Value when checked (default=1)* @property string $uncheckedValue Value when not checked (default='', blank string)* @property string $label2 Alterate label to display next to checkbox (default=use regular label)* @property string $checkboxLabel Same as label2, but used as part of field config rather than API-only config.* @property bool $checkboxOnly Show only the checkbox without label text next to it? (default=false) @since 3.0.144* @property array $labelAttrs Optional attributes for <label> element that surrounds checkbox (default=[]) @since 3.0.141* @property int $autocheck When set to 1, setting value attribute to non-blank/non-zero automatically triggers checked.***/class InputfieldCheckbox extends Inputfield {public static function getModuleInfo() {return array('title' => __('Checkbox', __FILE__), // Module Title'summary' => __('Single checkbox toggle', __FILE__), // Module Summary'version' => 106,'permanent' => true,);}/*** Default checked value**/const checkedValueDefault = 1;/*** Default unchecked value**/const uncheckedValueDefault = '';/*** True if the $checkedValue set manually (and should be used as a label), false if it was inherited from $value attribute**/protected $checkedValueIsLabel = false;/*** Construct and set default settings**/public function __construct() {$this->set('checkedValue', self::checkedValueDefault);$this->checkedValueIsLabel = false; // cancel line above$this->set('uncheckedValue', self::uncheckedValueDefault);// when autocheck set to 1, setting the value attribute to non-zero automatically triggered checked=checked attribute$this->set('autocheck', 0);// alternate label for checkbox (both do the same thing but for different config context)$this->set('label2', ''); // typically specified by API$this->set('checkboxOnly', false); // render checkbox only, without showing label text$this->set('checkboxLabel', ''); // typically specified by interactive config$this->set('labelAttrs', array()); // Optional attributes for <label> element that surrounds checkbox (3.0.141+)parent::__construct();// Use an undefined skipLabel setting so we can detect when to apply a custom default in ___render()// according to runtime conditions (placement after parent::__construct() is required)$this->set('skipLabel', -1);}/*** Wired to ProcessWire instance**/public function wired() {$languages = $this->wire()->languages;if($languages) {foreach($languages as $language) {if(!$language->isDefault()) $this->set("checkboxLabel$language", "");}}parent::wired();}/*** Init**/public function init() {parent::init();$this->attr('checked', '');}/*** Render checkbox input** @return string**/public function ___render() {$user = $this->wire()->user;// label placed to the right of the checkbox$checkboxLabel = '';if(!$this->checkboxOnly) {// we will be displaying a label next to the checkboxif($user->language) $checkboxLabel = $this->getSetting("checkboxLabel$user->language");if(!$checkboxLabel) $checkboxLabel = $this->getSetting("checkboxLabel");if(!$checkboxLabel && $this->checkedValueIsLabel) $checkboxLabel = $this->checkedValue;if(!$checkboxLabel) $checkboxLabel = $this->getSetting('label2');$checkboxLabel = trim($checkboxLabel);}if($this->getSetting('skipLabel') === -1) {// nothing has modified the skipLabel setting so apply an automatic settingif($checkboxLabel || $this->description) {$this->set('skipLabel', Inputfield::skipLabelFor);} else {$this->set('skipLabel', Inputfield::skipLabelHeader);}}if(!$checkboxLabel && !$this->checkboxOnly) {$checkboxLabel = $this->label;}$checkboxAttrs = $this->getAttributes();$checkboxAttrs['value'] = $this->checkedValue;unset($checkboxAttrs['type']);$checkboxAttrs = $this->getAttributesString($checkboxAttrs);if(strlen($checkboxLabel)) {if($this->getSetting('entityEncodeLabel') !== false) {$checkboxLabel = $this->entityEncode($checkboxLabel, Inputfield::textFormatBasic);}$checkboxLabel = "<span class='pw-no-select'>$checkboxLabel</span>";}$labelAttrs = $this->getSetting('labelAttrs');$labelAttrs = empty($labelAttrs) ? '' : ' ' . $this->getAttributesString($labelAttrs);$out ="<label$labelAttrs>" ."<input type='checkbox' $checkboxAttrs />" .$checkboxLabel ."</label>";return $out;}/*** Render value only** @return string**/public function ___renderValue() {$value = $this->val();if($value != self::uncheckedValueDefault && $value != $this->uncheckedValue) {$value = $this->wire()->sanitizer->entities($this->checkedValue);$value = $value === "1" ? $this->_('Checked') : $value;$value = wireIconMarkup('check-square-o') . " $value";} else {$value = $this->wire()->sanitizer->entities($this->uncheckedValue);$value = empty($value) ? $this->_('Not checked') : $value;$value = wireIconMarkup('square-o') . " $value";}return $value;}/*** Set attribute** @param array|string $key* @param array|int|string $value* @return Inputfield|InputfieldCheckbox**/public function setAttribute($key, $value) {if($key === 'value' && $value && "$value" !== "$this->uncheckedValue") {if("$value" !== (string) self::checkedValueDefault) {$this->checkedValue = $value;$this->checkedValueIsLabel = false;}// autocheck mode: when non-zero 'value' set, then 'checked=checked' is assumedif($this->autocheck || $this->getSetting('formBuilder')) $this->attr('checked', 'checked');}return parent::setAttribute($key, $value);}/*** Set property** @param string $key* @param mixed $value* @return InputfieldCheckbox|Inputfield**/public function set($key, $value) {if($key === 'checkedValue' && $value != self::checkedValueDefault) {$this->checkedValueIsLabel = true;}return parent::set($key, $value);}/*** Get or set current checkbox boolean attribute state** ~~~~~* // the following two lines are equivalent to GET checkbox state* $checked = $f->checked();* $checked = !empty($f->attr('checked'));** // the following two lines are equivalent to SET checkbox state* $f->checked(true);* $f->attr('checked', 'checked');* ~~~~~** @param bool|null Specify boolean to set checkbox state* @return bool* @since 3.0.133**/public function checked($checked = null) {if($checked !== null) {if($checked) {$this->attr('checked', 'checked');$checked = true;} else {$this->removeAttr('checked');$checked = false;}} else {$checked = $this->attr('checked');$checked = empty($checked) ? false : true;}return $checked;}/*** Is checkbox currently checked?** #pw-internal** @return bool**/public function isChecked() {return $this->checked();}/*** Is empty (checkbox not checked)?** @return bool**/public function isEmpty() {return !$this->checked();}/*** Process input** @param WireInputData $input* @return $this**/public function ___processInput(WireInputData $input) {$value = $input[$this->name];$checked = $this->isChecked();if(!empty($value)) {if(!$checked) $this->trackChange('value', $this->uncheckedValue, $this->checkedValue);parent::attr('checked', 'checked');parent::attr('value', $this->checkedValue);} else {if($checked) $this->trackChange('value', $this->checkedValue, $this->uncheckedValue);parent::attr('checked', '');parent::attr('value', $this->uncheckedValue);}return $this;}/*** Configure checkbox field** @return InputfieldWrapper**/public function ___getConfigInputfields() {$inputfields = parent::___getConfigInputfields();$languages = $this->wire()->languages;/** @var InputfieldText $f */$f = $this->wire()->modules->get('InputfieldText');$f->attr('name', 'checkboxLabel');$f->label = $this->_('Checkbox label');$f->description = $this->_('If you want to have separate field and checkbox labels, specify the label that will appear next to the checkbox here.');$f->notes = $this->_('If not specified, the field label will be used instead.');$f->attr('value', $this->getSetting('checkboxLabel'));$f->icon = 'check-square';if($languages) {$f->useLanguages = true;foreach($languages as $language) {if(!$language->isDefault()) $f->set("value$language", $this->getSetting("checkboxLabel$language"));}}$inputfields->add($f);// if working with fieldtype, no additional settings are applicableif($this->hasFieldtype) return $inputfields;$f = $this->wire()->modules->get('InputfieldText');$f->attr('name', 'checkedValue');$f->attr('value', $this->checkedValue);$f->label = $this->_('Checked Value');$f->collapsed = $this->checkedValue == self::checkedValueDefault ? Inputfield::collapsedYes : Inputfield::collapsedNo;$f->description = $this->_('When populated with something other than "1", this will appear as a label directly next to the checkbox.');$f->required = true;$inputfields->add($f);$f = $this->wire()->modules->get('InputfieldText');$f->attr('name', 'uncheckedValue');$f->attr('value', "$this->uncheckedValue");$f->label = $this->_('Unchecked Value');$f->collapsed = $this->uncheckedValue == self::uncheckedValueDefault ? Inputfield::collapsedYes : Inputfield::collapsedNo;$f->description = $this->_('This only appears in result entries, not in the form itself. You should leave this blank unless you want it to hold a specific value.');$inputfields->add($f);return $inputfields;}}