Rev 1 | Blame | Compare with Previous | Last modification | View Log | Download
<?php namespace ProcessWire;/*** An Inputfield for handling "submit" buttons** ProcessWire 3.x, Copyright 2021 by Ryan Cramer* https://processwire.com* License: MPL 2.0** @property bool $header Whether or not button will also appear in header (default=false).* @property bool $secondary Whether or not button is secondary (default=false).* @property bool $small Whether or not button should be small, where supported (default=false).* @property string $dropdownInputName Name of input to receive selected dropdown value (default='_action_value') #pw-internal* @property bool $dropdownSubmit Selected dropdown value becomes submit value? (default=true) #pw-internal* @property bool $dropdownRequired Require dropdown selection, when true, click submit without selection opens dropdown @since 3.0.180 #pw-internal* @property string $html Button inner HTML label (default='') @since 3.0.134* @property string $text Button inner TEXT label, if $html not provided. (default='') @since 3.0.134* @property string $value Button value attribute and inner TEXT label, if $text it provided (default='Submit')* @property string $textClass Class applied to span for inner html/text, omitted if blank (default='ui-button-text') @since 3.0.134* @property-read string|false $submitValue Value that was submitted if clicked (default=false) @since 3.0.134**/class InputfieldSubmit extends Inputfield {public static function getModuleInfo() {return array('title' => 'Submit', // Module Title'summary' => __('Form submit button', __FILE__), // Module Summary'version' => 103,'permanent' => true,);}/*** Names of submit buttons created** @var array**/protected static $submitNames = array();/*** Additional dropdown actions added to the button** @var array**/protected $dropdownItems = array();/*** Init**/public function init() {parent::init();$this->attr('type', 'submit');$this->attr('name', 'submit');$this->attr('value', $this->_('Submit')); // Standard submit button label$this->set('submitValue', false); // becomes string after processInput$this->attr('class', 'ui-button ui-widget ui-state-default ui-corner-all');$this->set('textClass', 'ui-button-text');$this->skipLabel = Inputfield::skipLabelBlank;$this->set('small', false);$this->set('html', '');$this->set('text', '');// name of 'hidden' input that will receive the clicked dropdown item value$this->set('dropdownInputName', '_action_value');// Selected dropdown value becomes submit value? If set to false, then only the// dropdownInputName above will contain the selected value$this->set('dropdownSubmit', true);// dropdown selection required? (when true, clicking submit without dropdown selection opens dropdown)$this->set('dropdownRequired', false);}public function set($key, $value) {if($key == 'header') {$this->showInHeader($value);} else if($key == 'secondary') {$this->setSecondary($value);}return parent::set($key, $value);}public function get($key) {if($key == 'header') return $this->hasClass('pw-head-button');if($key == 'secondary') return $this->hasClass('ui-priority-secondary');return parent::get($key);}public function setAttribute($key, $value) {if($key === 'name') self::$submitNames[$value] = $value;return parent::setAttribute($key, $value);}/*** Show another copy of this button in the header?** @param bool $show True=yes, false=no (default=true)* @return $this**/public function showInHeader($show = true) {if($show) {$this->addClass('pw-head-button');} else {$this->removeClass('pw-head-button');}return $this;}/*** Make this button secondary? (slightly faded)** Note: by default, buttons are not secondary** @param bool $secondary Default=true* @return $this**/public function setSecondary($secondary = true) {if($secondary) {$this->addClass('ui-priority-secondary');} else {$this->removeClass('ui-priority-secondary');}return $this;}/*** Make this button small?** By default, buttons are regular size. This makes them small.* Supported only for non-dropdown, non-header buttons.** @param bool $small Default=true* @return $this**/public function setSmall($small = true) {$this->set('small', $small ? true : false);return $this;}/*** Render ready** @param Inputfield|InputfieldWrapper|null The parent InputfieldWrapper that is rendering it, or null if no parent.* @param bool $renderValueMode Specify true only if this is for `Inputfield::renderValue()` rather than `Inputfield::render()`.* @return bool True if assets were just added, false if already added.**/public function renderReady(Inputfield $parent = null, $renderValueMode = false) {$class = $this->attr('class');if(strpos($class, 'head_button_clone') !== false) {// if legacy class name used, convert to updated pw- class name to accomodate 3rd party usages$class = str_replace('head_button_clone', 'pw-head-button', $class);$this->attr('class', $class);}if($this->getSetting('small')) {$this->addClass('InputfieldSubmitSmall', 'wrapClass');}return parent::renderReady($parent, $renderValueMode);}/*** Render the button** @return string**/public function ___render() {$sanitizer = $this->wire()->sanitizer;$attrs = $this->getAttributesString();$icon = $this->icon ? $sanitizer->name($this->icon) : '';$icon = $icon ? wireIconMarkup($icon) . ' ' : '';$buttonText = $this->getSetting('html'); // option for non-encoded button textif(empty($buttonText)) {$buttonText = $this->getSetting('text');if(empty($buttonText)) $buttonText = $this->attr('value');$buttonText = $this->entityEncode($buttonText);}$buttonText = $icon . $buttonText;$textClass = $sanitizer->entities($this->getSetting('textClass'));if(!empty($textClass)) $buttonText = "<span class='$textClass'>$buttonText</span>";$out = "<button $attrs>$buttonText</button>";if($this->getSetting('small')) $out = "<small>$out</small>";if(count($this->dropdownItems)) $out .= $this->renderDropdown();return $out;}/*** Render the dropdown to accompany the button** @return string**/protected function renderDropdown() {if($this->wire('input')->get('modal')) return '';$config = $this->wire()->config;$file = $config->debug ? 'dropdown.js' : 'dropdown.min.js';$config->scripts->add($config->urls->InputfieldSubmit . $file);$numValues = 0;$dropdownID = $this->attr('id') . '_dropdown';$out = "<ul id='$dropdownID' class='pw-button-dropdown' data-my='left top' data-at='left bottom+1'>";foreach($this->dropdownItems as $item) {// entity encode all the labels in the dropdownforeach($item as $k => $v) {if($k == 'type') continue;$item[$k] = htmlentities($v, ENT_QUOTES, "UTF-8");}if($item['type'] == 'link') {// direct link$out .= "<li><a href='$item[value]'>";} else {// populate hidden input with value before submit$out .= "<li><a data-pw-dropdown-value='$item[value]' href='#'>";$numValues++;}// icon to accompany labelif($item['icon']) $out .= "<i class='fa fa-fw fa-$item[icon]'></i>";// label and finish item$out .= "$item[label]</a></li>";}$out .= "</ul>";if($numValues) {// there are values that can be populated to a hidden input$inputID = $dropdownID . '_value';$attr = "type='hidden' name='{$this->dropdownInputName}' id='$inputID' value='' ";// copy the submitted dropdown value to the submit button value?if($this->dropdownSubmit) $attr .= "data-pw-dropdown-submit='1' ";// render the output$out = "<input $attr />" . str_replace("<ul ", "<ul data-pw-dropdown-input='#$inputID' ", $out);}$required = $this->dropdownRequired ? 'true' : 'false';// script to initialize this dropdown immediately$out .= "<script" . ">InputfieldSubmitDropdown.init('#{$this->id}', null, $required);</script>";return $out;}/*** Process input** @param WireInputData $input* @return $this**/public function ___processInput(WireInputData $input) {$this->submitValue = '';$name = $this->attr('name');$value = $input->$name;if($value === $this->attr('value')) {$this->submitValue = $value;return $this;}if(!count($this->dropdownItems)) return $this;if(!$this->dropdownSubmit) {$name = $this->dropdownInputName;$value = $input->$name;}if($value === null) return $this;foreach($this->dropdownItems as $item) {if($value !== $item['value']) continue;$this->submitValue = $item['value'];break;}return $this;}/*** Add a dropdown item to this button** @param string $type Either 'link' or 'value'* @param string|int $value* @param string $label* @param string $icon**/protected function addActionItem($type, $value, $label, $icon) {if(!$icon) $icon = 'angle-double-right';$this->dropdownItems[] = array('type' => $type,'value' => $value,'label' => $label,'icon' => $icon,);}/*** Add a dropdown action item that populates a new 'value' for the submit button** This also populates the value to $_POST['_action_value']** @param string $value Value to populate to hidden input when dropdown item is selected/clicked.* @param string $label Text label to accompany the item* @param string $icon Icon name (optional)**/public function addActionValue($value, $label, $icon = '') {$this->addActionItem('value', $value, $label, $icon);}/*** Add a dropdown action item that links to a URL** @param string $url URL to link to* @param string $label Text label to accompany the item* @param string $icon Icon name (optional)**/public function addActionLink($url, $label, $icon = '') {$this->addActionItem('link', $url, $label, $icon);}/*** #pw-internal** @return array()**/static public function getSubmitNames() {return self::$submitNames;}}