artabro/wire/modules/Inputfield/InputfieldSubmit/InputfieldSubmit.module
2024-08-27 11:35:37 +02:00

344 lines
10 KiB
Text

<?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 text
if(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 dropdown
foreach($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 label
if($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;
}
}