File manager - Edit - /home/opticamezl/www/newok/Form.tar
Back
Field/ConditionsField.php 0000604 00000002710 15172705215 0011356 0 ustar 00 <?php /** * @package Conditions * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Component\Conditions\Site\Form\Field; defined('_JEXEC') or die; use RegularLabs\Library\DB as RL_DB; use RegularLabs\Library\Form\FormField as RL_FormField; class ConditionsField extends RL_FormField { static $options; public bool $is_select_list = true; public function getNamesByIds(array $values, array $attributes): array { $query = $this->db->getQuery(true) ->select('condition.name') ->from('#__conditions AS condition') ->where(RL_DB::is('condition.id', $values)) ->order('condition.name ASC'); $this->db->setQuery($query); return $this->db->loadColumn(); } protected function getOptions() { if ( ! is_null(self::$options)) { return self::$options; } $query = $this->db->getQuery(true) ->select('condition.id as value, condition.name as text') ->from('#__conditions AS condition') ->order('a.name ASC'); $this->db->setQuery($query); self::$options = $this->db->loadObjectList(); return self::$options; } } Form.php 0000644 00000201563 15172746170 0006201 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Language\Text; use Joomla\CMS\Object\CMSObject; use Joomla\Database\DatabaseAwareInterface; use Joomla\Database\DatabaseAwareTrait; use Joomla\Database\DatabaseInterface; use Joomla\Database\Exception\DatabaseNotFoundException; use Joomla\Registry\Registry; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Class for the Joomla Platform. * * This class implements a robust API for constructing, populating, filtering, and validating forms. * It uses XML definitions to construct form fields and a variety of field and rule classes to * render and validate the form. * * @link https://www.w3.org/TR/html4/interact/forms.html * @link https://html.spec.whatwg.org/multipage/forms.html * @since 1.7.0 */ class Form { use DatabaseAwareTrait; /** * The Registry data store for form fields during display. * * @var Registry * @since 1.7.0 */ protected $data; /** * The form object errors array. * * @var \Exception[] * @since 1.7.0 */ protected $errors = []; /** * The name of the form instance. * * @var string * @since 1.7.0 */ protected $name; /** * The form object options for use in rendering and validation. * * @var array * @since 1.7.0 */ protected $options = []; /** * The form XML definition. * * @var \SimpleXMLElement * @since 1.7.0 */ protected $xml; /** * Form instances. * * @var Form[] * @since 1.7.0 */ protected static $forms = []; /** * Allows extensions to implement repeating elements * * @var boolean * @since 3.2 */ public $repeat = false; /** * Method to instantiate the form object. * * @param string $name The name of the form. * @param array $options An array of form options. * * @since 1.7.0 */ public function __construct($name, array $options = []) { // Set the name for the form. $this->name = $name; // Initialise the Registry data. $this->data = new Registry(); // Set the options if specified. $this->options['control'] = $options['control'] ?? false; } /** * Method to bind data to the form. * * @param mixed $data An array or object of data to bind to the form. * * @return boolean True on success. * * @since 1.7.0 */ public function bind($data) { // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } // The data must be an object or array. if (!\is_object($data) && !\is_array($data)) { return false; } $this->bindLevel(null, $data); return true; } /** * Method to bind data to the form for the group level. * * @param string $group The dot-separated form group path on which to bind the data. * @param mixed $data An array or object of data to bind to the form for the group level. * * @return void * * @since 1.7.0 */ protected function bindLevel($group, $data) { // Ensure the input data is an array. if (\is_object($data)) { if ($data instanceof Registry) { // Handle a Registry. $data = $data->toArray(); } elseif ($data instanceof CMSObject) { // Handle a CMSObject. $data = $data->getProperties(); } else { // Handle other types of objects. $data = (array) $data; } } // Process the input data. foreach ($data as $k => $v) { $level = $group ? $group . '.' . $k : $k; if ($this->findField($k, $group)) { // If the field exists set the value. $this->data->set($level, $v); } elseif (\is_object($v) || ArrayHelper::isAssociative($v)) { // If the value is an object or an associative array, hand it off to the recursive bind level method. $this->bindLevel($level, $v); } } } /** * Return Exceptions thrown during the form validation process. * * @return \Exception[] * * @since 1.7.0 */ public function getErrors() { return $this->errors; } /** * Method to get a form field represented as a FormField object. * * @param string $name The name of the form field. * @param string $group The optional dot-separated form group path on which to find the field. * @param mixed $value The optional value to use as the default for the field. * * @return FormField|boolean The FormField object for the field or boolean false on error. * * @since 1.7.0 */ public function getField($name, $group = null, $value = null) { // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } // Attempt to find the field by name and group. $element = $this->findField($name, $group); // If the field element was not found return false. if (!$element) { return false; } return $this->loadField($element, $group, $value); } /** * Method to get an attribute value from a field XML element. If the attribute doesn't exist or * is null then the optional default value will be used. * * @param string $name The name of the form field for which to get the attribute value. * @param string $attribute The name of the attribute for which to get a value. * @param mixed $default The optional default value to use if no attribute value exists. * @param string $group The optional dot-separated form group path on which to find the field. * * @return mixed The attribute value for the field. * * @since 1.7.0 * @throws \UnexpectedValueException */ public function getFieldAttribute($name, $attribute, $default = null, $group = null) { // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } // Find the form field element from the definition. $element = $this->findField($name, $group); // If the element exists and the attribute exists for the field return the attribute value. if (($element instanceof \SimpleXMLElement) && \strlen((string) $element[$attribute])) { return (string) $element[$attribute]; } else { // Otherwise return the given default value. return $default; } } /** * Method to get an array of FormField objects in a given fieldset by name. If no name is * given then all fields are returned. * * @param string $set The optional name of the fieldset. * * @return FormField[] The array of FormField objects in the fieldset. * * @since 1.7.0 */ public function getFieldset($set = null) { $fields = []; // Get all of the field elements in the fieldset. if ($set) { $elements = $this->findFieldsByFieldset($set); } else { // Get all fields. $elements = $this->findFieldsByGroup(); } // If no field elements were found return empty. if (empty($elements)) { return $fields; } // Build the result array from the found field elements. foreach ($elements as $element) { // Get the field groups for the element. $attrs = $element->xpath('ancestor::fields[@name]/@name'); $groups = array_map('strval', $attrs ?: []); $group = implode('.', $groups); // If the field is successfully loaded add it to the result array. if ($field = $this->loadField($element, $group)) { $fields[$field->id] = $field; } } return $fields; } /** * Method to get an array of fieldset objects optionally filtered over a given field group. * * @param string $group The dot-separated form group path on which to filter the fieldsets. * * @return object[] The array of fieldset objects. * * @since 1.7.0 */ public function getFieldsets($group = null) { $fieldsets = []; $sets = []; // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } if ($group) { // Get the fields elements for a given group. $elements = &$this->findGroup($group); foreach ($elements as &$element) { // Get an array of <fieldset /> elements and fieldset attributes within the fields element. if ($tmp = $element->xpath('descendant::fieldset[@name] | descendant::field[@fieldset]/@fieldset')) { $sets = array_merge($sets, (array) $tmp); } } } else { // Get an array of <fieldset /> elements and fieldset attributes. $sets = $this->xml->xpath('//fieldset[@name and not(ancestor::field/form/*)] | //field[@fieldset and not(ancestor::field/form/*)]/@fieldset'); } // If no fieldsets are found return empty. if (empty($sets)) { return $fieldsets; } // Process each found fieldset. foreach ($sets as $set) { if ((string) $set['hidden'] === 'true') { continue; } // Are we dealing with a fieldset element? if ((string) $set['name']) { // Only create it if it doesn't already exist. if (empty($fieldsets[(string) $set['name']])) { // Build the fieldset object. $fieldset = (object) ['name' => '', 'label' => '', 'description' => '']; foreach ($set->attributes() as $name => $value) { $fieldset->$name = (string) $value; } // Add the fieldset object to the list. $fieldsets[$fieldset->name] = $fieldset; } } else { // Must be dealing with a fieldset attribute. // Only create it if it doesn't already exist. if (empty($fieldsets[(string) $set])) { // Attempt to get the fieldset element for data (throughout the entire form document). $tmp = $this->xml->xpath('//fieldset[@name="' . (string) $set . '"]'); // If no element was found, build a very simple fieldset object. if (empty($tmp)) { $fieldset = (object) ['name' => (string) $set, 'label' => '', 'description' => '']; } else { // Build the fieldset object from the element. $fieldset = (object) ['name' => '', 'label' => '', 'description' => '']; foreach ($tmp[0]->attributes() as $name => $value) { $fieldset->$name = (string) $value; } } // Add the fieldset object to the list. $fieldsets[$fieldset->name] = $fieldset; } } } return $fieldsets; } /** * Method to get the form control. This string serves as a container for all form fields. For * example, if there is a field named 'foo' and a field named 'bar' and the form control is * empty the fields will be rendered like: `<input name="foo" />` and `<input name="bar" />`. If * the form control is set to 'joomla' however, the fields would be rendered like: * `<input name="joomla[foo]" />` and `<input name="joomla[bar]" />`. * * @return string The form control string. * * @since 1.7.0 */ public function getFormControl() { return (string) $this->options['control']; } /** * Method to get an array of FormField objects in a given field group by name. * * @param string $group The dot-separated form group path for which to get the form fields. * @param boolean $nested True to also include fields in nested groups that are inside of the * group for which to find fields. * * @return FormField[] The array of FormField objects in the field group. * * @since 1.7.0 */ public function getGroup($group, $nested = false) { $fields = []; // Get all of the field elements in the field group. $elements = $this->findFieldsByGroup($group, $nested); // If no field elements were found return empty. if (empty($elements)) { return $fields; } // Build the result array from the found field elements. foreach ($elements as $element) { // Get the field groups for the element. $attrs = $element->xpath('ancestor::fields[@name]/@name'); $groups = array_map('strval', $attrs ?: []); $group = implode('.', $groups); // If the field is successfully loaded add it to the result array. if ($field = $this->loadField($element, $group)) { $fields[$field->id] = $field; } } return $fields; } /** * Method to get a form field markup for the field input. * * @param string $name The name of the form field. * @param string $group The optional dot-separated form group path on which to find the field. * @param mixed $value The optional value to use as the default for the field. * * @return string The form field markup. * * @since 1.7.0 */ public function getInput($name, $group = null, $value = null) { // Attempt to get the form field. if ($field = $this->getField($name, $group, $value)) { return $field->input; } return ''; } /** * Method to get the label for a field input. * * @param string $name The name of the form field. * @param string $group The optional dot-separated form group path on which to find the field. * * @return string The form field label. * * @since 1.7.0 */ public function getLabel($name, $group = null) { // Attempt to get the form field. if ($field = $this->getField($name, $group)) { return $field->label; } return ''; } /** * Method to get the form name. * * @return string The name of the form. * * @since 1.7.0 */ public function getName() { return $this->name; } /** * Method to get the value of a field. * * @param string $name The name of the field for which to get the value. * @param string $group The optional dot-separated form group path on which to get the value. * @param mixed $default The optional default value of the field value is empty. * * @return mixed The value of the field or the default value if empty. * * @since 1.7.0 */ public function getValue($name, $group = null, $default = null) { // If a group is set use it. if ($group) { $return = $this->data->get($group . '.' . $name, $default); } else { $return = $this->data->get($name, $default); } return $return; } /** * Method to get a control group with label and input. * * @param string $name The name of the field for which to get the value. * @param string $group The optional dot-separated form group path on which to get the value. * @param mixed $default The optional default value of the field value is empty. * @param array $options Any options to be passed into the rendering of the field * * @return string A string containing the html for the control group * * @since 3.2.3 */ public function renderField($name, $group = null, $default = null, $options = []) { $field = $this->getField($name, $group, $default); if ($field) { return $field->renderField($options); } return ''; } /** * Method to get all control groups with label and input of a fieldset. * * @param string $name The name of the fieldset for which to get the values. * @param array $options Any options to be passed into the rendering of the field * * @return string A string containing the html for the control groups * * @since 3.2.3 */ public function renderFieldset($name, $options = []) { $fields = $this->getFieldset($name); $html = []; foreach ($fields as $field) { $html[] = $field->renderField($options); } return implode('', $html); } /** * Method to load the form description from an XML string or object. * * The replace option works per field. If a field being loaded already exists in the current * form definition then the behavior or load will vary depending upon the replace flag. If it * is set to true, then the existing field will be replaced in its exact location by the new * field being loaded. If it is false, then the new field being loaded will be ignored and the * method will move on to the next field to load. * * @param string|\SimpleXMLElement $data The name of an XML string or object. * @param boolean $replace Flag to toggle whether form fields should be replaced if a field * already exists with the same group/name. * @param string $xpath An optional xpath to search for the fields. * * @return boolean True on success, false otherwise. * * @since 1.7.0 */ public function load($data, $replace = true, $xpath = null) { // If the data to load isn't already an XML element or string return false. if (!($data instanceof \SimpleXMLElement) && !\is_string($data)) { return false; } // Attempt to load the XML if a string. if (\is_string($data)) { try { $data = new \SimpleXMLElement($data); } catch (\Exception $e) { return false; } } // If we have no XML definition at this point let's make sure we get one. if (empty($this->xml)) { // If no XPath query is set to search for fields, and we have a <form />, set it and return. if (!$xpath && ($data->getName() === 'form')) { $this->xml = $data; // Synchronize any paths found in the load. $this->syncPaths(); return true; } else { // Create a root element for the form. $this->xml = new \SimpleXMLElement('<form></form>'); } } // Get the XML elements to load. $elements = []; if ($xpath) { $elements = $data->xpath($xpath); } elseif ($data->getName() === 'form') { $elements = $data->children(); } // If there is nothing to load return true. if (empty($elements)) { return true; } // Load the found form elements. foreach ($elements as $element) { // Get an array of fields with the correct name. $fields = $element->xpath('descendant-or-self::field'); foreach ($fields as $field) { // Get the group names as strings for ancestor fields elements. $attrs = $field->xpath('ancestor::fields[@name]/@name'); $groups = array_map('strval', $attrs ?: []); // Check to see if the field exists in the current form. if ($current = $this->findField((string) $field['name'], implode('.', $groups))) { // If set to replace found fields, replace the data and remove the field so we don't add it twice. if ($replace) { $olddom = dom_import_simplexml($current); $loadeddom = dom_import_simplexml($field); $addeddom = $olddom->ownerDocument->importNode($loadeddom, true); $olddom->parentNode->replaceChild($addeddom, $olddom); $loadeddom->parentNode->removeChild($loadeddom); } else { unset($field); } } } // Merge the new field data into the existing XML document. self::addNode($this->xml, $element); } // Synchronize any paths found in the load. $this->syncPaths(); return true; } /** * Method to load the form description from an XML file. * * The reset option works on a group basis. If the XML file references * groups that have already been created they will be replaced with the * fields in the new XML file unless the $reset parameter has been set * to false. * * @param string $file The filesystem path of an XML file. * @param boolean $reset Flag to toggle whether form fields should be replaced if a field * already exists with the same group/name. * @param string $xpath An optional xpath to search for the fields. * * @return boolean True on success, false otherwise. * * @since 1.7.0 */ public function loadFile($file, $reset = true, $xpath = null) { // Check to see if the path is an absolute path. if (!is_file($file)) { // Not an absolute path so let's attempt to find one using JPath. $file = Path::find(self::addFormPath(), strtolower($file) . '.xml'); // If unable to find the file return false. if (!$file) { return false; } } // Attempt to load the XML file. $xml = simplexml_load_file($file); return $this->load($xml, $reset, $xpath); } /** * Method to remove a field from the form definition. * * @param string $name The name of the form field for which remove. * @param string $group The optional dot-separated form group path on which to find the field. * * @return boolean True on success, false otherwise. * * @since 1.7.0 * @throws \UnexpectedValueException */ public function removeField($name, $group = null) { // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } // Find the form field element from the definition. $element = $this->findField($name, $group); // If the element exists remove it from the form definition. if ($element instanceof \SimpleXMLElement) { $dom = dom_import_simplexml($element); $dom->parentNode->removeChild($dom); return true; } return false; } /** * Method to remove a group from the form definition. * * @param string $group The dot-separated form group path for the group to remove. * * @return boolean True on success. * * @since 1.7.0 * @throws \UnexpectedValueException */ public function removeGroup($group) { // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } // Get the fields elements for a given group. $elements = &$this->findGroup($group); foreach ($elements as &$element) { $dom = dom_import_simplexml($element); $dom->parentNode->removeChild($dom); } return true; } /** * Method to reset the form data store and optionally the form XML definition. * * @param boolean $xml True to also reset the XML form definition. * * @return boolean True on success. * * @since 1.7.0 */ public function reset($xml = false) { unset($this->data); $this->data = new Registry(); if ($xml) { unset($this->xml); $this->xml = new \SimpleXMLElement('<form></form>'); } return true; } /** * Method to set a field XML element to the form definition. If the replace flag is set then * the field will be set whether it already exists or not. If it isn't set, then the field * will not be replaced if it already exists. * * @param \SimpleXMLElement $element The XML element object representation of the form field. * @param string $group The optional dot-separated form group path on which to set the field. * @param boolean $replace True to replace an existing field if one already exists. * @param string $fieldset The name of the fieldset we are adding the field to. * * @return boolean True on success. * * @since 1.7.0 * @throws \UnexpectedValueException */ public function setField(\SimpleXMLElement $element, $group = null, $replace = true, $fieldset = 'default') { // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } // Find the form field element from the definition. $old = $this->findField((string) $element['name'], $group); // If an existing field is found and replace flag is false do nothing and return true. if (!$replace && !empty($old)) { return true; } // If an existing field is found and replace flag is true remove the old field. if ($replace && !empty($old) && ($old instanceof \SimpleXMLElement)) { $dom = dom_import_simplexml($old); // Get the parent element, this should be the fieldset $parent = $dom->parentNode; $fieldset = $parent->getAttribute('name'); $parent->removeChild($dom); } // Create the search path $path = '//'; if (!empty($group)) { $path .= 'fields[@name="' . $group . '"]/'; } $path .= 'fieldset[@name="' . $fieldset . '"]'; $fs = $this->xml->xpath($path); if (isset($fs[0]) && ($fs[0] instanceof \SimpleXMLElement)) { // Add field to the form. self::addNode($fs[0], $element); // Synchronize any paths found in the load. $this->syncPaths(); return true; } // We couldn't find a fieldset to add the field. Now we are checking, if we have set only a group if (!empty($group)) { $fields = &$this->findGroup($group); // If an appropriate fields element was found for the group, add the element. if (isset($fields[0]) && ($fields[0] instanceof \SimpleXMLElement)) { self::addNode($fields[0], $element); } // Synchronize any paths found in the load. $this->syncPaths(); return true; } // We couldn't find a parent so we are adding it at root level // Add field to the form. self::addNode($this->xml, $element); // Synchronize any paths found in the load. $this->syncPaths(); return true; } /** * Method to set an attribute value for a field XML element. * * @param string $name The name of the form field for which to set the attribute value. * @param string $attribute The name of the attribute for which to set a value. * @param mixed $value The value to set for the attribute. * @param string $group The optional dot-separated form group path on which to find the field. * * @return boolean True on success. * * @since 1.7.0 * @throws \UnexpectedValueException */ public function setFieldAttribute($name, $attribute, $value, $group = null) { // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } // Find the form field element from the definition. $element = $this->findField($name, $group); // If the element doesn't exist return false. if (!($element instanceof \SimpleXMLElement)) { return false; } else { // Otherwise set the attribute and return true. $element[$attribute] = $value; // Synchronize any paths found in the load. $this->syncPaths(); return true; } } /** * Method to set some field XML elements to the form definition. If the replace flag is set then * the fields will be set whether they already exists or not. If it isn't set, then the fields * will not be replaced if they already exist. * * @param \SimpleXMLElement[] &$elements The array of XML element object representations of the form fields. * @param string $group The optional dot-separated form group path on which to set the fields. * @param boolean $replace True to replace existing fields if they already exist. * @param string $fieldset The name of the fieldset we are adding the field to. * * @return boolean True on success. * * @since 1.7.0 * @throws \UnexpectedValueException */ public function setFields(&$elements, $group = null, $replace = true, $fieldset = 'default') { // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } // Make sure the elements to set are valid. foreach ($elements as $element) { if (!($element instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } } // Set the fields. $return = true; foreach ($elements as $element) { if (!$this->setField($element, $group, $replace, $fieldset)) { $return = false; } } // Synchronize any paths found in the load. $this->syncPaths(); return $return; } /** * Method to set the value of a field. If the field does not exist in the form then the method * will return false. * * @param string $name The name of the field for which to set the value. * @param string $group The optional dot-separated form group path on which to find the field. * @param mixed $value The value to set for the field. * * @return boolean True on success. * * @since 1.7.0 */ public function setValue($name, $group = null, $value = null) { // If the field does not exist return false. if (!$this->findField($name, $group)) { return false; } // If a group is set use it. if ($group) { $this->data->set($group . '.' . $name, $value); } else { $this->data->set($name, $value); } return true; } /** * Method to process the form data. * * @param array $data An array of field values to filter. * @param string $group The dot-separated form group path on which to filter the fields. * * @return mixed Array or false. * * @since 4.0.0 */ public function process($data, $group = null) { $data = $this->filter($data, $group); $valid = $this->validate($data, $group); if (!$valid) { return $valid; } return $this->postProcess($data, $group); } /** * Method to filter the form data. * * @param array $data An array of field values to filter. * @param string $group The dot-separated form group path on which to filter the fields. * * @return mixed Array or false. * * @since 4.0.0 */ public function filter($data, $group = null) { // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } $input = new Registry($data); $output = new Registry(); // Get the fields for which to filter the data. $fields = $this->findFieldsByGroup($group); if (!$fields) { // PANIC! return false; } // Filter the fields. foreach ($fields as $field) { $name = (string) $field['name']; // Get the field groups for the element. $attrs = $field->xpath('ancestor::fields[@name]/@name'); $groups = array_map('strval', $attrs ?: []); $attrGroup = implode('.', $groups); $key = $attrGroup ? $attrGroup . '.' . $name : $name; // Filter the value if it exists. if ($input->exists($key)) { $fieldObj = $this->loadField($field, $group); // Only set into the output if the field was supposed to render on the page (i.e. setup returned true) if ($fieldObj) { $output->set($key, $fieldObj->filter($input->get($key, (string) $field['default']), $group, $input)); } } } return $output->toArray(); } /** * Method to validate form data. * * Validation warnings will be pushed into Form::$errors and should be * retrieved with Form::getErrors() when validate returns boolean false. * * @param array $data An array of field values to validate. * @param string $group The optional dot-separated form group path on which to filter the * fields to be validated. * * @return boolean True on success. * * @since 1.7.0 */ public function validate($data, $group = null) { // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } $return = true; // Create an input registry object from the data to validate. $input = new Registry($data); // Get the fields for which to validate the data. $fields = $this->findFieldsByGroup($group); if (!$fields) { // PANIC! return false; } // Validate the fields. foreach ($fields as $field) { $name = (string) $field['name']; // Define field name for messages if ($field['label']) { $fieldLabel = $field['label']; // Try to translate label if not set to false $translate = (string) $field['translateLabel']; if (!($translate === 'false' || $translate === 'off' || $translate === '0')) { $fieldLabel = Text::_($fieldLabel); } } else { $fieldLabel = Text::_($name); } $disabled = ((string) $field['disabled'] === 'true' || (string) $field['disabled'] === 'disabled'); $fieldExistsInRequestData = $input->exists($name) || $input->exists($group . '.' . $name); // If the field is disabled but it is passed in the request this is invalid as disabled fields are not added to the request if ($disabled && $fieldExistsInRequestData) { throw new \RuntimeException(Text::sprintf('JLIB_FORM_VALIDATE_FIELD_INVALID', $fieldLabel)); } // Get the field groups for the element. $attrs = $field->xpath('ancestor::fields[@name]/@name'); $groups = array_map('strval', $attrs ?: []); $attrGroup = implode('.', $groups); $key = $attrGroup ? $attrGroup . '.' . $name : $name; $fieldObj = $this->loadField($field, $attrGroup); if ($fieldObj) { $valid = $fieldObj->validate($input->get($key), $attrGroup, $input); // Check for an error. if ($valid instanceof \Exception) { $this->errors[] = $valid; $return = false; } } elseif ($input->exists($key)) { // The field returned false from setup and shouldn't be included in the page body - yet we received // a value for it. This is probably some sort of injection attack and should be rejected $this->errors[] = new \RuntimeException(Text::sprintf('JLIB_FORM_VALIDATE_FIELD_INVALID', $key)); $return = false; } } return $return; } /** * Method to post-process form data. * * @param array $data An array of field values to post-process. * @param string $group The optional dot-separated form group path on which to filter the * fields to be validated. * * @return mixed Array or false. * * @since 4.0.0 */ public function postProcess($data, $group = null) { // Make sure there is a valid SimpleXMLElement if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } $input = new Registry($data); $output = new Registry(); // Get the fields for which to postProcess the data. $fields = $this->findFieldsByGroup($group); if (!$fields) { // PANIC! return false; } // Filter the fields. foreach ($fields as $field) { $name = (string) $field['name']; // Get the field groups for the element. $attrs = $field->xpath('ancestor::fields[@name]/@name'); $groups = array_map('strval', $attrs ?: []); $attrGroup = implode('.', $groups); $key = $attrGroup ? $attrGroup . '.' . $name : $name; // Filter the value if it exists. if ($input->exists($key)) { $fieldobj = $this->loadField($field, $group); $output->set($key, $fieldobj->postProcess($input->get($key, (string) $field['default']), $group, $input)); } } return $output->toArray(); } /** * Method to get a form field represented as an XML element object. * * @param string $name The name of the form field. * @param string $group The optional dot-separated form group path on which to find the field. * * @return \SimpleXMLElement|boolean The XML element object for the field or boolean false on error. * * @since 1.7.0 */ protected function findField($name, $group = null) { $element = false; $fields = []; // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } // Let's get the appropriate field element based on the method arguments. if ($group) { // Get the fields elements for a given group. $elements = &$this->findGroup($group); // Get all of the field elements with the correct name for the fields elements. foreach ($elements as $el) { // If there are matching field elements add them to the fields array. if ($tmp = $el->xpath('descendant::field[@name="' . $name . '" and not(ancestor::field/form/*)]')) { $fields = array_merge($fields, $tmp); } } // Make sure something was found. if (!$fields) { return false; } // Use the first correct match in the given group. $groupNames = explode('.', $group); foreach ($fields as &$field) { // Get the group names as strings for ancestor fields elements. $attrs = $field->xpath('ancestor::fields[@name]/@name'); $names = array_map('strval', $attrs ?: []); // If the field is in the exact group use it and break out of the loop. if ($names == (array) $groupNames) { $element = &$field; break; } } } else { // Get an array of fields with the correct name. $fields = $this->xml->xpath('//field[@name="' . $name . '" and not(ancestor::field/form/*)]'); // Make sure something was found. if (!$fields) { return false; } // Search through the fields for the right one. foreach ($fields as &$field) { // If we find an ancestor fields element with a group name then it isn't what we want. if ($field->xpath('ancestor::fields[@name]')) { continue; } else { // Found it! $element = &$field; break; } } } return $element; } /** * Method to get an array of `<field>` elements from the form XML document which are in a specified fieldset by name. * * @param string $name The name of the fieldset. * * @return \SimpleXMLElement[]|boolean Boolean false on error or array of SimpleXMLElement objects. * * @since 1.7.0 */ protected function &findFieldsByFieldset($name) { // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } /* * Get an array of <field /> elements that are underneath a <fieldset /> element * with the appropriate name attribute, and also any <field /> elements with * the appropriate fieldset attribute. To allow repeatable elements only fields * which are not descendants of other fields are selected. */ $fields = $this->xml->xpath('(//fieldset[@name="' . $name . '"]//field | //field[@fieldset="' . $name . '"])[not(ancestor::field)]'); return $fields; } /** * Method to get an array of `<field>` elements from the form XML document which are in a control group by name. * * @param mixed $group The optional dot-separated form group path on which to find the fields. * Null will return all fields. False will return fields not in a group. * @param boolean $nested True to also include fields in nested groups that are inside of the * group for which to find fields. * * @return \SimpleXMLElement[]|boolean Boolean false on error or array of SimpleXMLElement objects. * * @since 1.7.0 */ protected function &findFieldsByGroup($group = null, $nested = false) { $fields = []; // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } // Get only fields in a specific group? if ($group) { // Get the fields elements for a given group. $elements = &$this->findGroup($group); // Get all of the field elements for the fields elements. foreach ($elements as $element) { // If there are field elements add them to the return result. if ($tmp = $element->xpath('descendant::field')) { // If we also want fields in nested groups then just merge the arrays. if ($nested) { $fields = array_merge($fields, $tmp); } else { // If we want to exclude nested groups then we need to check each field. $groupNames = explode('.', $group); foreach ($tmp as $field) { // Get the names of the groups that the field is in. $attrs = $field->xpath('ancestor::fields[@name]/@name'); $names = array_map('strval', $attrs ?: []); // If the field is in the specific group then add it to the return list. if ($names == (array) $groupNames) { $fields = array_merge($fields, [$field]); } } } } } } elseif ($group === false) { // Get only field elements not in a group. $fields = $this->xml->xpath('descendant::fields[not(@name)]/field | descendant::fields[not(@name)]/fieldset/field '); } else { // Get an array of all the <field /> elements. $fields = $this->xml->xpath('//field[not(ancestor::field/form/*)]'); } return $fields; } /** * Method to get a form field group represented as an XML element object. * * @param string $group The dot-separated form group path on which to find the group. * * @return \SimpleXMLElement[]|boolean An array of XML element objects for the group or boolean false on error. * * @since 1.7.0 */ protected function &findGroup($group) { $groups = []; $tmp = []; // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } // Make sure there is actually a group to find. $group = explode('.', $group); if (count($group)) { // Get any fields elements with the correct group name. $elements = $this->xml->xpath('//fields[@name="' . (string) $group[0] . '" and not(ancestor::field/form/*)]'); // Check to make sure that there are no parent groups for each element. foreach ($elements as $element) { if (!$element->xpath('ancestor::fields[@name]')) { $tmp[] = $element; } } // Iterate through the nested groups to find any matching form field groups. for ($i = 1, $n = \count($group); $i < $n; $i++) { // Initialise some loop variables. $validNames = \array_slice($group, 0, $i + 1); $current = $tmp; $tmp = []; // Check to make sure that there are no parent groups for each element. foreach ($current as $element) { // Get any fields elements with the correct group name. $children = $element->xpath('descendant::fields[@name="' . (string) $group[$i] . '"]'); // For the found fields elements validate that they are in the correct groups. foreach ($children as $fields) { // Get the group names as strings for ancestor fields elements. $attrs = $fields->xpath('ancestor-or-self::fields[@name]/@name'); $names = array_map('strval', $attrs ?: []); // If the group names for the fields element match the valid names at this // level add the fields element. if ($validNames == $names) { $tmp[] = $fields; } } } } // Only include valid XML objects. foreach ($tmp as $element) { if ($element instanceof \SimpleXMLElement) { $groups[] = $element; } } } return $groups; } /** * Method to load, setup and return a FormField object based on field data. * * @param string|\SimpleXMLElement $element The XML element object representation of the form field. * @param string $group The optional dot-separated form group path on which to find the field. * @param mixed $value The optional value to use as the default for the field. * * @return FormField|boolean The FormField object for the field or boolean false on error. * * @since 1.7.0 */ protected function loadField($element, $group = null, $value = null) { // Make sure there is a valid SimpleXMLElement. if (!($element instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } // Get the field type. $type = $element['type'] ? (string) $element['type'] : 'text'; // Load the FormField object for the field. $field = FormHelper::loadFieldType($type); if ($field instanceof DatabaseAwareInterface) { try { $field->setDatabase($this->getDatabase()); } catch (DatabaseNotFoundException $e) { @trigger_error(sprintf('Database must be set, this will not be caught anymore in 5.0.'), E_USER_DEPRECATED); $field->setDatabase(Factory::getContainer()->get(DatabaseInterface::class)); } } // If the object could not be loaded, get a text field object. if ($field === false) { $field = FormHelper::loadFieldType('text'); } /* * Get the value for the form field if not set. * Default to the translated version of the 'default' attribute * if 'translate_default' attribute if set to 'true' or '1' * else the value of the 'default' attribute for the field. */ if ($value === null) { $default = (string) ($element['default'] ? $element['default'] : $element->default); if (($translate = $element['translate_default']) && ((string) $translate === 'true' || (string) $translate === '1')) { $lang = Factory::getLanguage(); if ($lang->hasKey($default)) { $debug = $lang->setDebug(false); $default = Text::_($default); $lang->setDebug($debug); } else { $default = Text::_($default); } } $value = $this->getValue((string) $element['name'], $group, $default); } // Setup the FormField object. $field->setForm($this); if ($field->setup($element, $value, $group)) { return $field; } else { return false; } } /** * Method to synchronize any field, form or rule paths contained in the XML document. * * @return boolean True on success. * * @since 1.7.0 * @todo Maybe we should receive all addXXXpaths attributes at once? */ protected function syncPaths() { // Make sure there is a valid Form XML document. if (!($this->xml instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::%s `xml` is not an instance of SimpleXMLElement', \get_class($this), __METHOD__)); } // Get any addfieldpath attributes from the form definition. $paths = $this->xml->xpath('//*[@addfieldpath]/@addfieldpath'); $paths = array_map('strval', $paths ?: []); // Add the field paths. foreach ($paths as $path) { $path = JPATH_ROOT . '/' . ltrim($path, '/\\'); self::addFieldPath($path); } // Get any addformpath attributes from the form definition. $paths = $this->xml->xpath('//*[@addformpath]/@addformpath'); $paths = array_map('strval', $paths ?: []); // Add the form paths. foreach ($paths as $path) { $path = JPATH_ROOT . '/' . ltrim($path, '/\\'); self::addFormPath($path); } // Get any addrulepath attributes from the form definition. $paths = $this->xml->xpath('//*[@addrulepath]/@addrulepath'); $paths = array_map('strval', $paths ?: []); // Add the rule paths. foreach ($paths as $path) { $path = JPATH_ROOT . '/' . ltrim($path, '/\\'); self::addRulePath($path); } // Get any addrulepath attributes from the form definition. $paths = $this->xml->xpath('//*[@addfilterpath]/@addfilterpath'); $paths = array_map('strval', $paths ?: []); // Add the rule paths. foreach ($paths as $path) { $path = JPATH_ROOT . '/' . ltrim($path, '/\\'); self::addFilterPath($path); } // Get any addfieldprefix attributes from the form definition. $prefixes = $this->xml->xpath('//*[@addfieldprefix]/@addfieldprefix'); $prefixes = array_map('strval', $prefixes ?: []); // Add the field prefixes. foreach ($prefixes as $prefix) { FormHelper::addFieldPrefix($prefix); } // Get any addformprefix attributes from the form definition. $prefixes = $this->xml->xpath('//*[@addformprefix]/@addformprefix'); $prefixes = array_map('strval', $prefixes ?: []); // Add the field prefixes. foreach ($prefixes as $prefix) { FormHelper::addFormPrefix($prefix); } // Get any addruleprefix attributes from the form definition. $prefixes = $this->xml->xpath('//*[@addruleprefix]/@addruleprefix'); $prefixes = array_map('strval', $prefixes ?: []); // Add the field prefixes. foreach ($prefixes as $prefix) { FormHelper::addRulePrefix($prefix); } // Get any addruleprefix attributes from the form definition. $prefixes = $this->xml->xpath('//*[@addfilterprefix]/@addfilterprefix'); $prefixes = array_map('strval', $prefixes ?: []); // Add the field prefixes. foreach ($prefixes as $prefix) { FormHelper::addFilterPrefix($prefix); } return true; } /** * Proxy for {@link FormHelper::addFieldPath()}. * * @param string|string[] $new A path or array of paths to add. * * @return string[] The list of paths that have been added. * * @since 1.7.0 */ public static function addFieldPath($new = null) { return FormHelper::addFieldPath($new); } /** * Proxy for FormHelper::addFormPath(). * * @param string|string[] $new A path or array of paths to add. * * @return string[] The list of paths that have been added. * * @see FormHelper::addFormPath() * @since 1.7.0 */ public static function addFormPath($new = null) { return FormHelper::addFormPath($new); } /** * Proxy for FormHelper::addRulePath(). * * @param string|string[] $new A path or array of paths to add. * * @return string[] The list of paths that have been added. * * @see FormHelper::addRulePath() * @since 1.7.0 */ public static function addRulePath($new = null) { return FormHelper::addRulePath($new); } /** * Proxy for FormHelper::addFilterPath(). * * @param string|string[] $new A path or array of paths to add. * * @return string[] The list of paths that have been added. * * @see FormHelper::addFilterPath() * @since 4.0.0 */ public static function addFilterPath($new = null) { return FormHelper::addFilterPath($new); } /** * Method to get an instance of a form. * * @param string $name The name of the form. * @param string $data The name of an XML file or string to load as the form definition. * @param array $options An array of form options. * @param boolean $replace Flag to toggle whether form fields should be replaced if a field * already exists with the same group/name. * @param string|boolean $xpath An optional xpath to search for the fields. * * @return Form Form instance. * * @since 1.7.0 * * @deprecated 4.3 will be removed in 6.0 * Use the FormFactory service from the container * Example: Factory::getContainer()->get(FormFactoryInterface::class)->createForm($name, $options); * * @throws \InvalidArgumentException if no data provided. * @throws \RuntimeException if the form could not be loaded. */ public static function getInstance($name, $data = null, $options = [], $replace = true, $xpath = false) { // Reference to array with form instances $forms = &self::$forms; // Only instantiate the form if it does not already exist. if (!isset($forms[$name])) { $data = trim($data); if (empty($data)) { throw new \InvalidArgumentException(sprintf('%1$s(%2$s, *%3$s*)', __METHOD__, $name, \gettype($data))); } // Instantiate the form. $forms[$name] = Factory::getContainer()->get(FormFactoryInterface::class)->createForm($name, $options); // Load the data. if (substr($data, 0, 1) === '<') { if ($forms[$name]->load($data, $replace, $xpath) == false) { throw new \RuntimeException(sprintf('%s() could not load form', __METHOD__)); } } else { if ($forms[$name]->loadFile($data, $replace, $xpath) == false) { throw new \RuntimeException(sprintf('%s() could not load file', __METHOD__)); } } } return $forms[$name]; } /** * Adds a new child SimpleXMLElement node to the source. * * @param \SimpleXMLElement $source The source element on which to append. * @param \SimpleXMLElement $new The new element to append. * * @return void * * @since 1.7.0 */ protected static function addNode(\SimpleXMLElement $source, \SimpleXMLElement $new) { // Add the new child node. $node = $source->addChild($new->getName(), htmlspecialchars(trim($new))); // Add the attributes of the child node. foreach ($new->attributes() as $name => $value) { $node->addAttribute($name, $value); } // Add any children of the new node. foreach ($new->children() as $child) { self::addNode($node, $child); } } /** * Update the attributes of a child node * * @param \SimpleXMLElement $source The source element on which to append the attributes * @param \SimpleXMLElement $new The new element to append * * @return void * * @since 1.7.0 */ protected static function mergeNode(\SimpleXMLElement $source, \SimpleXMLElement $new) { // Update the attributes of the child node. foreach ($new->attributes() as $name => $value) { if (isset($source[$name])) { $source[$name] = (string) $value; } else { $source->addAttribute($name, $value); } } } /** * Merges new elements into a source `<fields>` element. * * @param \SimpleXMLElement $source The source element. * @param \SimpleXMLElement $new The new element to merge. * * @return void * * @since 1.7.0 */ protected static function mergeNodes(\SimpleXMLElement $source, \SimpleXMLElement $new) { // The assumption is that the inputs are at the same relative level. // So we just have to scan the children and deal with them. // Update the attributes of the child node. foreach ($new->attributes() as $name => $value) { if (isset($source[$name])) { $source[$name] = (string) $value; } else { $source->addAttribute($name, $value); } } foreach ($new->children() as $child) { $type = $child->getName(); $name = $child['name']; // Does this node exist? $fields = $source->xpath($type . '[@name="' . $name . '"]'); if (empty($fields)) { // This node does not exist, so add it. self::addNode($source, $child); } else { // This node does exist. switch ($type) { case 'field': self::mergeNode($fields[0], $child); break; default: self::mergeNodes($fields[0], $child); break; } } } } /** * Returns the value of an attribute of the form itself * * @param string $name Name of the attribute to get * @param mixed $default Optional value to return if attribute not found * * @return mixed Value of the attribute / default * * @since 3.2 */ public function getAttribute($name, $default = null) { if ($this->xml instanceof \SimpleXMLElement) { $value = $this->xml->attributes()->$name; if ($value !== null) { return (string) $value; } } return $default; } /** * Getter for the form data * * @return Registry Object with the data * * @since 3.2 */ public function getData() { return $this->data; } /** * Method to get the XML form object * * @return \SimpleXMLElement The form XML object * * @since 3.2 */ public function getXml() { return $this->xml; } /** * Method to get a form field represented as an XML element object. * * @param string $name The name of the form field. * @param string $group The optional dot-separated form group path on which to find the field. * * @return \SimpleXMLElement|boolean The XML element object for the field or boolean false on error. * * @since 3.7.0 */ public function getFieldXml($name, $group = null) { return $this->findField($name, $group); } } FormField.php 0000644 00000116200 15172746170 0007136 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form; use Joomla\CMS\Factory; use Joomla\CMS\Filter\InputFilter; use Joomla\CMS\Form\Field\SubformField; use Joomla\CMS\Language\Text; use Joomla\CMS\Layout\FileLayout; use Joomla\CMS\Log\Log; use Joomla\Database\DatabaseAwareInterface; use Joomla\Database\DatabaseAwareTrait; use Joomla\Database\DatabaseInterface; use Joomla\Database\Exception\DatabaseNotFoundException; use Joomla\Registry\Registry; use Joomla\String\Normalise; use Joomla\String\StringHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Abstract Form Field class for the Joomla Platform. * * @since 1.7.0 */ abstract class FormField implements DatabaseAwareInterface { use DatabaseAwareTrait; /** * The description text for the form field. Usually used in tooltips. * * @var string * @since 1.7.0 */ protected $description; /** * The hint text for the form field used to display hint inside the field. * * @var string * @since 3.2 */ protected $hint; /** * The autocomplete state for the form field. If 'off' element will not be automatically * completed by browser. * * @var mixed * @since 3.2 */ protected $autocomplete = 'on'; /** * The spellcheck state for the form field. * * @var boolean * @since 3.2 */ protected $spellcheck = true; /** * The autofocus request for the form field. If true element will be automatically * focused on document load. * * @var boolean * @since 3.2 */ protected $autofocus = false; /** * The SimpleXMLElement object of the `<field>` XML element that describes the form field. * * @var \SimpleXMLElement * @since 1.7.0 */ protected $element; /** * The Form object of the form attached to the form field. * * @var Form * @since 1.7.0 */ protected $form; /** * The form control prefix for field names from the Form object attached to the form field. * * @var string * @since 1.7.0 */ protected $formControl; /** * The hidden state for the form field. * * @var boolean * @since 1.7.0 */ protected $hidden = false; /** * Should the label be hidden when rendering the form field? This may be useful if you have the * label rendering in a legend in your form field itself for radio buttons in a fieldset etc. * If you use this flag you should ensure you display the label in your form (for a11y etc.) * * @var boolean * @since 4.0.0 */ protected $hiddenLabel = false; /** * Should the description be hidden when rendering the form field? This may be useful if you have the * description rendering in your form field itself for e.g. note fields. * * @var boolean * @since 4.0.0 */ protected $hiddenDescription = false; /** * True to translate the field label string. * * @var boolean * @since 1.7.0 */ protected $translateLabel = true; /** * True to translate the field description string. * * @var boolean * @since 1.7.0 */ protected $translateDescription = true; /** * True to translate the field hint string. * * @var boolean * @since 3.2 */ protected $translateHint = true; /** * The document id for the form field. * * @var string * @since 1.7.0 */ protected $id; /** * The input for the form field. * * @var string * @since 1.7.0 */ protected $input; /** * The label for the form field. * * @var string * @since 1.7.0 */ protected $label; /** * The multiple state for the form field. If true then multiple values are allowed for the * field. Most often used for list field types. * * @var boolean * @since 1.7.0 */ protected $multiple = false; /** * Allows extensions to create repeat elements * * @var mixed * @since 3.2 */ public $repeat = false; /** * The pattern (Reg Ex) of value of the form field. * * @var string * @since 1.7.0 */ protected $pattern; /** * The validation text of invalid value of the form field. * * @var string * @since 4.0.0 */ protected $validationtext; /** * The name of the form field. * * @var string * @since 1.7.0 */ protected $name; /** * The name of the field. * * @var string * @since 1.7.0 */ protected $fieldname; /** * The group of the field. * * @var string * @since 1.7.0 */ protected $group; /** * The required state for the form field. If true then there must be a value for the field to * be considered valid. * * @var boolean * @since 1.7.0 */ protected $required = false; /** * The disabled state for the form field. If true then the field will be disabled and user can't * interact with the field. * * @var boolean * @since 3.2 */ protected $disabled = false; /** * The readonly state for the form field. If true then the field will be readonly. * * @var boolean * @since 3.2 */ protected $readonly = false; /** * The form field type. * * @var string * @since 1.7.0 */ protected $type; /** * The validation method for the form field. This value will determine which method is used * to validate the value for a field. * * @var string * @since 1.7.0 */ protected $validate; /** * The value of the form field. * * @var mixed * @since 1.7.0 */ protected $value; /** * The default value of the form field. * * @var mixed * @since 1.7.0 */ protected $default; /** * The size of the form field. * * @var integer * @since 3.2 */ protected $size; /** * The class of the form field * * @var mixed * @since 3.2 */ protected $class; /** * The label's CSS class of the form field * * @var mixed * @since 1.7.0 */ protected $labelclass; /** * The javascript onchange of the form field. * * @var string * @since 3.2 */ protected $onchange; /** * The javascript onclick of the form field. * * @var string * @since 3.2 */ protected $onclick; /** * The conditions to show/hide the field. * * @var string * @since 3.7.0 */ protected $showon; /** * The parent class of the field * * @var string * @since 4.0.0 */ protected $parentclass; /** * The count value for generated name field * * @var integer * @since 1.7.0 */ protected static $count = 0; /** * The string used for generated fields names * * @var string * @since 1.7.0 */ protected static $generated_fieldname = '__field'; /** * Name of the layout being used to render the field * * @var string * @since 3.5 */ protected $layout; /** * Layout to render the form field * * @var string */ protected $renderLayout = 'joomla.form.renderfield'; /** * Layout to render the label * * @var string */ protected $renderLabelLayout = 'joomla.form.renderlabel'; /** * The data-attribute name and values of the form field. * For example, data-action-type="click" data-action-type="change" * * @var array * * @since 4.0.0 */ protected $dataAttributes = []; /** * Method to instantiate the form field object. * * @param Form $form The form to attach to the form field object. * * @since 1.7.0 */ public function __construct($form = null) { // If there is a form passed into the constructor set the form and form control properties. if ($form instanceof Form) { $this->form = $form; $this->formControl = $form->getFormControl(); } // Detect the field type if not set if (!isset($this->type)) { $parts = Normalise::fromCamelCase(\get_called_class(), true); if ($parts[0] === 'J') { $this->type = StringHelper::ucfirst($parts[\count($parts) - 1], '_'); } else { $this->type = StringHelper::ucfirst($parts[0], '_') . StringHelper::ucfirst($parts[\count($parts) - 1], '_'); } } } /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 1.7.0 */ public function __get($name) { switch ($name) { case 'description': case 'hint': case 'formControl': case 'hidden': case 'id': case 'multiple': case 'name': case 'required': case 'type': case 'validate': case 'value': case 'class': case 'layout': case 'labelclass': case 'size': case 'onchange': case 'onclick': case 'fieldname': case 'group': case 'disabled': case 'readonly': case 'autofocus': case 'autocomplete': case 'spellcheck': case 'validationtext': case 'showon': case 'parentclass': return $this->$name; case 'input': // If the input hasn't yet been generated, generate it. if (empty($this->input)) { $this->input = $this->getInput(); } return $this->input; case 'label': // If the label hasn't yet been generated, generate it. if (empty($this->label)) { $this->label = $this->getLabel(); } return $this->label; case 'title': return $this->getTitle(); default: // Check for data attribute if (strpos($name, 'data-') === 0 && array_key_exists($name, $this->dataAttributes)) { return $this->dataAttributes[$name]; } } } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'class': // Removes spaces from left & right and extra spaces from middle $value = preg_replace('/\s+/', ' ', trim((string) $value)); // No break case 'description': case 'hint': case 'value': case 'labelclass': case 'layout': case 'onchange': case 'onclick': case 'validate': case 'pattern': case 'validationtext': case 'group': case 'showon': case 'parentclass': case 'default': case 'autocomplete': $this->$name = (string) $value; break; case 'id': $this->id = $this->getId((string) $value, $this->fieldname); break; case 'fieldname': $this->fieldname = $this->getFieldName((string) $value); break; case 'name': $this->fieldname = $this->getFieldName((string) $value); $this->name = $this->getName($this->fieldname); break; case 'multiple': // Allow for field classes to force the multiple values option. $value = (string) $value; $value = $value === '' && isset($this->forceMultiple) ? (string) $this->forceMultiple : $value; // No break case 'required': case 'disabled': case 'readonly': case 'autofocus': case 'hidden': $value = (string) $value; $this->$name = ($value === 'true' || $value === $name || $value === '1'); break; case 'spellcheck': case 'translateLabel': case 'translateDescription': case 'translateHint': $value = (string) $value; $this->$name = !($value === 'false' || $value === 'off' || $value === '0'); break; case 'translate_label': $value = (string) $value; $this->translateLabel = $this->translateLabel && !($value === 'false' || $value === 'off' || $value === '0'); break; case 'translate_description': $value = (string) $value; $this->translateDescription = $this->translateDescription && !($value === 'false' || $value === 'off' || $value === '0'); break; case 'size': $this->$name = (int) $value; break; default: // Detect data attribute(s) if (strpos($name, 'data-') === 0) { $this->dataAttributes[$name] = $value; } else { if (property_exists(__CLASS__, $name)) { Log::add("Cannot access protected / private property $name of " . __CLASS__); } else { $this->$name = $value; } } } } /** * Method to attach a Form object to the field. * * @param Form $form The Form object to attach to the form field. * * @return FormField The form field object so that the method can be used in a chain. * * @since 1.7.0 */ public function setForm(Form $form) { $this->form = $form; $this->formControl = $form->getFormControl(); return $this; } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @since 1.7.0 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { // Make sure there is a valid FormField XML element. if ((string) $element->getName() !== 'field') { return false; } // Reset the input and label values. $this->input = null; $this->label = null; // Set the XML element object. $this->element = $element; // Set the group of the field. $this->group = $group; $attributes = [ 'multiple', 'name', 'id', 'hint', 'class', 'description', 'labelclass', 'onchange', 'onclick', 'validate', 'pattern', 'validationtext', 'default', 'required', 'disabled', 'readonly', 'autofocus', 'hidden', 'autocomplete', 'spellcheck', 'translateHint', 'translateLabel', 'translate_label', 'translateDescription', 'translate_description', 'size', 'showon', ]; $this->default = isset($element['value']) ? (string) $element['value'] : $this->default; // Set the field default value. if ($element['multiple'] && \is_string($value) && \is_array(json_decode($value, true))) { $this->value = (array) json_decode($value); } else { $this->value = $value; } // Lets detect miscellaneous data attribute. For eg, data-* foreach ($this->element->attributes() as $key => $value) { if (strpos($key, 'data-') === 0) { // Data attribute key value pair $this->dataAttributes[$key] = $value; } } foreach ($attributes as $attributeName) { $this->__set($attributeName, $element[$attributeName]); } // Allow for repeatable elements $repeat = (string) $element['repeat']; $this->repeat = ($repeat === 'true' || $repeat === 'multiple' || (!empty($this->form->repeat) && $this->form->repeat == 1)); // Set the visibility. $this->hidden = ($this->hidden || strtolower((string) $this->element['type']) === 'hidden'); $this->layout = !empty($this->element['layout']) ? (string) $this->element['layout'] : $this->layout; $this->parentclass = isset($this->element['parentclass']) ? (string) $this->element['parentclass'] : $this->parentclass; // Add required to class list if field is required. if ($this->required) { $this->class = trim($this->class . ' required'); } return true; } /** * Simple method to set the value * * @param mixed $value Value to set * * @return void * * @since 3.2 */ public function setValue($value) { $this->value = $value; } /** * Method to get the id used for the field input tag. * * @param string $fieldId The field element id. * @param string $fieldName The field element name. * * @return string The id to be used for the field input tag. * * @since 1.7.0 */ protected function getId($fieldId, $fieldName) { $id = ''; // If there is a form control set for the attached form add it first. if ($this->formControl) { $id .= $this->formControl; } // If the field is in a group add the group control to the field id. if ($this->group) { // If we already have an id segment add the group control as another level. if ($id) { $id .= '_' . str_replace('.', '_', $this->group); } else { $id .= str_replace('.', '_', $this->group); } } // If we already have an id segment add the field id/name as another level. if ($id) { $id .= '_' . ($fieldId ?: $fieldName); } else { $id .= ($fieldId ?: $fieldName); } // Clean up any invalid characters. $id = preg_replace('#\W#', '_', $id); // If this is a repeatable element, add the repeat count to the ID if ($this->repeat) { $repeatCounter = empty($this->form->repeatCounter) ? 0 : $this->form->repeatCounter; $id .= '-' . $repeatCounter; if (strtolower($this->type) === 'radio') { $id .= '-'; } } return $id; } /** * Method to get the field input markup. * * @return string The field input markup. * * @since 1.7.0 */ protected function getInput() { if (empty($this->layout)) { throw new \UnexpectedValueException(sprintf('%s has no layout assigned.', $this->name)); } return $this->getRenderer($this->layout)->render($this->getLayoutData()); } /** * Method to get the field title. * * @return string The field title. * * @since 1.7.0 */ protected function getTitle() { $title = ''; if ($this->hidden) { return $title; } // Get the label text from the XML element, defaulting to the element name. $title = $this->element['label'] ? (string) $this->element['label'] : (string) $this->element['name']; $title = $this->translateLabel ? Text::_($title) : $title; return $title; } /** * Method to get the field label markup. * * @return string The field label markup. * * @since 1.7.0 */ protected function getLabel() { if ($this->hidden) { return ''; } $data = $this->getLayoutData(); // Forcing the Alias field to display the tip below $position = ((string) $this->element['name']) === 'alias' ? ' data-bs-placement="bottom" ' : ''; // Here mainly for B/C with old layouts. This can be done in the layouts directly $extraData = [ 'text' => $data['label'], 'for' => $this->id, 'classes' => explode(' ', $data['labelclass']), 'position' => $position, ]; return $this->getRenderer($this->renderLabelLayout)->render(array_merge($data, $extraData)); } /** * Method to get the name used for the field input tag. * * @param string $fieldName The field element name. * * @return string The name to be used for the field input tag. * * @since 1.7.0 */ protected function getName($fieldName) { // To support repeated element, extensions can set this in plugin->onRenderSettings $name = ''; // If there is a form control set for the attached form add it first. if ($this->formControl) { $name .= $this->formControl; } // If the field is in a group add the group control to the field name. if ($this->group) { // If we already have a name segment add the group control as another level. $groups = explode('.', $this->group); if ($name) { foreach ($groups as $group) { $name .= '[' . $group . ']'; } } else { $name .= array_shift($groups); foreach ($groups as $group) { $name .= '[' . $group . ']'; } } } // If we already have a name segment add the field name as another level. if ($name) { $name .= '[' . $fieldName . ']'; } else { $name .= $fieldName; } // If the field should support multiple values add the final array segment. if ($this->multiple) { switch (strtolower((string) $this->element['type'])) { case 'text': case 'textarea': case 'email': case 'password': case 'radio': case 'calendar': case 'editor': case 'hidden': break; default: $name .= '[]'; } } return $name; } /** * Method to get the field name used. * * @param string $fieldName The field element name. * * @return string The field name * * @since 1.7.0 */ protected function getFieldName($fieldName) { if ($fieldName) { return $fieldName; } else { self::$count = self::$count + 1; return self::$generated_fieldname . self::$count; } } /** * Method to get an attribute of the field * * @param string $name Name of the attribute to get * @param mixed $default Optional value to return if attribute not found * * @return mixed Value of the attribute / default * * @since 3.2 */ public function getAttribute($name, $default = null) { if ($this->element instanceof \SimpleXMLElement) { $attributes = $this->element->attributes(); // Ensure that the attribute exists if ($attributes->$name !== null) { return (string) $attributes->$name; } } return $default; } /** * Method to get data attributes. For example, data-user-type * * @return array list of data attribute(s) * * @since 4.0.0 */ public function getDataAttributes() { return $this->dataAttributes; } /** * Method to render data attributes to html. * * @return string A HTML Tag Attribute string of data attribute(s) * * @since 4.0.0 */ public function renderDataAttributes() { $dataAttribute = ''; $dataAttributes = $this->getDataAttributes(); if (!empty($dataAttributes)) { foreach ($dataAttributes as $key => $attrValue) { $dataAttribute .= ' ' . $key . '="' . htmlspecialchars($attrValue, ENT_COMPAT, 'UTF-8') . '"'; } } return $dataAttribute; } /** * Render a layout of this field * * @param string $layoutId Layout identifier * @param array $data Optional data for the layout * * @return string * * @since 3.5 */ public function render($layoutId, $data = []) { $data = array_merge($this->getLayoutData(), $data); return $this->getRenderer($layoutId)->render($data); } /** * Method to get a control group with label and input. * * @param array $options Options to be passed into the rendering of the field * * @return string A string containing the html for the control group * * @since 3.2 */ public function renderField($options = []) { if ($this->hidden) { return $this->getInput(); } if (!isset($options['class'])) { $options['class'] = ''; } $options['rel'] = ''; if (empty($options['hiddenLabel'])) { if ($this->getAttribute('hiddenLabel')) { $options['hiddenLabel'] = $this->getAttribute('hiddenLabel') == 'true'; } else { $options['hiddenLabel'] = $this->hiddenLabel; } } if (empty($options['hiddenDescription'])) { if ($this->getAttribute('hiddenDescription')) { $options['hiddenDescription'] = $this->getAttribute('hiddenDescription') == 'true'; } else { $options['hiddenDescription'] = $this->hiddenDescription; } } $options['inlineHelp'] = isset($this->form, $this->form->getXml()->config->inlinehelp['button']) ? ((string) $this->form->getXml()->config->inlinehelp['button'] == 'show' ?: false) : false; // Check if the field has showon in nested option $hasOptionShowOn = false; if (!empty((array) $this->element->xpath('option'))) { foreach ($this->element->xpath('option') as $option) { if ((string) $option['showon']) { $hasOptionShowOn = true; break; } } } if ($this->showon || $hasOptionShowOn) { $options['rel'] = ' data-showon=\'' . json_encode(FormHelper::parseShowOnConditions($this->showon, $this->formControl, $this->group)) . '\''; $options['showonEnabled'] = true; } $data = [ 'input' => $this->getInput(), 'label' => $this->getLabel(), 'options' => $options, ]; $data = array_merge($this->getLayoutData(), $data); return $this->getRenderer($this->renderLayout)->render($data); } /** * Method to filter a field value. * * @param mixed $value The optional value to use as the default for the field. * @param string $group The optional dot-separated form group path on which to find the field. * @param ?Registry $input An optional Registry object with the entire data set to filter * against the entire form. * * @return mixed The filtered value. * * @since 4.0.0 * @throws \UnexpectedValueException */ public function filter($value, $group = null, Registry $input = null) { // Make sure there is a valid SimpleXMLElement. if (!($this->element instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::filter `element` is not an instance of SimpleXMLElement', \get_class($this))); } // Get the field filter type. $filter = (string) $this->element['filter']; if ($filter !== '') { $required = ((string) $this->element['required'] === 'true' || (string) $this->element['required'] === 'required'); if (($value === '' || $value === null) && !$required) { return ''; } // Check for a callback filter if (strpos($filter, '::') !== false && \is_callable(explode('::', $filter))) { return \call_user_func(explode('::', $filter), $value); } // Load the FormRule object for the field. FormRule objects take precedence over PHP functions $obj = FormHelper::loadFilterType($filter); // Run the filter rule. if ($obj) { return $obj->filter($this->element, $value, $group, $input, $this->form); } if (\function_exists($filter)) { return \call_user_func($filter, $value); } if ($this instanceof SubformField) { $subForm = $this->loadSubForm(); // Subform field may have a default value, that is a JSON string if ($value && is_string($value)) { $value = json_decode($value, true); // The string is invalid json if (!$value) { return null; } } if ($this->multiple) { $return = []; if ($value) { foreach ($value as $key => $val) { $return[$key] = $subForm->filter($val); } } } else { $return = $subForm->filter($value); } return $return; } } return InputFilter::getInstance()->clean($value, $filter); } /** * Method to validate a FormField object based on field data. * * @param mixed $value The optional value to use as the default for the field. * @param string $group The optional dot-separated form group path on which to find the field. * @param ?Registry $input An optional Registry object with the entire data set to validate * against the entire form. * * @return boolean|\Exception Boolean true if field value is valid, Exception on failure. * * @since 4.0.0 * @throws \InvalidArgumentException * @throws \UnexpectedValueException */ public function validate($value, $group = null, Registry $input = null) { // Make sure there is a valid SimpleXMLElement. if (!($this->element instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::validate `element` is not an instance of SimpleXMLElement', \get_class($this))); } $valid = true; // Check if the field is required. $required = ((string) $this->element['required'] === 'true' || (string) $this->element['required'] === 'required'); if ($this->element['label']) { $fieldLabel = $this->element['label']; // Try to translate label if not set to false $translate = (string) $this->element['translateLabel']; if (!($translate === 'false' || $translate === 'off' || $translate === '0')) { $fieldLabel = Text::_($fieldLabel); } } else { $fieldLabel = Text::_($this->element['name']); } // If the field is required and the value is empty return an error message. if ($required && (($value === '') || ($value === null))) { $message = Text::sprintf('JLIB_FORM_VALIDATE_FIELD_REQUIRED', $fieldLabel); return new \RuntimeException($message); } // Get the field validation rule. if ($type = (string) $this->element['validate']) { // Load the FormRule object for the field. $rule = FormHelper::loadRuleType($type); // If the object could not be loaded return an error message. if ($rule === false) { throw new \UnexpectedValueException(sprintf('%s::validate() rule `%s` missing.', \get_class($this), $type)); } if ($rule instanceof DatabaseAwareInterface) { try { $rule->setDatabase($this->getDatabase()); } catch (DatabaseNotFoundException $e) { @trigger_error(sprintf('Database must be set, this will not be caught anymore in 5.0.'), E_USER_DEPRECATED); $rule->setDatabase(Factory::getContainer()->get(DatabaseInterface::class)); } } try { // Run the field validation rule test. $valid = $rule->test($this->element, $value, $group, $input, $this->form); } catch (\Exception $e) { return $e; } } if ($valid !== false && $this instanceof SubformField) { // Load the subform validation rule. $rule = FormHelper::loadRuleType('Subform'); if ($rule instanceof DatabaseAwareInterface) { try { $rule->setDatabase($this->getDatabase()); } catch (DatabaseNotFoundException $e) { @trigger_error(sprintf('Database must be set, this will not be caught anymore in 5.0.'), E_USER_DEPRECATED); $rule->setDatabase(Factory::getContainer()->get(DatabaseInterface::class)); } } try { // Run the field validation rule test. $valid = $rule->test($this->element, $value, $group, $input, $this->form); } catch (\Exception $e) { return $e; } } // Check if the field is valid. if ($valid === false) { // Does the field have a defined error message? $message = (string) $this->element['message']; if ($message) { $message = Text::_($this->element['message']); } else { $message = Text::sprintf('JLIB_FORM_VALIDATE_FIELD_INVALID', $fieldLabel); } return new \UnexpectedValueException($message); } return $valid; } /** * Method to post-process a field value. * * @param mixed $value The optional value to use as the default for the field. * @param string $group The optional dot-separated form group path on which to find the field. * @param ?Registry $input An optional Registry object with the entire data set to filter * against the entire form. * * @return mixed The processed value. * * @since 4.0.0 */ public function postProcess($value, $group = null, Registry $input = null) { return $value; } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.5 */ protected function getLayoutData() { $label = !empty($this->element['label']) ? (string) $this->element['label'] : null; $label = $label && $this->translateLabel ? Text::_($label) : $label; $description = !empty($this->description) ? $this->description : null; $description = !empty($description) && $this->translateDescription ? Text::_($description) : $description; $alt = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname); $options = [ 'autocomplete' => $this->autocomplete, 'autofocus' => $this->autofocus, 'class' => $this->class, 'description' => $description, 'disabled' => $this->disabled, 'field' => $this, 'group' => $this->group, 'hidden' => $this->hidden, 'hint' => $this->translateHint ? Text::alt($this->hint, $alt) : $this->hint, 'id' => $this->id, 'label' => $label, 'labelclass' => $this->labelclass, 'multiple' => $this->multiple, 'name' => $this->name, 'onchange' => $this->onchange, 'onclick' => $this->onclick, 'pattern' => $this->pattern, 'validationtext' => $this->validationtext, 'readonly' => $this->readonly, 'repeat' => $this->repeat, 'required' => (bool) $this->required, 'size' => $this->size, 'spellcheck' => $this->spellcheck, 'validate' => $this->validate, 'value' => $this->value, 'dataAttribute' => $this->renderDataAttributes(), 'dataAttributes' => $this->dataAttributes, 'parentclass' => $this->parentclass, ]; return $options; } /** * Allow to override renderer include paths in child fields * * @return array * * @since 3.5 */ protected function getLayoutPaths() { $renderer = new FileLayout('default'); return $renderer->getDefaultIncludePaths(); } /** * Get the renderer * * @param string $layoutId Id to load * * @return FileLayout * * @since 3.5 */ protected function getRenderer($layoutId = 'default') { $renderer = new FileLayout($layoutId); $renderer->setDebug($this->isDebugEnabled()); $layoutPaths = $this->getLayoutPaths(); if ($layoutPaths) { $renderer->setIncludePaths($layoutPaths); } return $renderer; } /** * Is debug enabled for this field * * @return boolean * * @since 3.5 */ protected function isDebugEnabled() { return $this->getAttribute('debug', 'false') === 'true'; } } FormFieldGroup.php 0000604 00000001074 15172746170 0010151 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form; defined('_JEXEC') or die; /** * @depracated No longer used */ class FormFieldGroup extends \RegularLabs\Library\Form\FormField { public $default_group = 'Categories'; public $type = 'Field'; } Field/HeaderField.php 0000604 00000010035 15172746170 0010441 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Factory as JFactory; use Joomla\CMS\Installer\Installer as JInstaller; use Joomla\CMS\Language\Text as JText; use RegularLabs\Library\Form\FormField as RL_FormField; use RegularLabs\Library\RegEx as RL_RegEx; use RegularLabs\Library\StringHelper as RL_String; use RegularLabs\Library\Version; class HeaderField extends RL_FormField { protected function getInput() { $title = $this->get('label'); $jversion = Version::getMajorJoomlaVersion(); if ($jversion != 4) { JFactory::getApplication()->enqueueMessage(JText::sprintf('RL_NOT_COMPATIBLE_WITH_JOOMLA_VERSION', JText::_($title), $jversion), 'error'); return ''; } $description = $this->get('description'); $xml = $this->get('xml'); $url = $this->get('url'); $this->description = ''; if ($description) { $description = RL_String::html_entity_decoder(trim(JText::_($description))); } if ($title) { $title = JText::_($title); } if ($description) { // Replace inline monospace style with rl_code classname $description = str_replace('span style="font-family:monospace;"', 'span class="rl_code"', $description); // 'Break' plugin style tags $description = str_replace(['{', '['], ['<span>{</span>', '<span>[</span>'], $description); // Wrap in paragraph (if not already starting with an html tag) if ($description[0] != '<') { $description = '<p>' . $description . '</p>'; } } if (!$xml && $this->form->getValue('element')) { if ($this->form->getValue('folder')) { $xml = 'plugins/' . $this->form->getValue('folder') . '/' . $this->form->getValue('element') . '/' . $this->form->getValue('element') . '.xml'; } else { $xml = 'administrator/modules/' . $this->form->getValue('element') . '/' . $this->form->getValue('element') . '.xml'; } } if ($xml) { $xml = JInstaller::parseXMLInstallFile(JPATH_SITE . '/' . $xml); $version = 0; if ($xml && isset($xml['version'])) { $version = $xml['version']; } if ($version) { if (str_contains($version, 'PRO')) { $version = str_replace('PRO', '', $version); $version .= ' <small style="color:green">[PRO]</small>'; } elseif (str_contains($version, 'FREE')) { $version = str_replace('FREE', '', $version); $version .= ' <small style="color:green">[FREE]</small>'; } if ($title) { $title .= ' v'; } else { $title = JText::_('Version') . ' '; } $title .= $version; } } $html = []; if ($title) { if ($url) { $title = '<a href="' . $url . '" target="_blank" title="' . RL_RegEx::replace('<[^>]*>', '', $title) . '">' . $title . '</a>'; } $html[] = '<h4>' . RL_String::html_entity_decoder($title) . '</h4>'; } if ($description) { $html[] = $description; } if ($url) { $html[] = '<p><a href="' . $url . '" class="btn btn-outline-info" target="_blank" title="' . JText::_('RL_MORE_INFO') . '">' . JText::_('RL_MORE_INFO') . ' >></a></p>'; } return $this->getControlGroupEnd() . implode('', $html) . $this->getControlGroupStart(); } protected function getLabel() { return ''; } } Field/LanguagesField.php 0000604 00000003205 15172746170 0011160 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\HTML\HTMLHelper as JHtml; use RegularLabs\Library\Form\FormField as RL_FormField; class LanguagesField extends RL_FormField { public bool $is_select_list = \true; public function getNamesByIds(array $values, array $attributes): array { $languages = JHtml::_('contentlanguage.existing'); $names = []; foreach ($languages as $language) { if (empty($language->value)) { continue; } if (!in_array($language->value, $values)) { continue; } $names[] = $language->text . ' [' . $language->value . ']'; } return $names; } protected function getOptions() { $languages = JHtml::_('contentlanguage.existing'); $value = $this->get('value', []); if (!is_array($value)) { $value = [$value]; } $options = []; foreach ($languages as $language) { if (empty($language->value)) { continue; } $options[] = (object) ['value' => $language->value, 'text' => $language->text . ' [' . $language->value . ']', 'selected' => in_array($language->value, $value, \true)]; } return $options; } } Field/ComponentsField.php 0000644 00000004265 15172746170 0011412 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Framework. * * @since 3.7.0 */ class ComponentsField extends ListField { /** * The form field type. * * @var string * @since 3.7.0 */ protected $type = 'Components'; /** * Method to get a list of options for a list input. * * @return object[] An array of JHtml options. * * @since 2.5.0 */ protected function getOptions() { $db = $this->getDatabase(); $query = $db->getQuery(true) ->select( [ $db->quoteName('name', 'text'), $db->quoteName('element', 'value'), ] ) ->from($db->quoteName('#__extensions')) ->where( [ $db->quoteName('enabled') . ' >= 1', $db->quoteName('type') . ' = ' . $db->quote('component'), ] ); $items = $db->setQuery($query)->loadObjectList(); if ($items) { $lang = Factory::getLanguage(); foreach ($items as &$item) { // Load language $extension = $item->value; $lang->load("$extension.sys", JPATH_ADMINISTRATOR) || $lang->load("$extension.sys", JPATH_ADMINISTRATOR . '/components/' . $extension); // Translate component name $item->text = Text::_($item->text); } // Sort by component name $items = ArrayHelper::sortObjects($items, 'text', 1, true, true); } // Merge any additional options in the XML definition. $options = array_merge(parent::getOptions(), $items); return $options; } } Field/ContentCategoriesField.php 0000604 00000004037 15172746170 0012676 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use RegularLabs\Library\ArrayHelper as RL_Array; use RegularLabs\Library\DB as RL_DB; use RegularLabs\Library\Form\Form as RL_Form; use RegularLabs\Library\Form\FormField as RL_FormField; class ContentCategoriesField extends RL_FormField { public bool $is_select_list = \true; public bool $use_ajax = \true; public bool $use_tree_select = \true; public function getNamesByIds(array $values, array $attributes): array { $query = $this->db->getQuery(\true)->select('c.id, c.title as name, c.published, c.language')->from('#__categories AS c')->where('c.extension = ' . $this->db->quote('com_content'))->where(RL_DB::is('c.id', $values))->order('c.lft'); $this->db->setQuery($query); $categories = $this->db->loadObjectList(); return RL_Form::getNamesWithExtras($categories, ['language', 'unpublished']); } protected function getOptions() { if ($this->max_list_count) { $query = $this->db->getQuery(\true)->select('COUNT(*)')->from('#__categories as c')->where('c.extension = ' . $this->db->quote('com_content'))->where('c.parent_id > 0')->where('c.published > -1'); $this->db->setQuery($query); $total = $this->db->loadResult(); if ($total > $this->max_list_count) { return -1; } } $this->value = RL_Array::toArray($this->value); $query->clear('select')->select('c.id, c.title as name, c.published, c.language, c.level')->order('c.lft'); $this->db->setQuery($query); $list = $this->db->loadObjectList(); return $this->getOptionsByList($list, ['language', 'unpublished'], -1); } } Field/AjaxField.php 0000604 00000005250 15172746170 0010137 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Language\Text as JText; use RegularLabs\Library\Document as RL_Document; use RegularLabs\Library\Form\FormField as RL_FormField; class AjaxField extends RL_FormField { protected function getInput() { $class = $this->get('class', 'btn btn-success'); if ($this->get('disabled')) { return $this->getButton($class . ' disabled', 'disabled'); } RL_Document::script('regularlabs.admin-form'); RL_Document::script('regularlabs.regular'); RL_Document::script('regularlabs.script'); $query = ''; $url_query = $this->get('url-query'); if ($url_query) { $name_prefix = $this->form->getFormControl() . '\\\\[' . $this->group . '\\\\]'; $id_prefix = $this->form->getFormControl() . '_' . $this->group . '_'; $query_parts = []; $url_query = explode(',', $url_query); foreach ($url_query as $url_query_part) { [$key, $id] = explode(':', $url_query_part); $el_name = 'document.querySelector(`input[name=' . $name_prefix . '\\\\[' . $id . '\\\\]]:checked`)'; $el_id = 'document.querySelector(`#' . $id_prefix . $id . '`)'; $query_parts[] = '`&' . $key . '=`' . ' + encodeURI(' . $el_name . ' ? ' . $el_name . '.value : (' . $el_id . ' ? ' . $el_id . '.value' . ' : ``))'; } $query = '+' . implode('+', $query_parts); } $url = '`' . addslashes($this->get('url')) . '`' . $query; $attributes = 'onclick="RegularLabs.AdminForm.loadAjaxButton(`' . $this->id . '`, ' . $url . ')"'; return $this->getButton($class, $attributes); } private function getButton(string $class = 'btn btn-success', string $attributes_string = ''): string { $icon = $this->get('icon', '') ? 'icon-' . $this->get('icon', '') : ''; $attributes_string = $attributes_string ? ' ' . $attributes_string : ''; return '<button type="button" id="' . $this->id . '" class="' . $class . '"' . ' title="' . JText::_($this->get('description')) . '"' . $attributes_string . '>' . '<span class="' . $icon . '"></span> ' . '<span>' . JText::_($this->get('text', $this->get('label'))) . '</span>' . '</button>' . '<div id="message_' . $this->id . '"></div>'; } } Field/NoteField.php 0000644 00000005334 15172746170 0010170 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Form\FormField; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Supports a one line text field. * * @link https://html.spec.whatwg.org/multipage/input.html#text-(type=text)-state-and-search-state-(type=search) * @since 1.7.0 */ class NoteField extends FormField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Note'; /** * Hide the label when rendering the form field. * * @var boolean * @since 4.0.0 */ protected $hiddenLabel = true; /** * Hide the description when rendering the form field. * * @var boolean * @since 4.0.0 */ protected $hiddenDescription = true; /** * Method to get the field label markup. * * @return string The field label markup. * * @since 1.7.0 */ protected function getLabel() { if (empty($this->element['label']) && empty($this->element['description'])) { return ''; } $html = []; $class = []; if (!empty($this->class)) { $class[] = $this->class; } if ($close = (string) $this->element['close']) { HTMLHelper::_('bootstrap.alert'); $close = $close === 'true' ? 'alert' : $close; $html[] = '<button type="button" class="btn-close" data-bs-dismiss="' . $close . '"></button>'; $class[] = 'alert-dismissible show'; } $class = $class ? ' class="' . implode(' ', $class) . '"' : ''; $title = $this->element['label'] ? (string) $this->element['label'] : ($this->element['title'] ? (string) $this->element['title'] : ''); $heading = $this->element['heading'] ? (string) $this->element['heading'] : 'h4'; $description = (string) $this->element['description']; $html[] = !empty($title) ? '<' . $heading . '>' . Text::_($title) . '</' . $heading . '>' : ''; $html[] = !empty($description) ? Text::_($description) : ''; return '</div><div ' . $class . '>' . implode('', $html); } /** * Method to get the field input markup. * * @return string The field input markup. * * @since 1.7.0 */ protected function getInput() { return ''; } } Field/DependencyField.php 0000604 00000001470 15172746170 0011332 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use RegularLabs\Library\Form\FormField as RL_FormField; class DependencyField extends RL_FormField { protected function getInput() { $file = $this->get('file', ''); $label = $this->get('label', 'the main extension'); \RegularLabs\Library\Form\Field\DependencyFieldHelper::setMessage($file, $label); return ''; } protected function getLabel() { return ''; } } Field/ContentArticlesField.php 0000604 00000005150 15172746170 0012354 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\HTML\HTMLHelper as JHtml; use Joomla\CMS\Language\Text as JText; use RegularLabs\Library\DB as RL_DB; use RegularLabs\Library\Form\Form; use RegularLabs\Library\Form\FormField as RL_FormField; class ContentArticlesField extends RL_FormField { public bool $is_select_list = \true; public bool $use_ajax = \true; public function getNamesByIds(array $values, array $attributes): array { $query = $this->db->getQuery(\true)->from('#__content AS i')->select('i.id, i.title as name, i.language, c.title as category, i.state as published')->join('LEFT', '#__categories AS c ON c.id = i.catid')->where(RL_DB::is('i.id', $values))->order('i.title, i.ordering, i.id'); $this->db->setQuery($query); $articles = $this->db->loadObjectList(); return Form::getNamesWithExtras($articles, ['language', 'category', 'id', 'unpublished']); } protected function getOptions() { if ($this->max_list_count) { $query = $this->db->getQuery(\true)->select('COUNT(*)')->from('#__content AS i')->where('i.access > -1')->where('i.state > -1'); $this->db->setQuery($query); $total = $this->db->loadResult(); if ($total > $this->max_list_count) { return -1; } } $id = 'i.id'; $extras = ['language', 'category', 'id', 'unpublished']; if ($this->get('id_alias_name_as_value', 0)) { $id = 'CONCAT(i.id, "::", i.alias, "::", i.title) AS id'; $extras = ['language', 'category', 'id_number', 'unpublished']; } $query->clear('select')->select($id . ', i.id AS id_number, i.title AS name, i.language, c.title AS category, i.state AS published')->join('LEFT', '#__categories AS c ON c.id = i.catid')->order('i.title, i.ordering, i.id'); $this->db->setQuery($query); $list = $this->db->loadObjectList(); $options = $this->getOptionsByList($list, $extras); if ($this->get('showselect')) { array_unshift($options, JHtml::_('select.option', '-', ' ', 'value', 'text', \true)); array_unshift($options, JHtml::_('select.option', '-', '- ' . JText::_('Select Item') . ' -')); } return $options; } } Field/GeoInformationField.php 0000604 00000003033 15172746170 0012171 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Language\Text as JText; use RegularLabs\Library\Form\FormField as RL_FormField; use RegularLabs\Library\GeoIp\GeoIp as RL_GeoIP; class GeoInformationField extends RL_FormField { protected function getInput() { return ''; } protected function getLabel() { if (!class_exists('RegularLabs\Library\GeoIp\GeoIp')) { return ''; } $ip = ''; $geo = new RL_GeoIP($ip); if (empty($geo)) { return \false; } $geo = $geo->get(); if (empty($geo)) { return \false; } $details = [JText::_('CON_CONTINENT') . ': <strong>' . $geo->continent . '</strong>', JText::_('CON_COUNTRY') . ': <strong>' . $geo->country . '</strong>', JText::_('CON_REGION') . ': <strong>' . implode(', ', $geo->regions) . '</strong>', JText::_('CON_POSTAL_CODE') . ': <strong>' . $geo->postalCode . '</strong>']; $html = '<div class="rl-alert alert alert-info rl-alert-light">' . JText::_('CON_GEO_CURRENT_DETAILS') . '<ul><li>' . implode('</li><li>', $details) . '</li></ul>' . '</div>'; return '</div><div>' . $html; } } Field/AccessLevelsField.php 0000604 00000002444 15172746170 0011632 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use RegularLabs\Library\DB as RL_DB; use RegularLabs\Library\Form\FormField as RL_FormField; class AccessLevelsField extends RL_FormField { static $options; public bool $is_select_list = \true; public function getNamesByIds(array $values, array $attributes): array { $query = $this->db->getQuery(\true)->select('a.title')->from('#__viewlevels AS a')->where(RL_DB::is('a.id', $values))->order('a.ordering ASC'); $this->db->setQuery($query); return $this->db->loadColumn(); } protected function getOptions() { if (!is_null(self::$options)) { return self::$options; } $query = $this->db->getQuery(\true)->select('a.id as value, a.title as text')->from('#__viewlevels AS a')->order('a.ordering ASC'); $this->db->setQuery($query); self::$options = $this->db->loadObjectList(); return self::$options; } } Field/MiniColorField.php 0000604 00000003242 15172746170 0011146 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use RegularLabs\Library\ArrayHelper as RL_Array; use RegularLabs\Library\Document as RL_Document; use RegularLabs\Library\Form\FormField as RL_FormField; class MiniColorField extends RL_FormField { public function getInput() { $class = trim('rl-mini-colors ' . $this->get('class')); $table = $this->get('table'); $item_id = $this->get('item_id'); $id_column = $this->get('id_column') ?: 'id'; $disabled = $this->get('disabled') ? ' disabled="disabled"' : ''; $colors = $this->get('colors', 'none,#c0c6cf,#000000,#dc2a28,#fb6b14,#ffa813,#eac90a,#18a047,#0f9aa4,#115dda,#761bda,#d319a4'); $colors = str_replace('none', 'transparent', $colors); RL_Document::scriptOptions(['swatches' => RL_Array::toArray($colors)], 'minicolors'); RL_Document::script('regularlabs.script'); RL_Document::script('regularlabs.mini-colors'); RL_Document::style('regularlabs.mini-colors'); return '<div class="rl-mini-colors">' . '<input type="text" name="' . $this->name . '" id="' . $this->id . '"' . ' class="' . $class . '" value="' . $this->value . '"' . $disabled . ' data-rl-mini-colors data-table="' . $table . '" data-item_id="' . $item_id . '" data-id_column="' . $id_column . '"' . '>' . '</div>'; } } Field/TemplatesField.php 0000604 00000010066 15172746170 0011213 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\HTML\HTMLHelper as JHtml; use Joomla\CMS\Language\Text as JText; use RegularLabs\Library\DB as RL_DB; use RegularLabs\Library\Form\FormField as RL_FormField; class TemplatesField extends RL_FormField { public bool $collapse_children = \true; public bool $is_select_list = \true; public bool $use_ajax = \true; public bool $use_tree_select = \true; public function getNamesByIds(array $values, array $attributes): array { if (empty($values)) { return []; } $query = $this->db->getQuery(\true)->select('e.name, e.element as template')->from('#__extensions as e')->where('e.enabled=1')->where($this->db->quoteName('e.type') . '=' . $this->db->quote('template'))->where(RL_DB::is('e.name', $values))->order('e.name'); $this->db->setQuery($query); $templates = $this->db->loadObjectList(); $query = $this->db->getQuery(\true)->select('s.title, e.name as template_name, s.template')->from('#__template_styles as s')->join('LEFT', '#__extensions as e on e.element = s.template')->where(RL_DB::is('s.client_id', 0))->where(RL_DB::is('e.enabled', 1))->where(RL_DB::is('e.type', 'template'))->where(RL_DB::in('CONCAT(e.name, "--", s.id)', $values, [], \false))->order('s.template')->order('s.title'); $this->db->setQuery($query); $styles = $this->db->loadObjectList(); $lang = $this->app->getLanguage(); $names = []; foreach ($templates as $template) { $lang->load('tpl_' . $template->template . '.sys', JPATH_SITE) || $lang->load('tpl_' . $template->template . '.sys', JPATH_SITE . '/templates/' . $template->template); $names[] = JText::_($template->name); } foreach ($styles as $style) { $lang->load('tpl_' . $style->template . '.sys', JPATH_SITE) || $lang->load('tpl_' . $style->template . '.sys', JPATH_SITE . '/templates/' . $style->template); $names[] = '[' . JText::_($style->template_name) . '] ' . JText::_($style->title); } return $names; } protected function getOptions() { $options = []; $templates = $this->getTemplates(); foreach ($templates as $styles) { $level = 0; foreach ($styles as $style) { $style->level = $level; $options[] = $style; if (count($styles) <= 2) { break; } $level = 1; } } return $options; } protected function getTemplates() { $query = $this->db->getQuery(\true)->select('s.id, s.title, e.name as name, s.template')->from('#__template_styles as s')->where('s.client_id = 0')->join('LEFT', '#__extensions as e on e.element=s.template')->where('e.enabled=1')->where($this->db->quoteName('e.type') . '=' . $this->db->quote('template'))->order('s.template')->order('s.title'); $this->db->setQuery($query); $styles = $this->db->loadObjectList(); if (empty($styles)) { return []; } $lang = $this->app->getLanguage(); $groups = []; foreach ($styles as $style) { $template = $style->template; $lang->load('tpl_' . $template . '.sys', JPATH_SITE) || $lang->load('tpl_' . $template . '.sys', JPATH_SITE . '/templates/' . $template); $name = JText::_($style->name); if (!isset($groups[$template])) { $groups[$template] = []; $groups[$template][] = JHtml::_('select.option', $template, $name); } $groups[$template][] = JHtml::_('select.option', $template . '--' . $style->id, $style->title); } return $groups; } } Field/ImageField.php 0000604 00000002404 15172746170 0010274 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use RegularLabs\Library\Form\FormField as RL_FormField; use RegularLabs\Library\HtmlTag as RL_HtmlTag; class ImageField extends RL_FormField { protected function getInput() { $attributes = ['src' => (string) (string) $this->element['src']]; if ($this->element['alt']) { $attributes['alt'] = (string) $this->element['alt']; } if ($this->element['title']) { $attributes['title'] = (string) $this->element['title']; } if ($this->element['height']) { $attributes['height'] = (string) $this->element['height']; } if ($this->element['width']) { $attributes['width'] = (string) $this->element['width']; } $attributes = RL_HtmlTag::combineAttributes($attributes, (string) $this->element['attributes']); return '<img ' . $attributes . '>'; } } Field/OnlyProField.php 0000604 00000004340 15172746170 0010655 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Language\Text as JText; use RegularLabs\Library\Extension as RL_Extension; use RegularLabs\Library\Form\FormField as RL_FormField; class OnlyProField extends RL_FormField { protected function getExtensionName() { $element = $this->form->getValue('element'); if ($element) { return $element; } $component = $this->app->input->get('component', ''); if ($component) { return str_replace('com_', '', $component); } $folder = $this->app->input->get('folder', ''); if ($folder) { $extension = explode('.', $folder); return array_pop($extension); } $option = $this->app->input->get('option', ''); if ($option) { return str_replace('com_', '', $option); } return \false; } protected function getInput() { $label = $this->prepareText($this->get('label')); $description = $this->prepareText($this->get('description')); if (!$label && !$description) { return ''; } return $this->getText(); } protected function getLabel() { $label = $this->prepareText($this->get('label')); $description = $this->prepareText($this->get('description')); if (!$label && !$description) { return '</div><div>' . $this->getText(); } return parent::getLabel(); } protected function getText() { $text = JText::_('RL_ONLY_AVAILABLE_IN_PRO'); $text = '<em>' . $text . '</em>'; $extension = $this->getExtensionName(); $alias = RL_Extension::getAliasByName($extension); if (!$alias) { return $text; } return '<a href="https://regularlabs.com/' . $extension . '/features" target="_blank">' . $text . '</a>'; } } Field/HeaderLibraryField.php 0000604 00000003405 15172746170 0011771 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Language\Text as JText; class HeaderLibraryField extends \RegularLabs\Library\Form\Field\HeaderField { protected function getInput() { $extensions = [ 'Advanced Module Manager', 'Articles Anywhere', 'Articles Field', 'Better Frontend Link', 'Cache Cleaner', 'CDN for Joomla!', 'Conditional Content', // 'Content Templater', 'DB Replacer', 'GeoIP', 'IP Login', // 'Keyboard Shortcuts', // 'Modals', 'Modules Anywhere', 'Quick Index', 'Regular Labs Extension Manager', 'ReReplacer', 'Snippets', 'Sourcerer', // 'Tabs & Accordions', // 'Tooltips', 'What? Nothing!', ]; $list = '<ul><li>' . implode('</li><li>', $extensions) . '</li></ul>'; $attributes = $this->element->attributes(); $warning = ''; if (isset($attributes['warning'])) { $warning = '<div class="alert alert-danger">' . JText::_($attributes['warning']) . '</div>'; } $this->element->attributes()['description'] = JText::sprintf($attributes['description'], $warning, $list); return parent::getInput(); } } Field/CustomOptionsField.php 0000604 00000002430 15172746170 0012077 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Language\Text as JText; use Joomla\CMS\Layout\FileLayout as JFileLayout; use RegularLabs\Library\ArrayHelper as RL_Array; use RegularLabs\Library\Form\FormField as RL_FormField; class CustomOptionsField extends RL_FormField { protected function getInput() { $data = $this->getLayoutData(); $data['options'] = $this->getOptions(); $data['value'] = RL_Array::toArray($this->value); $data['placeholder'] = JText::_('RL_ENTER_NEW_VALUES'); return (new JFileLayout('regularlabs.form.field.customoptions', JPATH_SITE . '/libraries/regularlabs/layouts'))->render($data); } protected function getOptions() { $values = RL_Array::toArray($this->value); $options = []; foreach ($values as $value) { $options[] = (object) ['value' => $value, 'text' => $value]; } return $options; } } Field/SimpleCategoryField.php 0000604 00000005063 15172746170 0012205 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\HTML\HTMLHelper as JHtml; use Joomla\CMS\Language\Text as JText; use Joomla\CMS\Layout\FileLayout as JFileLayout; use RegularLabs\Library\Form\FormField as RL_FormField; class SimpleCategoryField extends RL_FormField { protected function getInput() { $categories = $this->getOptions(); $options = parent::getOptions(); $options = [...$options, ...$categories]; if ($this->get('show_none', \true)) { $empty_option = JHtml::_('select.option', $this->get('none_value', ''), '- ' . JText::_('JNONE') . ' -'); $empty_option->class = 'hidden'; array_unshift($options, $empty_option); } if ($this->get('show_keep_original')) { $keep_original_option = JHtml::_('select.option', ' ', '- ' . JText::_('RL_KEEP_ORIGINAL_CATEGORY') . ' -'); array_unshift($options, $keep_original_option); } $data = $this->getLayoutData(); $data['options'] = $options; $data['placeholder'] = JText::_($this->get('hint', 'RL_SELECT_OR_CREATE_A_CATEGORY')); $data['allowCustom'] = $this->get('allow_custom', \true); return (new JFileLayout('regularlabs.form.field.simplecategory', JPATH_SITE . '/libraries/regularlabs/layouts'))->render($data); } protected function getOptions() { $table = $this->get('table'); if (!$table) { return []; } // Get the user groups from the database. $query = $this->db->getQuery(\true)->select([$this->db->quoteName('category', 'value'), $this->db->quoteName('category', 'text')])->from($this->db->quoteName('#__' . $table))->where($this->db->quoteName('category') . ' != ' . $this->db->quote(''))->group($this->db->quoteName('category'))->order($this->db->quoteName('category') . ' ASC'); $this->db->setQuery($query); $categories = $this->db->loadObjectList(); foreach ($categories as &$category) { if (!str_contains($category->text, '::')) { continue; } [$text, $icon] = explode('::', $category->text, 2); $category->text = $text; } return $categories; } } Field/SubformField.php 0000644 00000032400 15172746170 0010672 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormField; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * The Field to load the form inside current form * * @Example with all attributes: * <field name="field-name" type="subform" * formsource="path/to/form.xml" min="1" max="3" multiple="true" buttons="add,remove,move" * layout="joomla.form.field.subform.repeatable-table" groupByFieldset="false" component="com_example" client="site" * label="Field Label" description="Field Description" /> * * @since 3.6 */ class SubformField extends FormField { /** * The form field type. * @var string */ protected $type = 'Subform'; /** * Form source * @var string */ protected $formsource; /** * Minimum items in repeat mode * @var integer */ protected $min = 0; /** * Maximum items in repeat mode * @var integer */ protected $max = 1000; /** * Layout to render the form * @var string */ protected $layout = 'joomla.form.field.subform.default'; /** * Whether group subform fields by it`s fieldset * @var boolean */ protected $groupByFieldset = false; /** * Which buttons to show in multiple mode * @var boolean[] $buttons */ protected $buttons = ['add' => true, 'remove' => true, 'move' => true]; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.6 */ public function __get($name) { switch ($name) { case 'formsource': case 'min': case 'max': case 'layout': case 'groupByFieldset': case 'buttons': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.6 */ public function __set($name, $value) { switch ($name) { case 'formsource': $this->formsource = (string) $value; // Add root path if we have a path to XML file if (strrpos($this->formsource, '.xml') === \strlen($this->formsource) - 4) { $this->formsource = Path::clean(JPATH_ROOT . '/' . $this->formsource); } break; case 'min': $this->min = (int) $value; break; case 'max': if ($value) { $this->max = max(1, (int) $value); } break; case 'groupByFieldset': if ($value !== null) { $value = (string) $value; $this->groupByFieldset = !($value === 'false' || $value === 'off' || $value === '0'); } break; case 'layout': $this->layout = (string) $value; // Make sure the layout is not empty. if (!$this->layout) { // Set default value depend from "multiple" mode $this->layout = !$this->multiple ? 'joomla.form.field.subform.default' : 'joomla.form.field.subform.repeatable'; } break; case 'buttons': if (!$this->multiple) { $this->buttons = []; break; } if ($value && !\is_array($value)) { $value = explode(',', (string) $value); $value = array_fill_keys(array_filter($value), true); } if ($value) { $value = array_merge(['add' => false, 'remove' => false, 'move' => false], $value); $this->buttons = $value; } break; case 'value': // We allow a json encoded string or an array if (is_string($value)) { $value = json_decode($value, true); } $this->value = $value !== null ? (array) $value : null; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the <field /> tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. * * @return boolean True on success. * * @since 3.6 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { if (!parent::setup($element, $value, $group)) { return false; } foreach (['formsource', 'min', 'max', 'layout', 'groupByFieldset', 'buttons'] as $attributeName) { $this->__set($attributeName, $element[$attributeName]); } if ((string) $element['fieldname']) { $this->__set('fieldname', $element['fieldname']); } if ($this->value && \is_string($this->value)) { // Guess here is the JSON string from 'default' attribute $this->value = json_decode($this->value, true); } if (!$this->formsource && $element->form) { // Set the formsource parameter from the content of the node $this->formsource = $element->form->saveXML(); } return true; } /** * Method to get the field input markup. * * @return string The field input markup. * * @since 3.6 */ protected function getInput() { // Prepare data for renderer $data = $this->getLayoutData(); $tmpl = null; $control = $this->name; try { $tmpl = $this->loadSubForm(); $forms = $this->loadSubFormData($tmpl); } catch (\Exception $e) { return $e->getMessage(); } $data['tmpl'] = $tmpl; $data['forms'] = $forms; $data['min'] = $this->min; $data['max'] = $this->max; $data['control'] = $control; $data['buttons'] = $this->buttons; $data['fieldname'] = $this->fieldname; $data['fieldId'] = $this->id; $data['groupByFieldset'] = $this->groupByFieldset; /** * For each rendering process of a subform element, we want to have a * separate unique subform id present to could distinguish the eventhandlers * regarding adding/moving/removing rows from nested subforms from their parents. */ static $unique_subform_id = 0; $data['unique_subform_id'] = ('sr-' . ($unique_subform_id++)); // Prepare renderer $renderer = $this->getRenderer($this->layout); // Allow to define some Layout options as attribute of the element if ($this->element['component']) { $renderer->setComponent((string) $this->element['component']); } if ($this->element['client']) { $renderer->setClient((string) $this->element['client']); } // Render $html = $renderer->render($data); // Add hidden input on front of the subform inputs, in multiple mode // for allow to submit an empty value if ($this->multiple) { $html = '<input name="' . $this->name . '" type="hidden" value="">' . $html; } return $html; } /** * Method to get the name used for the field input tag. * * @param string $fieldName The field element name. * * @return string The name to be used for the field input tag. * * @since 3.6 */ protected function getName($fieldName) { $name = ''; // If there is a form control set for the attached form add it first. if ($this->formControl) { $name .= $this->formControl; } // If the field is in a group add the group control to the field name. if ($this->group) { // If we already have a name segment add the group control as another level. $groups = explode('.', $this->group); if ($name) { foreach ($groups as $group) { $name .= '[' . $group . ']'; } } else { $name .= array_shift($groups); foreach ($groups as $group) { $name .= '[' . $group . ']'; } } } // If we already have a name segment add the field name as another level. if ($name) { $name .= '[' . $fieldName . ']'; } else { $name .= $fieldName; } return $name; } /** * Loads the form instance for the subform. * * @return Form The form instance. * * @throws \InvalidArgumentException if no form provided. * @throws \RuntimeException if the form could not be loaded. * * @since 3.9.7 */ public function loadSubForm() { $control = $this->name; if ($this->multiple) { $control .= '[' . $this->fieldname . 'X]'; } // Prepare the form template $formname = 'subform.' . str_replace(['jform[', '[', ']'], ['', '.', ''], $this->name); $tmpl = Form::getInstance($formname, $this->formsource, ['control' => $control]); return $tmpl; } /** * Binds given data to the subform and its elements. * * @param Form $subForm Form instance of the subform. * * @return Form[] Array of Form instances for the rows. * * @since 3.9.7 */ protected function loadSubFormData(Form $subForm) { $value = $this->value ? (array) $this->value : []; // Simple form, just bind the data and return one row. if (!$this->multiple) { $subForm->bind($value); return [$subForm]; } // Multiple rows possible: Construct array and bind values to their respective forms. $forms = []; $value = array_values($value); // Show as many rows as we have values, but at least min and at most max. $c = max($this->min, min(\count($value), $this->max)); for ($i = 0; $i < $c; $i++) { $control = $this->name . '[' . $this->fieldname . $i . ']'; $itemForm = Form::getInstance($subForm->getName() . $i, $this->formsource, ['control' => $control]); if (!empty($value[$i])) { $itemForm->bind($value[$i]); } $forms[] = $itemForm; } return $forms; } /** * Method to filter a field value. * * @param mixed $value The optional value to use as the default for the field. * @param string $group The optional dot-separated form group path on which to find the field. * @param ?Registry $input An optional Registry object with the entire data set to filter * against the entire form. * * @return mixed The filtered value. * * @since 4.0.0 * @throws \UnexpectedValueException */ public function filter($value, $group = null, Registry $input = null) { // Make sure there is a valid SimpleXMLElement. if (!($this->element instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::filter `element` is not an instance of SimpleXMLElement', \get_class($this))); } // Get the field filter type. $filter = (string) $this->element['filter']; if ($filter !== '') { return parent::filter($value, $group, $input); } // Dirty way of ensuring required fields in subforms are submitted and filtered the way other fields are $subForm = $this->loadSubForm(); // Subform field may have a default value, that is a JSON string if ($value && is_string($value)) { $value = json_decode($value, true); // The string is invalid json if (!$value) { return null; } } if ($this->multiple) { $return = []; if ($value) { foreach ($value as $key => $val) { $return[$key] = $subForm->filter($val); } } } else { $return = $subForm->filter($value); } return $return; } } Field/CheckboxesField.php 0000644 00000011022 15172746170 0011330 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Displays options as a list of checkboxes. * Multiselect may be forced to be true. * * @see CheckboxesField * @since 1.7.0 */ class CheckboxesField extends ListField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Checkboxes'; /** * Name of the layout being used to render the field * * @var string * @since 3.5 */ protected $layout = 'joomla.form.field.checkboxes'; /** * Flag to tell the field to always be in multiple values mode. * * @var boolean * @since 1.7.0 */ protected $forceMultiple = true; /** * The comma separated list of checked checkboxes value. * * @var mixed * @since 3.2 */ public $checkedOptions; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'forceMultiple': case 'checkedOptions': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'checkedOptions': $this->checkedOptions = (string) $value; break; default: parent::__set($name, $value); } } /** * Method to get the radio button field input markup. * * @return string The field input markup. * * @since 1.7.0 */ protected function getInput() { if (empty($this->layout)) { throw new \UnexpectedValueException(sprintf('%s has no layout assigned.', $this->name)); } return $this->getRenderer($this->layout)->render($this->getLayoutData()); } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { $this->checkedOptions = (string) $this->element['checked']; } return $return; } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.5 */ protected function getLayoutData() { $data = parent::getLayoutData(); // True if the field has 'value' set. In other words, it has been stored, don't use the default values. $hasValue = (isset($this->value) && !empty($this->value)); // If a value has been stored, use it. Otherwise, use the defaults. $checkedOptions = $hasValue ? $this->value : $this->checkedOptions; $extraData = [ 'checkedOptions' => \is_array($checkedOptions) ? $checkedOptions : explode(',', (string) $checkedOptions), 'hasValue' => $hasValue, 'options' => $this->getOptions(), ]; return array_merge($data, $extraData); } } Field/MenuItemsField.php 0000604 00000007047 15172746170 0011170 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\HTML\HTMLHelper as JHtml; use Joomla\CMS\Language\Multilanguage as JMultilanguage; use Joomla\CMS\Language\Text as JText; use Joomla\Component\Menus\Administrator\Helper\MenusHelper as JMenusHelper; use RegularLabs\Library\Form\FormField as RL_FormField; use RegularLabs\Library\Language as RL_Language; use RegularLabs\Library\RegEx as RL_RegEx; class MenuItemsField extends RL_FormField { public bool $collapse_children = \true; public bool $is_select_list = \true; public bool $use_ajax = \true; public bool $use_tree_select = \true; public function getNamesByIds(array $ids): array { if (empty($ids)) { return []; } RL_Language::load('com_modules', JPATH_ADMINISTRATOR); $menuTypes = JMenusHelper::getMenuLinks(); $items = array_fill_keys($ids, ''); foreach ($menuTypes as $type) { if (isset($items['type.' . $type->menutype])) { $items['type.' . $type->menutype] = $type->title . ' <span class="small">(' . JText::_('JALL') . ')</span>'; } foreach ($type->links as $link) { if (!isset($items[$link->value])) { continue; } $text = []; $text[] = $link->text; $items[$link->value] = implode(' ', $text); } } return $items; } protected function getOptions() { RL_Language::load('com_modules', JPATH_ADMINISTRATOR); $menuTypes = JMenusHelper::getMenuLinks(); $options = []; foreach ($menuTypes as &$type) { $option = (object) ['value' => 'type.' . $type->menutype, 'text' => $type->title, 'level' => 0, 'class' => 'hidechildren', 'labelclass' => 'nav-header']; $options[] = $option; foreach ($type->links as $link) { $check1 = RL_RegEx::replace('[^a-z0-9]', '', strtolower($link->text)); $check2 = RL_RegEx::replace('[^a-z0-9]', '', $link->alias); $text = []; $text[] = $link->text; if ($check1 !== $check2) { $text[] = '<small class="text-muted">[' . $link->alias . ']</small>'; } if (in_array($link->type, ['separator', 'heading', 'alias', 'url'], \true)) { $text[] = '<span class="badge bg-secondary">' . JText::_('COM_MODULES_MENU_ITEM_' . strtoupper($link->type)) . '</span>'; // Don't disable, as you need to be able to select the 'Also on Child Items' option // $link->disable = 1; } if (JMultilanguage::isEnabled() && $link->language != '' && $link->language != '*') { $text[] = $link->language_image ? JHtml::_('image', 'mod_languages/' . $link->language_image . '.gif', $link->language_title, ['title' => $link->language_title], \true) : '<span class="badge bg-secondary" title="' . $link->language_title . '">' . $link->language_sef . '</span>'; } $link->text = implode(' ', $text); $options[] = $link; } } return $options; } } Field/LoadLanguageField.php 0000604 00000002051 15172746170 0011573 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use RegularLabs\Library\Form\FormField as RL_FormField; use RegularLabs\Library\Language as RL_Language; class LoadLanguageField extends RL_FormField { protected function getInput() { $extension = $this->get('extension'); $admin = (bool) $this->get('admin', 1); self::loadLanguage($extension, $admin); return ''; } protected function getLabel() { return ''; } private static function loadLanguage(string $extension, bool $admin = \true): void { if (!$extension) { return; } RL_Language::load($extension, $admin ? JPATH_ADMINISTRATOR : JPATH_SITE); } } Field/RangeField.php 0000644 00000003171 15172746170 0010314 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides a horizontal scroll bar to specify a value in a range. * * @link https://html.spec.whatwg.org/multipage/input.html#range-state-(type=range) * @since 3.2 */ class RangeField extends NumberField { /** * The form field type. * * @var string * @since 3.2 */ protected $type = 'Range'; /** * Name of the layout being used to render the field * * @var string * @since 3.7 */ protected $layout = 'joomla.form.field.range'; /** * Method to get the field input markup. * * @return string The field input markup. * * @since 3.2 */ protected function getInput() { return $this->getRenderer($this->layout)->render($this->getLayoutData()); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.7 */ protected function getLayoutData() { $data = parent::getLayoutData(); // Initialize some field attributes. $extraData = [ 'max' => $this->max, 'min' => $this->min, 'step' => $this->step, ]; return array_merge($data, $extraData); } } Field/IconsField.php 0000604 00000007316 15172746170 0010334 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Language\Text as JText; use RegularLabs\Library\Form\FormField as RL_FormField; class IconsField extends RL_FormField { protected $layout = 'joomla.form.field.radio.buttons'; protected function getInput() { $data = $this->getLayoutData(); return $this->getRenderer($this->layout)->render($data); } protected function getLayoutData() { $data = parent::getLayoutData(); $extraData = ['options' => $this->getOptions(), 'value' => (string) $this->value, 'class' => 'btn-group rl-btn-group rl-btn-group-separate rl-btn-group-min-size']; return [...$data, ...$extraData]; } protected function getOptions() { $classes = ['address-book', 'address-card', 'align-center', 'align-justify', 'align-left', 'align-right', 'angle-double-left', 'angle-double-right', 'angle-down', 'angle-left', 'angle-right', 'angle-up', 'archive', 'arrow-alt-circle-down', 'arrow-alt-circle-left', 'arrow-alt-circle-right', 'arrow-alt-circle-up', 'arrow-down', 'arrow-left', 'arrow-right', 'arrow-up', 'arrows-alt', 'bars', 'bell', 'bolt', 'bookmark', 'briefcase', 'bullhorn', 'calendar-alt', 'calendar-check', 'camera', 'caret-down', 'caret-left', 'caret-right', 'caret-up', 'chart-area', 'chart-bar', 'chart-pie', 'check-square', 'plus-square', 'minus-square', 'check-circle', 'plus-circle', 'minus-circle', 'times-circle', 'play-circle', 'pause-circle', 'stop-circle', 'chevron-circle-left', 'chevron-circle-right', 'backward', 'forward', 'step-backward', 'fast-backward', 'fast-forward', 'square', 'chevron-down', 'chevron-left', 'chevron-right', 'chevron-up', 'circle', 'clipboard', 'clock', 'cloud-download-alt', 'cloud-upload-alt', 'code-branch', 'cogs', 'comment-dots', 'comments', 'compress', 'copy', 'credit-card', 'crop', 'cubes', 'cut', 'database', 'desktop', 'tablet', 'mobile', 'dot-circle', 'download', 'upload', 'edit', 'pen-square', 'pencil-alt', 'ellipsis-h', 'ellipsis-v', 'envelope-open-text', 'exclamation-circle', 'exclamation-triangle', 'info-circle', 'question-circle', 'expand-arrows-alt', 'external-link-alt', 'external-link-square-alt', 'eye-slash', 'fax', 'file-alt', 'filter', 'flag', 'folder-open', 'handshake', 'home', 'image', 'key', 'lock-open', 'unlock-alt', 'language', 'life-ring', 'lightbulb', 'link', 'list-ol', 'list-ul', 'tasks', 'magic', 'compass', 'globe', 'map-marker-alt', 'thumbtack', 'map-signs', 'medkit', 'music', 'paint-brush', 'paperclip', 'phone-square', 'plug', 'power-off', 'print', 'project-diagram', 'puzzle-piece', 'quote-left', 'quote-right', 'random', 'rss-square', 'save', 'search-minus', 'search-plus', 'shield-alt', 'shopping-basket', 'shopping-cart', 'sign-in-alt', 'sign-out-alt', 'sitemap', 'sliders-h', 'smile', 'frown', 'thumbs-down', 'thumbs-up', 'heart', 'star', 'star-half', 'trophy', 'tachometer-alt', 'tags', 'text-width', 'th-large', 'toggle-off', 'toggle-on', 'trash', 'share', 'sync', 'undo', 'universal-access', 'user-circle', 'user-edit', 'user-lock', 'user-tag', 'users-cog', 'video', 'wifi', 'wrench']; $options = []; foreach ($classes as $class) { $options[] = (object) ['value' => $class, 'text' => '<i class="fa fa-' . $class . '"></i>']; } if ($this->get('show_none')) { $options[] = (object) ['value' => '0', 'text' => JText::_('JNONE')]; } return $options; } } Field/LoadMediaField.php 0000604 00000002007 15172746170 0011070 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use RegularLabs\Library\Document as RL_Document; use RegularLabs\Library\Form\FormField as RL_FormField; class LoadMediaField extends RL_FormField { protected function getInput() { return ''; } protected function getLabel() { $filetype = $this->get('filetype'); $file = $this->get('file'); switch ($filetype) { case 'style': RL_Document::style($file); break; case 'script': RL_Document::script($file); break; default: break; } return ''; } } Field/DependencyFieldHelper.php 0000604 00000002261 15172746170 0012471 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Factory as JFactory; use Joomla\CMS\Language\Text as JText; class DependencyFieldHelper { public static function setMessage(string $file, string $name): void { if (empty($file)) { return; } $file = JPATH_SITE . '/' . trim($file, '/'); if (file_exists($file)) { return; } $msg = JText::sprintf('RL_THIS_EXTENSION_NEEDS_THE_MAIN_EXTENSION_TO_FUNCTION', JText::_($name)); $messageQueue = JFactory::getApplication()->getMessageQueue(); foreach ($messageQueue as $queue_message) { if ($queue_message['type'] == 'error' && $queue_message['message'] == $msg) { return; } } JFactory::getApplication()->enqueueMessage($msg, 'error'); } } Field/LicenseField.php 0000604 00000001475 15172746170 0010643 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use RegularLabs\Library\Form\FormField as RL_FormField; use RegularLabs\Library\License as RL_License; class LicenseField extends RL_FormField { protected function getInput() { $extension = $this->get('extension'); if (empty($extension)) { return ''; } return RL_License::getMessage($extension, \true); } protected function getLabel() { return ''; } } Field/GeoField.php 0000604 00000201533 15172746170 0007770 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\HTML\HTMLHelper as JHtml; use RegularLabs\Library\Form\Form as RL_Form; use RegularLabs\Library\Form\FormField as RL_FormField; use RegularLabs\Library\RegEx as RL_RegEx; class GeoField extends RL_FormField { public $attributes = ['group' => 'countries']; public bool $is_select_list = \true; public null|int $max_list_count = 0; private $continents = ['AF' => 'Africa', 'AS' => 'Asia', 'EU' => 'Europe', 'NA' => 'North America', 'SA' => 'South America', 'OC' => 'Oceania', 'AN' => 'Antarctica']; private $countries = ['AF' => "Afghanistan", 'AX' => "Aland Islands", 'AL' => "Albania", 'DZ' => "Algeria", 'AS' => "American Samoa", 'AD' => "Andorra", 'AO' => "Angola", 'AI' => "Anguilla", 'AQ' => "Antarctica", 'AG' => "Antigua and Barbuda", 'AR' => "Argentina", 'AM' => "Armenia", 'AW' => "Aruba", 'AU' => "Australia", 'AT' => "Austria", 'AZ' => "Azerbaijan", 'BS' => "Bahamas", 'BH' => "Bahrain", 'BD' => "Bangladesh", 'BB' => "Barbados", 'BY' => "Belarus", 'BE' => "Belgium", 'BZ' => "Belize", 'BJ' => "Benin", 'BM' => "Bermuda", 'BT' => "Bhutan", 'BO' => "Bolivia", 'BA' => "Bosnia and Herzegovina", 'BW' => "Botswana", 'BV' => "Bouvet Island", 'BR' => "Brazil", 'IO' => "British Indian Ocean Territory", 'BN' => "Brunei Darussalam", 'BG' => "Bulgaria", 'BF' => "Burkina Faso", 'BI' => "Burundi", 'KH' => "Cambodia", 'CM' => "Cameroon", 'CA' => "Canada", 'CV' => "Cape Verde", 'KY' => "Cayman Islands", 'CF' => "Central African Republic", 'TD' => "Chad", 'CL' => "Chile", 'CN' => "China", 'CX' => "Christmas Island", 'CC' => "Cocos (Keeling) Islands", 'CO' => "Colombia", 'KM' => "Comoros", 'CG' => "Congo", 'CD' => "Congo, The Democratic Republic of the", 'CK' => "Cook Islands", 'CR' => "Costa Rica", 'CI' => "Cote d'Ivoire", 'HR' => "Croatia", 'CU' => "Cuba", 'CY' => "Cyprus", 'CZ' => "Czech Republic", 'DK' => "Denmark", 'DJ' => "Djibouti", 'DM' => "Dominica", 'DO' => "Dominican Republic", 'EC' => "Ecuador", 'EG' => "Egypt", 'SV' => "El Salvador", 'GQ' => "Equatorial Guinea", 'ER' => "Eritrea", 'EE' => "Estonia", 'ET' => "Ethiopia", 'FK' => "Falkland Islands (Malvinas)", 'FO' => "Faroe Islands", 'FJ' => "Fiji", 'FI' => "Finland", 'FR' => "France", 'GF' => "French Guiana", 'PF' => "French Polynesia", 'TF' => "French Southern Territories", 'GA' => "Gabon", 'GM' => "Gambia", 'GE' => "Georgia", 'DE' => "Germany", 'GH' => "Ghana", 'GI' => "Gibraltar", 'GR' => "Greece", 'GL' => "Greenland", 'GD' => "Grenada", 'GP' => "Guadeloupe", 'GU' => "Guam", 'GT' => "Guatemala", 'GG' => "Guernsey", 'GN' => "Guinea", 'GW' => "Guinea-Bissau", 'GY' => "Guyana", 'HT' => "Haiti", 'HM' => "Heard Island and McDonald Islands", 'VA' => "Holy See (Vatican City State)", 'HN' => "Honduras", 'HK' => "Hong Kong", 'HU' => "Hungary", 'IS' => "Iceland", 'IN' => "India", 'ID' => "Indonesia", 'IR' => "Iran, Islamic Republic of", 'IQ' => "Iraq", 'IE' => "Ireland", 'IM' => "Isle of Man", 'IL' => "Israel", 'IT' => "Italy", 'JM' => "Jamaica", 'JP' => "Japan", 'JE' => "Jersey", 'JO' => "Jordan", 'KZ' => "Kazakhstan", 'KE' => "Kenya", 'KI' => "Kiribati", 'KP' => "Korea, Democratic People's Republic of", 'KR' => "Korea, Republic of", 'KW' => "Kuwait", 'KG' => "Kyrgyzstan", 'LA' => "Lao People's Democratic Republic", 'LV' => "Latvia", 'LB' => "Lebanon", 'LS' => "Lesotho", 'LR' => "Liberia", 'LY' => "Libyan Arab Jamahiriya", 'LI' => "Liechtenstein", 'LT' => "Lithuania", 'LU' => "Luxembourg", 'MO' => "Macao", 'MK' => "Macedonia", 'MG' => "Madagascar", 'MW' => "Malawi", 'MY' => "Malaysia", 'MV' => "Maldives", 'ML' => "Mali", 'MT' => "Malta", 'MH' => "Marshall Islands", 'MQ' => "Martinique", 'MR' => "Mauritania", 'MU' => "Mauritius", 'YT' => "Mayotte", 'MX' => "Mexico", 'FM' => "Micronesia, Federated States of", 'MD' => "Moldova, Republic of", 'MC' => "Monaco", 'MN' => "Mongolia", 'ME' => "Montenegro", 'MS' => "Montserrat", 'MA' => "Morocco", 'MZ' => "Mozambique", 'MM' => "Myanmar", 'NA' => "Namibia", 'NR' => "Nauru", 'NP' => "Nepal", 'NL' => "Netherlands", 'AN' => "Netherlands Antilles", 'NC' => "New Caledonia", 'NZ' => "New Zealand", 'NI' => "Nicaragua", 'NE' => "Niger", 'NG' => "Nigeria", 'NU' => "Niue", 'NF' => "Norfolk Island", 'MP' => "Northern Mariana Islands", 'NO' => "Norway", 'OM' => "Oman", 'PK' => "Pakistan", 'PW' => "Palau", 'PS' => "Palestinian Territory", 'PA' => "Panama", 'PG' => "Papua New Guinea", 'PY' => "Paraguay", 'PE' => "Peru", 'PH' => "Philippines", 'PN' => "Pitcairn", 'PL' => "Poland", 'PT' => "Portugal", 'PR' => "Puerto Rico", 'QA' => "Qatar", 'RE' => "Reunion", 'RO' => "Romania", 'RU' => "Russian Federation", 'RW' => "Rwanda", 'SH' => "Saint Helena", 'KN' => "Saint Kitts and Nevis", 'LC' => "Saint Lucia", 'PM' => "Saint Pierre and Miquelon", 'VC' => "Saint Vincent and the Grenadines", 'WS' => "Samoa", 'SM' => "San Marino", 'ST' => "Sao Tome and Principe", 'SA' => "Saudi Arabia", 'SN' => "Senegal", 'RS' => "Serbia", 'SC' => "Seychelles", 'SL' => "Sierra Leone", 'SG' => "Singapore", 'SK' => "Slovakia", 'SI' => "Slovenia", 'SB' => "Solomon Islands", 'SO' => "Somalia", 'ZA' => "South Africa", 'GS' => "South Georgia and the South Sandwich Islands", 'ES' => "Spain", 'LK' => "Sri Lanka", 'SD' => "Sudan", 'SR' => "Suriname", 'SJ' => "Svalbard and Jan Mayen", 'SZ' => "Swaziland", 'SE' => "Sweden", 'CH' => "Switzerland", 'SY' => "Syrian Arab Republic", 'TW' => "Taiwan", 'TJ' => "Tajikistan", 'TZ' => "Tanzania, United Republic of", 'TH' => "Thailand", 'TL' => "Timor-Leste", 'TG' => "Togo", 'TK' => "Tokelau", 'TO' => "Tonga", 'TT' => "Trinidad and Tobago", 'TN' => "Tunisia", 'TR' => "Turkey", 'TM' => "Turkmenistan", 'TC' => "Turks and Caicos Islands", 'TV' => "Tuvalu", 'UG' => "Uganda", 'UA' => "Ukraine", 'AE' => "United Arab Emirates", 'GB' => "United Kingdom", 'US' => "United States", 'UM' => "United States Minor Outlying Islands", 'UY' => "Uruguay", 'UZ' => "Uzbekistan", 'VU' => "Vanuatu", 'VE' => "Venezuela", 'VN' => "Vietnam", 'VG' => "Virgin Islands, British", 'VI' => "Virgin Islands, U.S.", 'WF' => "Wallis and Futuna", 'EH' => "Western Sahara", 'YE' => "Yemen", 'ZM' => "Zambia", 'ZW' => "Zimbabwe"]; private $region_countries = ['AU' => "Australia", 'BE' => "Belgium", 'BR' => "Brazil", 'BG' => "Bulgaria", 'CA' => "Canada", 'CN' => "China", 'CY' => "Cyprus", 'CZ' => "Czech Republic", 'DK' => "Denmark", 'EG' => "Egypt", 'FR' => "France", 'DE' => "Germany", 'GR' => "Greece", 'HK' => "Hong Kong", 'HU' => "Hungary", 'IS' => "Iceland", 'IN' => "India", 'ID' => "Indonesia", 'IE' => "Ireland", 'IL' => "Israel", 'IT' => "Italy", 'JP' => "Japan", 'MX' => "Mexico", 'MA' => "Morocco", 'NL' => "Netherlands", 'NG' => "Nigeria", 'NO' => "Norway", 'PH' => "Philippines", 'PL' => "Poland", 'PT' => "Portugal", 'RO' => "Romania", 'RU' => "Russian Federation", 'SK' => "Slovakia", 'SI' => "Slovenia", 'ZA' => "South Africa", 'ES' => "Spain", 'SE' => "Sweden", 'CH' => "Switzerland", 'TW' => "Taiwan", 'TH' => "Thailand", 'TR' => "Turkey", 'UA' => "Ukraine", 'AE' => "United Arab Emirates", 'GB' => "United Kingdom", 'US' => "United States", 'VN' => "Vietnam"]; private $regions = ["Australia" => ['AU-ACT' => "Australian Capital Territory", 'AU-NSW' => "New South Wales", 'AU-NT' => "Northern Territory", 'AU-QLD' => "Queensland", 'AU-SA' => "South Australia", 'AU-TAS' => "Tasmania", 'AU-VIC' => "Victoria", 'AU-WA' => "Western Australia"], "Belgium" => ['BE-VAN' => "Antwerpen", 'BE-WBR' => "Brabant Wallon", 'BE-BRU' => "Brussels-Capital Region", 'BE-WHT' => "Hainaut", 'BE-WLG' => "Liege", 'BE-VLI' => "Limburg", 'BE-WLX' => "Luxembourg, Luxemburg", 'BE-WNA' => "Namur", 'BE-VOV' => "Oost-Vlaanderen", 'BE-VBR' => "Vlaams-Brabant", 'BE-VWV' => "West-Vlaanderen"], "Brazil" => ['BR-AC' => "Acre", 'BR-AL' => "Alagoas", 'BR-AP' => "Amapá", 'BR-AM' => "Amazonas", 'BR-BA' => "Bahia", 'BR-CE' => "Ceará", 'BR-DF' => "Distrito Federal", 'BR-ES' => "Espírito Santo", 'BR-FN' => "Fernando de Noronha", 'BR-GO' => "Goiás", 'BR-MA' => "Maranhão", 'BR-MT' => "Mato Grosso", 'BR-MS' => "Mato Grosso do Sul", 'BR-MG' => "Minas Gerais", 'BR-PR' => "Paraná", 'BR-PB' => "Paraíba", 'BR-PA' => "Pará", 'BR-PE' => "Pernambuco", 'BR-PI' => "Piauí", 'BR-RN' => "Rio Grande do Norte", 'BR-RS' => "Rio Grande do Sul", 'BR-RJ' => "Rio de Janeiro", 'BR-RO' => "Rondônia", 'BR-RR' => "Roraima", 'BR-SC' => "Santa Catarina", 'BR-SE' => "Sergipe", 'BR-SP' => "São Paulo", 'BR-TO' => "Tocantins"], "Bulgaria" => ['BG-01' => "Blagoevgrad", 'BG-02' => "Burgas", 'BG-08' => "Dobrich", 'BG-07' => "Gabrovo", 'BG-26' => "Haskovo", 'BG-09' => "Kardzhali", 'BG-10' => "Kyustendil", 'BG-11' => "Lovech", 'BG-12' => "Montana", 'BG-13' => "Pazardzhik", 'BG-14' => "Pernik", 'BG-15' => "Pleven", 'BG-16' => "Plovdiv", 'BG-17' => "Razgrad", 'BG-18' => "Ruse", 'BG-27' => "Shumen", 'BG-19' => "Silistra", 'BG-20' => "Sliven", 'BG-21' => "Smolyan", 'BG-23' => "Sofia", 'BG-22' => "Sofia-Grad", 'BG-24' => "Stara Zagora", 'BG-25' => "Targovishte", 'BG-03' => "Varna", 'BG-04' => "Veliko Tarnovo", 'BG-05' => "Vidin", 'BG-06' => "Vratsa", 'BG-28' => "Yambol"], "Canada" => ['CA-AB' => "Alberta", 'CA-BC' => "British Columbia", 'CA-MB' => "Manitoba", 'CA-NB' => "New Brunswick", 'CA-NL' => "Newfoundland and Labrador", 'CA-NT' => "Northwest Territories", 'CA-NS' => "Nova Scotia", 'CA-NU' => "Nunavut", 'CA-ON' => "Ontario", 'CA-PE' => "Prince Edward Island", 'CA-QC' => "Quebec", 'CA-SK' => "Saskatchewan", 'CA-YT' => "Yukon Territory"], "China" => ['CN-34' => "Anhui", 'CN-92' => "Aomen (Macau)", 'CN-11' => "Beijing", 'CN-50' => "Chongqing", 'CN-35' => "Fujian", 'CN-62' => "Gansu", 'CN-44' => "Guangdong", 'CN-45' => "Guangxi", 'CN-52' => "Guizhou", 'CN-46' => "Hainan", 'CN-13' => "Hebei", 'CN-23' => "Heilongjiang", 'CN-41' => "Henan", 'CN-42' => "Hubei", 'CN-43' => "Hunan", 'CN-32' => "Jiangsu", 'CN-36' => "Jiangxi", 'CN-22' => "Jilin", 'CN-21' => "Liaoning", 'CN-15' => "Nei Mongol", 'CN-64' => "Ningxia", 'CN-63' => "Qinghai", 'CN-61' => "Shaanxi", 'CN-37' => "Shandong", 'CN-31' => "Shanghai", 'CN-14' => "Shanxi", 'CN-51' => "Sichuan", 'CN-71' => "Taiwan", 'CN-12' => "Tianjin", 'CN-91' => "Xianggang (Hong-Kong)", 'CN-65' => "Xinjiang", 'CN-54' => "Xizang", 'CN-53' => "Yunnan", 'CN-33' => "Zhejiang"], "Cyprus" => ['CY-04' => "Ammóchostos", 'CY-06' => "Kerýneia", 'CY-01' => "Lefkosía", 'CY-02' => "Lemesós", 'CY-03' => "Lárnaka", 'CY-05' => "Páfos"], "Czech Republic" => ['CZ-201' => "Benešov", 'CZ-202' => "Beroun", 'CZ-621' => "Blansko", 'CZ-622' => "Brno-město", 'CZ-623' => "Brno-venkov", 'CZ-801' => "Bruntál", 'CZ-624' => "Břeclav", 'CZ-411' => "Cheb", 'CZ-422' => "Chomutov", 'CZ-531' => "Chrudim", 'CZ-321' => "Domažlice", 'CZ-421' => "Děčín", 'CZ-802' => "Frýdek Místek", 'CZ-611' => "Havlíčkův Brod", 'CZ-625' => "Hodonín", 'CZ-521' => "Hradec Králové", 'CZ-512' => "Jablonec nad Nisou", 'CZ-711' => "Jeseník", 'CZ-612' => "Jihlava", 'CZ-JM' => "Jihomoravský kraj", 'CZ-JC' => "Jihočeský kraj", 'CZ-313' => "Jindřichův Hradec", 'CZ-522' => "Jičín", 'CZ-KA' => "Karlovarský kraj", 'CZ-412' => "Karlovy Vary", 'CZ-803' => "Karviná", 'CZ-203' => "Kladno", 'CZ-322' => "Klatovy", 'CZ-204' => "Kolín", 'CZ-721' => "Kromĕříž", 'CZ-KR' => "Královéhradecký kraj", 'CZ-205' => "Kutná Hora", 'CZ-513' => "Liberec", 'CZ-LI' => "Liberecký kraj", 'CZ-423' => "Litoměřice", 'CZ-424' => "Louny", 'CZ-207' => "Mladá Boleslav", 'CZ-MO' => "Moravskoslezský kraj", 'CZ-425' => "Most", 'CZ-206' => "Mělník", 'CZ-804' => "Nový Jičín", 'CZ-208' => "Nymburk", 'CZ-523' => "Náchod", 'CZ-712' => "Olomouc", 'CZ-OL' => "Olomoucký kraj", 'CZ-805' => "Opava", 'CZ-806' => "Ostrava město", 'CZ-532' => "Pardubice", 'CZ-PA' => "Pardubický kraj", 'CZ-613' => "Pelhřimov", 'CZ-324' => "Plzeň jih", 'CZ-323' => "Plzeň město", 'CZ-325' => "Plzeň sever", 'CZ-PL' => "Plzeňský kraj", 'CZ-315' => "Prachatice", 'CZ-101' => "Praha 1", 'CZ-10A' => "Praha 10", 'CZ-10B' => "Praha 11", 'CZ-10C' => "Praha 12", 'CZ-10D' => "Praha 13", 'CZ-10E' => "Praha 14", 'CZ-10F' => "Praha 15", 'CZ-102' => "Praha 2", 'CZ-103' => "Praha 3", 'CZ-104' => "Praha 4", 'CZ-105' => "Praha 5", 'CZ-106' => "Praha 6", 'CZ-107' => "Praha 7", 'CZ-108' => "Praha 8", 'CZ-109' => "Praha 9", 'CZ-209' => "Praha východ", 'CZ-20A' => "Praha západ", 'CZ-PR' => "Praha, hlavní město", 'CZ-713' => "Prostĕjov", 'CZ-314' => "Písek", 'CZ-714' => "Přerov", 'CZ-20B' => "Příbram", 'CZ-20C' => "Rakovník", 'CZ-326' => "Rokycany", 'CZ-524' => "Rychnov nad Kněžnou", 'CZ-514' => "Semily", 'CZ-413' => "Sokolov", 'CZ-316' => "Strakonice", 'CZ-ST' => "Středočeský kraj", 'CZ-533' => "Svitavy", 'CZ-327' => "Tachov", 'CZ-426' => "Teplice", 'CZ-525' => "Trutnov", 'CZ-317' => "Tábor", 'CZ-614' => "Třebíč", 'CZ-722' => "Uherské Hradištĕ", 'CZ-723' => "Vsetín", 'CZ-VY' => "Vysočina", 'CZ-626' => "Vyškov", 'CZ-724' => "Zlín", 'CZ-ZL' => "Zlínský kraj", 'CZ-627' => "Znojmo", 'CZ-US' => "Ústecký kraj", 'CZ-427' => "Ústí nad Labem", 'CZ-534' => "Ústí nad Orlicí", 'CZ-511' => "Česká Lípa", 'CZ-311' => "České Budějovice", 'CZ-312' => "Český Krumlov", 'CZ-715' => "Šumperk", 'CZ-615' => "Žd’ár nad Sázavou"], "Denmark" => ['DK-84' => "Hovedstaden", 'DK-82' => "Midtjylland", 'DK-81' => "Nordjylland", 'DK-85' => "Sjælland", 'DK-83' => "Syddanmark"], "Egypt" => ['EG-DK' => "Ad Daqahlīyah", 'EG-BA' => "Al Bahr al Ahmar", 'EG-BH' => "Al Buhayrah", 'EG-FYM' => "Al Fayyūm", 'EG-GH' => "Al Gharbīyah", 'EG-ALX' => "Al Iskandarīyah", 'EG-IS' => "Al Ismā`īlīyah", 'EG-GZ' => "Al Jīzah", 'EG-MN' => "Al Minyā", 'EG-MNF' => "Al Minūfīyah", 'EG-KB' => "Al Qalyūbīyah", 'EG-C' => "Al Qāhirah", 'EG-WAD' => "Al Wādī al Jadīd", 'EG-SUZ' => "As Suways", 'EG-SU' => "As Sādis min Uktūbar", 'EG-SHR' => "Ash Sharqīyah", 'EG-ASN' => "Aswān", 'EG-AST' => "Asyūt", 'EG-BNS' => "Banī Suwayf", 'EG-PTS' => "Būr Sa`īd", 'EG-DT' => "Dumyāt", 'EG-JS' => "Janūb Sīnā'", 'EG-KFS' => "Kafr ash Shaykh", 'EG-MT' => "Matrūh", 'EG-KN' => "Qinā", 'EG-SIN' => "Shamal Sīnā'", 'EG-SHG' => "Sūhāj", 'EG-HU' => "Ḩulwān"], "France" => ['FR-01' => "Ain", 'FR-02' => "Aisne", 'FR-03' => "Allier", 'FR-06' => "Alpes-Maritimes", 'FR-04' => "Alpes-de-Haute-Provence", 'FR-A' => "Alsace", 'FR-B' => "Aquitaine", 'FR-08' => "Ardennes", 'FR-07' => "Ardèche", 'FR-09' => "Ariège", 'FR-10' => "Aube", 'FR-11' => "Aude", 'FR-C' => "Auvergne", 'FR-12' => "Aveyron", 'FR-67' => "Bas-Rhin", 'FR-P' => "Basse-Normandie", 'FR-13' => "Bouches-du-Rhône", 'FR-D' => "Bourgogne", 'FR-E' => "Bretagne", 'FR-14' => "Calvados", 'FR-15' => "Cantal", 'FR-F' => "Centre", 'FR-G' => "Champagne-Ardenne", 'FR-16' => "Charente", 'FR-17' => "Charente-Maritime", 'FR-18' => "Cher", 'FR-CP' => "Clipperton", 'FR-19' => "Corrèze", 'FR-H' => "Corse", 'FR-2A' => "Corse-du-Sud", 'FR-23' => "Creuse", 'FR-21' => "Côte-d'Or", 'FR-22' => "Côtes-d'Armor", 'FR-79' => "Deux-Sèvres", 'FR-24' => "Dordogne", 'FR-25' => "Doubs", 'FR-26' => "Drôme", 'FR-91' => "Essonne", 'FR-27' => "Eure", 'FR-28' => "Eure-et-Loir", 'FR-29' => "Finistère", 'FR-I' => "Franche-Comté", 'FR-30' => "Gard", 'FR-32' => "Gers", 'FR-33' => "Gironde", 'FR-GP' => "Guadeloupe", 'FR-GF' => "Guyane", 'FR-68' => "Haut-Rhin", 'FR-2B' => "Haute-Corse", 'FR-31' => "Haute-Garonne", 'FR-43' => "Haute-Loire", 'FR-52' => "Haute-Marne", 'FR-Q' => "Haute-Normandie", 'FR-74' => "Haute-Savoie", 'FR-70' => "Haute-Saône", 'FR-87' => "Haute-Vienne", 'FR-05' => "Hautes-Alpes", 'FR-65' => "Hautes-Pyrénées", 'FR-92' => "Hauts-de-Seine", 'FR-34' => "Hérault", 'FR-35' => "Ille-et-Vilaine", 'FR-36' => "Indre", 'FR-37' => "Indre-et-Loire", 'FR-38' => "Isère", 'FR-39' => "Jura", 'FR-40' => "Landes", 'FR-K' => "Languedoc-Roussillon", 'FR-L' => "Limousin", 'FR-41' => "Loir-et-Cher", 'FR-42' => "Loire", 'FR-44' => "Loire-Atlantique", 'FR-45' => "Loiret", 'FR-M' => "Lorraine", 'FR-46' => "Lot", 'FR-47' => "Lot-et-Garonne", 'FR-48' => "Lozère", 'FR-49' => "Maine-et-Loire", 'FR-50' => "Manche", 'FR-51' => "Marne", 'FR-MQ' => "Martinique", 'FR-53' => "Mayenne", 'FR-YT' => "Mayotte", 'FR-54' => "Meurthe-et-Moselle", 'FR-55' => "Meuse", 'FR-N' => "Midi-Pyrénées", 'FR-56' => "Morbihan", 'FR-57' => "Moselle", 'FR-58' => "Nièvre", 'FR-59' => "Nord", 'FR-O' => "Nord - Pas-de-Calais", 'FR-NC' => "Nouvelle-Calédonie", 'FR-60' => "Oise", 'FR-61' => "Orne", 'FR-75' => "Paris", 'FR-62' => "Pas-de-Calais", 'FR-R' => "Pays de la Loire", 'FR-S' => "Picardie", 'FR-T' => "Poitou-Charentes", 'FR-PF' => "Polynésie française", 'FR-U' => "Provence-Alpes-Côte d'Azur", 'FR-63' => "Puy-de-Dôme", 'FR-64' => "Pyrénées-Atlantiques", 'FR-66' => "Pyrénées-Orientales", 'FR-69' => "Rhône", 'FR-V' => "Rhône-Alpes", 'FR-RE' => "Réunion", 'FR-BL' => "Saint-Barthélemy", 'FR-MF' => "Saint-Martin", 'FR-PM' => "Saint-Pierre-et-Miquelon", 'FR-72' => "Sarthe", 'FR-73' => "Savoie", 'FR-71' => "Saône-et-Loire", 'FR-76' => "Seine-Maritime", 'FR-93' => "Seine-Saint-Denis", 'FR-77' => "Seine-et-Marne", 'FR-80' => "Somme", 'FR-81' => "Tarn", 'FR-82' => "Tarn-et-Garonne", 'FR-TF' => "Terres australes françaises", 'FR-90' => "Territoire de Belfort", 'FR-95' => "Val d'Oise", 'FR-94' => "Val-de-Marne", 'FR-83' => "Var", 'FR-84' => "Vaucluse", 'FR-85' => "Vendée", 'FR-86' => "Vienne", 'FR-88' => "Vosges", 'FR-WF' => "Wallis-et-Futuna", 'FR-89' => "Yonne", 'FR-78' => "Yvelines", 'FR-J' => "Île-de-France"], "Germany" => ['DE-BW' => "Baden-Württemberg", 'DE-BY' => "Bayern", 'DE-BE' => "Berlin", 'DE-BB' => "Brandenburg", 'DE-HB' => "Bremen", 'DE-HH' => "Hamburg", 'DE-HE' => "Hessen", 'DE-MV' => "Mecklenburg-Vorpommern", 'DE-NI' => "Niedersachsen", 'DE-NW' => "Nordrhein-Westfalen", 'DE-RP' => "Rheinland-Pfalz", 'DE-SL' => "Saarland", 'DE-SN' => "Sachsen", 'DE-ST' => "Sachsen-Anhalt", 'DE-SH' => "Schleswig-Holstein", 'DE-TH' => "Thüringen"], "Greece" => ['GR-13' => "Achaïa", 'GR-69' => "Agio Oros", 'GR-01' => "Aitolia kai Akarnania", 'GR-A' => "Anatoliki Makedonia kai Thraki", 'GR-11' => "Argolida", 'GR-12' => "Arkadia", 'GR-31' => "Arta", 'GR-A1' => "Attiki", 'GR-64' => "Chalkidiki", 'GR-94' => "Chania", 'GR-85' => "Chios", 'GR-81' => "Dodekanisos", 'GR-52' => "Drama", 'GR-G' => "Dytiki Ellada", 'GR-C' => "Dytiki Makedonia", 'GR-71' => "Evros", 'GR-05' => "Evrytania", 'GR-04' => "Evvoias", 'GR-63' => "Florina", 'GR-07' => "Fokida", 'GR-06' => "Fthiotida", 'GR-51' => "Grevena", 'GR-14' => "Ileia", 'GR-53' => "Imathia", 'GR-33' => "Ioannina", 'GR-F' => "Ionia Nisia", 'GR-D' => "Ipeiros", 'GR-91' => "Irakleio", 'GR-41' => "Karditsa", 'GR-56' => "Kastoria", 'GR-55' => "Kavala", 'GR-23' => "Kefallonia", 'GR-B' => "Kentriki Makedonia", 'GR-22' => "Kerkyra", 'GR-57' => "Kilkis", 'GR-15' => "Korinthia", 'GR-58' => "Kozani", 'GR-M' => "Kriti", 'GR-82' => "Kyklades", 'GR-16' => "Lakonia", 'GR-42' => "Larisa", 'GR-92' => "Lasithi", 'GR-24' => "Lefkada", 'GR-83' => "Lesvos", 'GR-43' => "Magnisia", 'GR-17' => "Messinia", 'GR-L' => "Notio Aigaio", 'GR-59' => "Pella", 'GR-J' => "Peloponnisos", 'GR-61' => "Pieria", 'GR-34' => "Preveza", 'GR-93' => "Rethymno", 'GR-73' => "Rodopi", 'GR-84' => "Samos", 'GR-62' => "Serres", 'GR-H' => "Sterea Ellada", 'GR-32' => "Thesprotia", 'GR-E' => "Thessalia", 'GR-54' => "Thessaloniki", 'GR-44' => "Trikala", 'GR-03' => "Voiotia", 'GR-K' => "Voreio Aigaio", 'GR-72' => "Xanthi", 'GR-21' => "Zakynthos"], "Hungary" => ['HU-BA' => "Baranya", 'HU-BZ' => "Borsod-Abaúj-Zemplén", 'HU-BU' => "Budapest", 'HU-BK' => "Bács-Kiskun", 'HU-BE' => "Békés", 'HU-BC' => "Békéscsaba", 'HU-CS' => "Csongrád", 'HU-DE' => "Debrecen", 'HU-DU' => "Dunaújváros", 'HU-EG' => "Eger", 'HU-FE' => "Fejér", 'HU-GY' => "Győr", 'HU-GS' => "Győr-Moson-Sopron", 'HU-HB' => "Hajdú-Bihar", 'HU-HE' => "Heves", 'HU-HV' => "Hódmezővásárhely", 'HU-JN' => "Jász-Nagykun-Szolnok", 'HU-KV' => "Kaposvár", 'HU-KM' => "Kecskemét", 'HU-KE' => "Komárom-Esztergom", 'HU-MI' => "Miskolc", 'HU-NK' => "Nagykanizsa", 'HU-NY' => "Nyíregyháza", 'HU-NO' => "Nógrád", 'HU-PE' => "Pest", 'HU-PS' => "Pécs", 'HU-ST' => "Salgótarján", 'HU-SO' => "Somogy", 'HU-SN' => "Sopron", 'HU-SZ' => "Szabolcs-Szatmár-Bereg", 'HU-SD' => "Szeged", 'HU-SS' => "Szekszárd", 'HU-SK' => "Szolnok", 'HU-SH' => "Szombathely", 'HU-SF' => "Székesfehérvár", 'HU-TB' => "Tatabánya", 'HU-TO' => "Tolna", 'HU-VA' => "Vas", 'HU-VM' => "Veszprém", 'HU-VE' => "Veszprém (county)", 'HU-ZA' => "Zala", 'HU-ZE' => "Zalaegerszeg", 'HU-ER' => "Érd"], "Iceland" => ['IS-7' => "Austurland", 'IS-1' => "Höfuðborgarsvæðið", 'IS-6' => "Norðurland eystra", 'IS-5' => "Norðurland vestra", 'IS-0' => "Reykjavík", 'IS-8' => "Suðurland", 'IS-2' => "Suðurnes", 'IS-4' => "Vestfirðir", 'IS-3' => "Vesturland"], "India" => ['IN-AN' => "Andaman and Nicobar Islands", 'IN-AP' => "Andhra Pradesh", 'IN-AR' => "Arunāchal Pradesh", 'IN-AS' => "Assam", 'IN-BR' => "Bihār", 'IN-CH' => "Chandīgarh", 'IN-CT' => "Chhattīsgarh", 'IN-DD' => "Damān and Diu", 'IN-DL' => "Delhi", 'IN-DN' => "Dādra and Nagar Haveli", 'IN-GA' => "Goa", 'IN-GJ' => "Gujarāt", 'IN-HR' => "Haryāna", 'IN-HP' => "Himāchal Pradesh", 'IN-JK' => "Jammu and Kashmīr", 'IN-JH' => "Jharkhand", 'IN-KA' => "Karnātaka", 'IN-KL' => "Kerala", 'IN-LD' => "Lakshadweep", 'IN-MP' => "Madhya Pradesh", 'IN-MH' => "Mahārāshtra", 'IN-MN' => "Manipur", 'IN-ML' => "Meghālaya", 'IN-MZ' => "Mizoram", 'IN-NL' => "Nāgāland", 'IN-OR' => "Orissa", 'IN-PY' => "Pondicherry", 'IN-PB' => "Punjab", 'IN-RJ' => "Rājasthān", 'IN-SK' => "Sikkim", 'IN-TN' => "Tamil Nādu", 'IN-TR' => "Tripura", 'IN-UP' => "Uttar Pradesh", 'IN-UL' => "Uttaranchal", 'IN-WB' => "West Bengal"], "Indonesia" => ['ID-AC' => "Aceh", 'ID-BA' => "Bali", 'ID-BB' => "Bangka Belitung", 'ID-BT' => "Banten", 'ID-BE' => "Bengkulu", 'ID-GO' => "Gorontalo", 'ID-JK' => "Jakarta Raya", 'ID-JA' => "Jambi", 'ID-JW' => "Jawa", 'ID-JB' => "Jawa Barat", 'ID-JT' => "Jawa Tengah", 'ID-JI' => "Jawa Timur", 'ID-KA' => "Kalimantan", 'ID-KB' => "Kalimantan Barat", 'ID-KS' => "Kalimantan Selatan", 'ID-KT' => "Kalimantan Tengah", 'ID-KI' => "Kalimantan Timur", 'ID-KR' => "Kepulauan Riau", 'ID-LA' => "Lampung", 'ID-MA' => "Maluku", 'ID-MU' => "Maluku Utara", 'ID-NU' => "Nusa Tenggara", 'ID-NB' => "Nusa Tenggara Barat", 'ID-NT' => "Nusa Tenggara Timur", 'ID-PA' => "Papua", 'ID-PB' => "Papua Barat", 'ID-RI' => "Riau", 'ID-SL' => "Sulawesi", 'ID-SR' => "Sulawesi Barat", 'ID-SN' => "Sulawesi Selatan", 'ID-ST' => "Sulawesi Tengah", 'ID-SG' => "Sulawesi Tenggara", 'ID-SA' => "Sulawesi Utara", 'ID-SM' => "Sumatera", 'ID-SU' => "Sumatera Utara", 'ID-SB' => "Sumatra Barat", 'ID-SS' => "Sumatra Selatan", 'ID-YO' => "Yogyakarta"], "Ireland" => ['IE-CW' => "Carlow", 'IE-CN' => "Cavan", 'IE-CE' => "Clare", 'IE-C' => "Connacht", 'IE-CO' => "Cork", 'IE-DL' => "Donegal", 'IE-D' => "Dublin", 'IE-G' => "Galway", 'IE-KY' => "Kerry", 'IE-KE' => "Kildare", 'IE-KK' => "Kilkenny", 'IE-LS' => "Laois", 'IE-L' => "Leinster", 'IE-LM' => "Leitrim", 'IE-LK' => "Limerick", 'IE-LD' => "Longford", 'IE-LH' => "Louth", 'IE-MO' => "Mayo", 'IE-MH' => "Meath", 'IE-MN' => "Monaghan", 'IE-M' => "Munster", 'IE-OY' => "Offaly", 'IE-RN' => "Roscommon", 'IE-SO' => "Sligo", 'IE-TA' => "Tipperary", 'IE-U' => "Ulster", 'IE-WD' => "Waterford", 'IE-WH' => "Westmeath", 'IE-WX' => "Wexford", 'IE-WW' => "Wicklow"], "Israel" => ['IL-D' => "HaDarom", 'IL-M' => "HaMerkaz", 'IL-Z' => "HaZafon", 'IL-HA' => "Hefa", 'IL-TA' => "Tel-Aviv", 'IL-JM' => "Yerushalayim Al Quds"], "Italy" => ['IT-65' => "Abruzzo", 'IT-AG' => "Agrigento", 'IT-AL' => "Alessandria", 'IT-AN' => "Ancona", 'IT-AO' => "Aosta", 'IT-AR' => "Arezzo", 'IT-AP' => "Ascoli Piceno", 'IT-AT' => "Asti", 'IT-AV' => "Avellino", 'IT-BA' => "Bari", 'IT-BT' => "Barletta-Andria-Trani", 'IT-77' => "Basilicata", 'IT-BL' => "Belluno", 'IT-BN' => "Benevento", 'IT-BG' => "Bergamo", 'IT-BI' => "Biella", 'IT-BO' => "Bologna", 'IT-BZ' => "Bolzano", 'IT-BS' => "Brescia", 'IT-BR' => "Brindisi", 'IT-CA' => "Cagliari", 'IT-78' => "Calabria", 'IT-CL' => "Caltanissetta", 'IT-72' => "Campania", 'IT-CB' => "Campobasso", 'IT-CI' => "Carbonia-Iglesias", 'IT-CE' => "Caserta", 'IT-CT' => "Catania", 'IT-CZ' => "Catanzaro", 'IT-CH' => "Chieti", 'IT-CO' => "Como", 'IT-CS' => "Cosenza", 'IT-CR' => "Cremona", 'IT-KR' => "Crotone", 'IT-CN' => "Cuneo", 'IT-45' => "Emilia-Romagna", 'IT-EN' => "Enna", 'IT-FM' => "Fermo", 'IT-FE' => "Ferrara", 'IT-FI' => "Firenze", 'IT-FG' => "Foggia", 'IT-FC' => "Forlì-Cesena", 'IT-36' => "Friuli-Venezia Giulia", 'IT-FR' => "Frosinone", 'IT-GE' => "Genova", 'IT-GO' => "Gorizia", 'IT-GR' => "Grosseto", 'IT-IM' => "Imperia", 'IT-IS' => "Isernia", 'IT-AQ' => "L'Aquila", 'IT-SP' => "La Spezia", 'IT-LT' => "Latina", 'IT-62' => "Lazio", 'IT-LE' => "Lecce", 'IT-LC' => "Lecco", 'IT-42' => "Liguria", 'IT-LI' => "Livorno", 'IT-LO' => "Lodi", 'IT-25' => "Lombardia", 'IT-LU' => "Lucca", 'IT-MC' => "Macerata", 'IT-MN' => "Mantova", 'IT-57' => "Marche", 'IT-MS' => "Massa-Carrara", 'IT-MT' => "Matera", 'IT-VS' => "Medio Campidano", 'IT-ME' => "Messina", 'IT-MI' => "Milano", 'IT-MO' => "Modena", 'IT-67' => "Molise", 'IT-MB' => "Monza e Brianza", 'IT-NA' => "Napoli", 'IT-NO' => "Novara", 'IT-NU' => "Nuoro", 'IT-OG' => "Ogliastra", 'IT-OT' => "Olbia-Tempio", 'IT-OR' => "Oristano", 'IT-PD' => "Padova", 'IT-PA' => "Palermo", 'IT-PR' => "Parma", 'IT-PV' => "Pavia", 'IT-PG' => "Perugia", 'IT-PU' => "Pesaro e Urbino", 'IT-PE' => "Pescara", 'IT-PC' => "Piacenza", 'IT-21' => "Piemonte", 'IT-PI' => "Pisa", 'IT-PT' => "Pistoia", 'IT-PN' => "Pordenone", 'IT-PZ' => "Potenza", 'IT-PO' => "Prato", 'IT-75' => "Puglia", 'IT-RG' => "Ragusa", 'IT-RA' => "Ravenna", 'IT-RC' => "Reggio Calabria", 'IT-RE' => "Reggio Emilia", 'IT-RI' => "Rieti", 'IT-RN' => "Rimini", 'IT-RM' => "Roma", 'IT-RO' => "Rovigo", 'IT-SA' => "Salerno", 'IT-88' => "Sardegna", 'IT-SS' => "Sassari", 'IT-SV' => "Savona", 'IT-82' => "Sicilia", 'IT-SI' => "Siena", 'IT-SR' => "Siracusa", 'IT-SO' => "Sondrio", 'IT-TA' => "Taranto", 'IT-TE' => "Teramo", 'IT-TR' => "Terni", 'IT-TO' => "Torino", 'IT-52' => "Toscana", 'IT-TP' => "Trapani", 'IT-32' => "Trentino-Alto Adige", 'IT-TN' => "Trento", 'IT-TV' => "Treviso", 'IT-TS' => "Trieste", 'IT-UD' => "Udine", 'IT-55' => "Umbria", 'IT-23' => "Valle d'Aosta", 'IT-VA' => "Varese", 'IT-34' => "Veneto", 'IT-VE' => "Venezia", 'IT-VB' => "Verbano-Cusio-Ossola", 'IT-VC' => "Vercelli", 'IT-VR' => "Verona", 'IT-VV' => "Vibo Valentia", 'IT-VI' => "Vicenza", 'IT-VT' => "Viterbo"], "Japan" => ['JP-23' => "Aichi", 'JP-05' => "Akita", 'JP-02' => "Aomori", 'JP-12' => "Chiba", 'JP-38' => "Ehime", 'JP-18' => "Fukui", 'JP-40' => "Fukuoka", 'JP-07' => "Fukushima", 'JP-21' => "Gifu", 'JP-10' => "Gunma", 'JP-34' => "Hiroshima", 'JP-01' => "Hokkaido", 'JP-28' => "Hyogo", 'JP-08' => "Ibaraki", 'JP-17' => "Ishikawa", 'JP-03' => "Iwate", 'JP-37' => "Kagawa", 'JP-46' => "Kagoshima", 'JP-14' => "Kanagawa", 'JP-39' => "Kochi", 'JP-43' => "Kumamoto", 'JP-26' => "Kyoto", 'JP-24' => "Mie", 'JP-04' => "Miyagi", 'JP-45' => "Miyazaki", 'JP-20' => "Nagano", 'JP-42' => "Nagasaki", 'JP-29' => "Nara", 'JP-15' => "Niigata", 'JP-44' => "Oita", 'JP-33' => "Okayama", 'JP-47' => "Okinawa", 'JP-27' => "Osaka", 'JP-41' => "Saga", 'JP-11' => "Saitama", 'JP-25' => "Shiga", 'JP-32' => "Shimane", 'JP-22' => "Shizuoka", 'JP-09' => "Tochigi", 'JP-36' => "Tokushima", 'JP-13' => "Tokyo", 'JP-31' => "Tottori", 'JP-16' => "Toyama", 'JP-30' => "Wakayama", 'JP-06' => "Yamagata", 'JP-35' => "Yamaguchi", 'JP-19' => "Yamanashi"], "Mexico" => ['MX-AGU' => "Aguascalientes", 'MX-BCN' => "Baja California", 'MX-BCS' => "Baja California Sur", 'MX-CAM' => "Campeche", 'MX-CHP' => "Chiapas", 'MX-CHH' => "Chihuahua", 'MX-COA' => "Coahuila", 'MX-COL' => "Colima", 'MX-DIF' => "Distrito Federal (Mexico City)", 'MX-DUR' => "Durango", 'MX-GUA' => "Guanajuato", 'MX-GRO' => "Guerrero", 'MX-HID' => "Hidalgo", 'MX-JAL' => "Jalisco", 'MX-MIC' => "Michoacán", 'MX-MOR' => "Morelos", 'MX-MEX' => "México", 'MX-NAY' => "Nayarit", 'MX-NLE' => "Nuevo León", 'MX-OAX' => "Oaxaca", 'MX-PUE' => "Puebla", 'MX-QUE' => "Querétaro", 'MX-ROO' => "Quintana Roo", 'MX-SLP' => "San Luis Potosí", 'MX-SIN' => "Sinaloa", 'MX-SON' => "Sonora", 'MX-TAB' => "Tabasco", 'MX-TAM' => "Tamaulipas", 'MX-TLA' => "Tlaxcala", 'MX-VER' => "Veracruz", 'MX-YUC' => "Yucatán", 'MX-ZAC' => "Zacatecas"], "Morocco" => ['MA-AGD' => "Agadir-Ida-Outanane", 'MA-HAO' => "Al Haouz", 'MA-HOC' => "Al Hoceïma", 'MA-AOU' => "Aousserd", 'MA-ASZ' => "Assa-Zag", 'MA-AZI' => "Azilal", 'MA-BES' => "Ben Slimane", 'MA-BEM' => "Beni Mellal", 'MA-BER' => "Berkane", 'MA-BOD' => "Boujdour (EH)", 'MA-BOM' => "Boulemane", 'MA-CAS' => "Casablanca [Dar el Beïda]", 'MA-09' => "Chaouia-Ouardigha", 'MA-CHE' => "Chefchaouen", 'MA-CHI' => "Chichaoua", 'MA-CHT' => "Chtouka-Ait Baha", 'MA-10' => "Doukhala-Abda", 'MA-HAJ' => "El Hajeb", 'MA-JDI' => "El Jadida", 'MA-ERR' => "Errachidia", 'MA-ESM' => "Es Smara (EH)", 'MA-ESI' => "Essaouira", 'MA-FAH' => "Fahs-Beni Makada", 'MA-FIG' => "Figuig", 'MA-05' => "Fès-Boulemane", 'MA-FES' => "Fès-Dar-Dbibegh", 'MA-02' => "Gharb-Chrarda-Beni Hssen", 'MA-08' => "Grand Casablanca", 'MA-GUE' => "Guelmim", 'MA-14' => "Guelmim-Es Smara", 'MA-IFR' => "Ifrane", 'MA-INE' => "Inezgane-Ait Melloul", 'MA-JRA' => "Jrada", 'MA-KES' => "Kelaat es Sraghna", 'MA-KHE' => "Khemisaet", 'MA-KHN' => "Khenifra", 'MA-KHO' => "Khouribga", 'MA-KEN' => "Kénitra", 'MA-04' => "L'Oriental", 'MA-LAR' => "Larache", 'MA-LAA' => "Laâyoune (EH)", 'MA-15' => "Laâyoune-Boujdour-Sakia el Hamra", 'MA-MMD' => "Marrakech-Medina", 'MA-MMN' => "Marrakech-Menara", 'MA-11' => "Marrakech-Tensift-Al Haouz", 'MA-MEK' => "Meknès", 'MA-06' => "Meknès-Tafilalet", 'MA-MOH' => "Mohammadia", 'MA-MOU' => "Moulay Yacoub", 'MA-MED' => "Médiouna", 'MA-NAD' => "Nador", 'MA-NOU' => "Nouaceur", 'MA-OUA' => "Ouarzazate", 'MA-OUD' => "Oued ed Dahab (EH)", 'MA-16' => "Oued ed Dahab-Lagouira", 'MA-OUJ' => "Oujda-Angad", 'MA-RAB' => "Rabat", 'MA-07' => "Rabat-Salé-Zemmour-Zaer", 'MA-SAF' => "Safi", 'MA-SAL' => "Salé", 'MA-SEF' => "Sefrou", 'MA-SET' => "Settat", 'MA-SYB' => "Sidi Youssef Ben Ali", 'MA-SIK' => "Sidl Kacem", 'MA-SKH' => "Skhirate-Témara", 'MA-13' => "Sous-Massa-Draa", 'MA-12' => "Tadla-Azilal", 'MA-TNT' => "Tan-Tan", 'MA-TNG' => "Tanger-Assilah", 'MA-01' => "Tanger-Tétouan", 'MA-TAO' => "Taounate", 'MA-TAI' => "Taourirt", 'MA-TAR' => "Taroudant", 'MA-TAT' => "Tata", 'MA-TAZ' => "Taza", 'MA-03' => "Taza-Al Hoceima-Taounate", 'MA-TIZ' => "Tiznit", 'MA-TET' => "Tétouan", 'MA-ZAG' => "Zagora"], "Netherlands" => ['NL-DR' => "Drenthe", 'NL-FL' => "Flevoland", 'NL-FR' => "Friesland", 'NL-GE' => "Gelderland", 'NL-GR' => "Groningen", 'NL-LI' => "Limburg", 'NL-NB' => "Noord-Brabant", 'NL-NH' => "Noord-Holland", 'NL-OV' => "Overijssel", 'NL-UT' => "Utrecht", 'NL-ZE' => "Zeeland", 'NL-ZH' => "Zuid-Holland"], "Nigeria" => ['NG-AB' => "Abia", 'NG-FC' => "Abuja Capital Territory", 'NG-AD' => "Adamawa", 'NG-AK' => "Akwa Ibom", 'NG-AN' => "Anambra", 'NG-BA' => "Bauchi", 'NG-BY' => "Bayelsa", 'NG-BE' => "Benue", 'NG-BO' => "Borno", 'NG-CR' => "Cross River", 'NG-DE' => "Delta", 'NG-EB' => "Ebonyi", 'NG-ED' => "Edo", 'NG-EK' => "Ekiti", 'NG-EN' => "Enugu", 'NG-GO' => "Gombe", 'NG-IM' => "Imo", 'NG-JI' => "Jigawa", 'NG-KD' => "Kaduna", 'NG-KN' => "Kano", 'NG-KT' => "Katsina", 'NG-KE' => "Kebbi", 'NG-KO' => "Kogi", 'NG-KW' => "Kwara", 'NG-LA' => "Lagos", 'NG-NA' => "Nassarawa", 'NG-NI' => "Niger, Níger", 'NG-OG' => "Ogun", 'NG-ON' => "Ondo", 'NG-OS' => "Osun", 'NG-OY' => "Oyo", 'NG-PL' => "Plateau", 'NG-RI' => "Rivers", 'NG-SO' => "Sokoto", 'NG-TA' => "Taraba", 'NG-YO' => "Yobe", 'NG-ZA' => "Zamfara"], "Norway" => ['NO-02' => "Akershus", 'NO-09' => "Aust-Agder", 'NO-06' => "Buskerud", 'NO-20' => "Finnmark", 'NO-04' => "Hedmark", 'NO-12' => "Hordaland", 'NO-22' => "Jan Mayen", 'NO-15' => "Møre og Romsdal", 'NO-17' => "Nord-Trøndelag", 'NO-18' => "Nordland", 'NO-05' => "Oppland", 'NO-03' => "Oslo", 'NO-11' => "Rogaland", 'NO-14' => "Sogn og Fjordane", 'NO-21' => "Svalbard", 'NO-16' => "Sør-Trøndelag", 'NO-08' => "Telemark", 'NO-19' => "Troms", 'NO-10' => "Vest-Agder", 'NO-07' => "Vestfold", 'NO-01' => "Østfold"], "Philippines" => ['PH-ABR' => "Abra", 'PH-AGN' => "Agusan del Norte", 'PH-AGS' => "Agusan del Sur", 'PH-AKL' => "Aklan", 'PH-ALB' => "Albay", 'PH-ANT' => "Antique", 'PH-APA' => "Apayao", 'PH-AUR' => "Aurora", 'PH-14' => "Autonomous Region in Muslim Mindanao (ARMM)", 'PH-BAS' => "Basilan", 'PH-BTN' => "Batanes", 'PH-BTG' => "Batangas", 'PH-BAN' => "Batasn", 'PH-BEN' => "Benguet", 'PH-05' => "Bicol (Region V)", 'PH-BIL' => "Biliran", 'PH-BOH' => "Bohol", 'PH-BUK' => "Bukidnon", 'PH-BUL' => "Bulacan", 'PH-40' => "CALABARZON (Region IV-A)", 'PH-CAG' => "Cagayan", 'PH-02' => "Cagayan Valley (Region II)", 'PH-CAN' => "Camarines Norte", 'PH-CAS' => "Camarines Sur", 'PH-CAM' => "Camiguin", 'PH-CAP' => "Capiz", 'PH-13' => "Caraga (Region XIII)", 'PH-CAT' => "Catanduanes", 'PH-CAV' => "Cavite", 'PH-CEB' => "Cebu", 'PH-03' => "Central Luzon (Region III)", 'PH-07' => "Central Visayas (Region VII)", 'PH-COM' => "Compostela Valley", 'PH-15' => "Cordillera Administrative Region (CAR)", 'PH-11' => "Davao (Region XI)", 'PH-DAO' => "Davao Oriental", 'PH-DAV' => "Davao del Norte", 'PH-DAS' => "Davao del Sur", 'PH-DIN' => "Dinagat Islands", 'PH-EAS' => "Eastern Samar", 'PH-08' => "Eastern Visayas (Region VIII)", 'PH-GUI' => "Guimaras", 'PH-IFU' => "Ifugao", 'PH-01' => "Ilocos (Region I)", 'PH-ILN' => "Ilocos Norte", 'PH-ILS' => "Ilocos Sur", 'PH-ILI' => "Iloilo", 'PH-ISA' => "Isabela", 'PH-KAL' => "Kalinga-Apayso", 'PH-LUN' => "La Union", 'PH-LAG' => "Laguna", 'PH-LAN' => "Lanao del Norte", 'PH-LAS' => "Lanao del Sur", 'PH-LEY' => "Leyte", 'PH-41' => "MIMAROPA (Region IV-B)", 'PH-MAG' => "Maguindanao", 'PH-MAD' => "Marinduque", 'PH-MAS' => "Masbate", 'PH-MDC' => "Mindoro Occidental", 'PH-MDR' => "Mindoro Oriental", 'PH-MSC' => "Misamis Occidental", 'PH-MSR' => "Misamis Oriental", 'PH-MOU' => "Mountain Province", 'PH-00' => "National Capital Region", 'PH-NEC' => "Negroe Occidental", 'PH-NER' => "Negros Oriental", 'PH-NCO' => "North Cotabato", 'PH-10' => "Northern Mindanao (Region X)", 'PH-NSA' => "Northern Samar", 'PH-NUE' => "Nueva Ecija", 'PH-NUV' => "Nueva Vizcaya", 'PH-PLW' => "Palawan", 'PH-PAM' => "Pampanga", 'PH-PAN' => "Pangasinan", 'PH-QUE' => "Quezon", 'PH-QUI' => "Quirino", 'PH-RIZ' => "Rizal", 'PH-ROM' => "Romblon", 'PH-SAR' => "Sarangani", 'PH-SIG' => "Siquijor", 'PH-12' => "Soccsksargen (Region XII)", 'PH-SOR' => "Sorsogon", 'PH-SCO' => "South Cotabato", 'PH-SLE' => "Southern Leyte", 'PH-SUK' => "Sultan Kudarat", 'PH-SLU' => "Sulu", 'PH-SUN' => "Surigao del Norte", 'PH-SUR' => "Surigao del Sur", 'PH-TAR' => "Tarlac", 'PH-TAW' => "Tawi-Tawi", 'PH-WSA' => "Western Samar", 'PH-06' => "Western Visayas (Region VI)", 'PH-ZMB' => "Zambales", 'PH-09' => "Zamboanga Peninsula (Region IX)", 'PH-ZSI' => "Zamboanga Sibugay", 'PH-ZAN' => "Zamboanga del Norte", 'PH-ZAS' => "Zamboanga del Sur"], "Poland" => ['PL-DS' => "Dolnośląskie", 'PL-KP' => "Kujawsko-pomorskie", 'PL-LU' => "Lubelskie", 'PL-LB' => "Lubuskie", 'PL-MZ' => "Mazowieckie", 'PL-MA' => "Małopolskie", 'PL-OP' => "Opolskie", 'PL-PK' => "Podkarpackie", 'PL-PD' => "Podlaskie", 'PL-PM' => "Pomorskie", 'PL-WN' => "Warmińsko-mazurskie", 'PL-WP' => "Wielkopolskie", 'PL-ZP' => "Zachodniopomorskie", 'PL-LD' => "Łódzkie", 'PL-SL' => "Śląskie", 'PL-SK' => "Świętokrzyskie"], "Portugal" => ['PT-01' => "Aveiro", 'PT-02' => "Beja", 'PT-03' => "Braga", 'PT-04' => "Bragança", 'PT-05' => "Castelo Branco", 'PT-06' => "Coimbra", 'PT-08' => "Faro", 'PT-09' => "Guarda", 'PT-10' => "Leiria", 'PT-11' => "Lisboa", 'PT-12' => "Portalegre", 'PT-13' => "Porto", 'PT-30' => "Região Autónoma da Madeira", 'PT-20' => "Região Autónoma dos Açores", 'PT-14' => "Santarém", 'PT-15' => "Setúbal", 'PT-16' => "Viana do Castelo", 'PT-17' => "Vila Real", 'PT-18' => "Viseu", 'PT-07' => "Évora"], "Romania" => ['RO-AB' => "Alba", 'RO-AR' => "Arad", 'RO-AG' => "Argeș", 'RO-BC' => "Bacău", 'RO-BH' => "Bihor", 'RO-BN' => "Bistrița-Năsăud", 'RO-BT' => "Botoșani", 'RO-BV' => "Brașov", 'RO-BR' => "Brăila", 'RO-B' => "București", 'RO-BZ' => "Buzău", 'RO-CS' => "Caraș-Severin", 'RO-CJ' => "Cluj", 'RO-CT' => "Constanța", 'RO-CV' => "Covasna", 'RO-CL' => "Călărași", 'RO-DJ' => "Dolj", 'RO-DB' => "Dâmbovița", 'RO-GL' => "Galați", 'RO-GR' => "Giurgiu", 'RO-GJ' => "Gorj", 'RO-HR' => "Harghita", 'RO-HD' => "Hunedoara", 'RO-IL' => "Ialomița", 'RO-IS' => "Iași", 'RO-IF' => "Ilfov", 'RO-MM' => "Maramureș", 'RO-MH' => "Mehedinți", 'RO-MS' => "Mureș", 'RO-NT' => "Neamț", 'RO-OT' => "Olt", 'RO-PH' => "Prahova", 'RO-SM' => "Satu Mare", 'RO-SB' => "Sibiu", 'RO-SV' => "Suceava", 'RO-SJ' => "Sălaj", 'RO-TR' => "Teleorman", 'RO-TM' => "Timiș", 'RO-TL' => "Tulcea", 'RO-VS' => "Vaslui", 'RO-VN' => "Vrancea", 'RO-VL' => "Vâlcea"], "Russian Federation" => ['RU-AD' => "Adygeya, Respublika", 'RU-AL' => "Altay, Respublika", 'RU-ALT' => "Altayskiy kray", 'RU-AMU' => "Amurskaya oblast'", 'RU-ARK' => "Arkhangel'skaya oblast'", 'RU-AST' => "Astrakhanskaya oblast'", 'RU-BA' => "Bashkortostan, Respublika", 'RU-BEL' => "Belgorodskaya oblast'", 'RU-BRY' => "Bryanskaya oblast'", 'RU-BU' => "Buryatiya, Respublika", 'RU-CE' => "Chechenskaya Respublika", 'RU-CHE' => "Chelyabinskaya oblast'", 'RU-CHU' => "Chukotskiy avtonomnyy okrug", 'RU-CU' => "Chuvashskaya Respublika", 'RU-DA' => "Dagestan, Respublika", 'RU-IRK' => "Irkutiskaya oblast'", 'RU-IVA' => "Ivanovskaya oblast'", 'RU-KB' => "Kabardino-Balkarskaya Respublika", 'RU-KGD' => "Kaliningradskaya oblast'", 'RU-KL' => "Kalmykiya, Respublika", 'RU-KLU' => "Kaluzhskaya oblast'", 'RU-KAM' => "Kamchatskiy kray", 'RU-KC' => "Karachayevo-Cherkesskaya Respublika", 'RU-KR' => "Kareliya, Respublika", 'RU-KEM' => "Kemerovskaya oblast'", 'RU-KHA' => "Khabarovskiy kray", 'RU-KK' => "Khakasiya, Respublika", 'RU-KHM' => "Khanty-Mansiysky avtonomnyy okrug-Yugra", 'RU-KIR' => "Kirovskaya oblast'", 'RU-KO' => "Komi, Respublika", 'RU-KOS' => "Kostromskaya oblast'", 'RU-KDA' => "Krasnodarskiy kray", 'RU-KYA' => "Krasnoyarskiy kray", 'RU-KGN' => "Kurganskaya oblast'", 'RU-KRS' => "Kurskaya oblast'", 'RU-LEN' => "Leningradskaya oblast'", 'RU-LIP' => "Lipetskaya oblast'", 'RU-MAG' => "Magadanskaya oblast'", 'RU-ME' => "Mariy El, Respublika", 'RU-MO' => "Mordoviya, Respublika", 'RU-MOS' => "Moskovskaya oblast'", 'RU-MOW' => "Moskva", 'RU-MUR' => "Murmanskaya oblast'", 'RU-NEN' => "Nenetskiy avtonomnyy okrug", 'RU-NIZ' => "Nizhegorodskaya oblast'", 'RU-NGR' => "Novgorodskaya oblast'", 'RU-NVS' => "Novosibirskaya oblast'", 'RU-OMS' => "Omskaya oblast'", 'RU-ORE' => "Orenburgskaya oblast'", 'RU-ORL' => "Orlovskaya oblast'", 'RU-PNZ' => "Penzenskaya oblast'", 'RU-PER' => "Permskiy kray", 'RU-PRI' => "Primorskiy kray", 'RU-PSK' => "Pskovskaya oblast'", 'RU-IN' => "Respublika Ingushetiya", 'RU-ROS' => "Rostovskaya oblast'", 'RU-RYA' => "Ryazanskaya oblast'", 'RU-SA' => "Sakha, Respublika [Yakutiya]", 'RU-SAK' => "Sakhalinskaya oblast'", 'RU-SAM' => "Samaraskaya oblast'", 'RU-SPE' => "Sankt-Peterburg", 'RU-SAR' => "Saratovskaya oblast'", 'RU-SE' => "Severnaya Osetiya-Alaniya, Respublika", 'RU-SMO' => "Smolenskaya oblast'", 'RU-STA' => "Stavropol'skiy kray", 'RU-SVE' => "Sverdlovskaya oblast'", 'RU-TAM' => "Tambovskaya oblast'", 'RU-TA' => "Tatarstan, Respublika", 'RU-TOM' => "Tomskaya oblast'", 'RU-TUL' => "Tul'skaya oblast'", 'RU-TVE' => "Tverskaya oblast'", 'RU-TYU' => "Tyumenskaya oblast'", 'RU-TY' => "Tyva, Respublika [Tuva]", 'RU-UD' => "Udmurtskaya Respublika", 'RU-ULY' => "Ul'yanovskaya oblast'", 'RU-VLA' => "Vladimirskaya oblast'", 'RU-VGG' => "Volgogradskaya oblast'", 'RU-VLG' => "Vologodskaya oblast'", 'RU-VOR' => "Voronezhskaya oblast'", 'RU-YAN' => "Yamalo-Nenetskiy avtonomnyy okrug", 'RU-YAR' => "Yaroslavskaya oblast'", 'RU-YEV' => "Yevreyskaya avtonomnaya oblast'", 'RU-ZAB' => "Zabajkal'skij kraj"], "Slovakia" => ['SK-BC' => "Banskobystrický kraj", 'SK-BL' => "Bratislavský kraj", 'SK-KI' => "Košický kraj", 'SK-NI' => "Nitriansky kraj", 'SK-PV' => "Prešovský kraj", 'SK-TC' => "Trenčiansky kraj", 'SK-TA' => "Trnavský kraj", 'SK-ZI' => "Žilinský kraj"], "Slovenia" => ['SI-001' => "Ajdovščina", 'SI-195' => "Apače", 'SI-002' => "Beltinci", 'SI-148' => "Benedikt", 'SI-149' => "Bistrica ob Sotli", 'SI-003' => "Bled", 'SI-150' => "Bloke", 'SI-004' => "Bohinj", 'SI-005' => "Borovnica", 'SI-006' => "Bovec", 'SI-151' => "Braslovče", 'SI-007' => "Brda", 'SI-008' => "Brezovica", 'SI-009' => "Brežice", 'SI-152' => "Cankova", 'SI-011' => "Celje", 'SI-012' => "Cerklje na Gorenjskem", 'SI-013' => "Cerknica", 'SI-014' => "Cerkno", 'SI-153' => "Cerkvenjak", 'SI-196' => "Cirkulane", 'SI-018' => "Destrnik", 'SI-019' => "Divača", 'SI-154' => "Dobje", 'SI-020' => "Dobrepolje", 'SI-155' => "Dobrna", 'SI-021' => "Dobrova-Polhov Gradec", 'SI-156' => "Dobrovnik/Dobronak", 'SI-022' => "Dol pri Ljubljani", 'SI-157' => "Dolenjske Toplice", 'SI-023' => "Domžale", 'SI-024' => "Dornava", 'SI-025' => "Dravograd", 'SI-026' => "Duplek", 'SI-027' => "Gorenja vas-Poljane", 'SI-028' => "Gorišnica", 'SI-207' => "Gorje", 'SI-029' => "Gornja Radgona", 'SI-030' => "Gornji Grad", 'SI-031' => "Gornji Petrovci", 'SI-158' => "Grad", 'SI-032' => "Grosuplje", 'SI-159' => "Hajdina", 'SI-161' => "Hodoš/Hodos", 'SI-162' => "Horjul", 'SI-160' => "Hoče-Slivnica", 'SI-034' => "Hrastnik", 'SI-035' => "Hrpelje-Kozina", 'SI-036' => "Idrija", 'SI-037' => "Ig", 'SI-038' => "Ilirska Bistrica", 'SI-039' => "Ivančna Gorica", 'SI-040' => "Izola/Isola", 'SI-041' => "Jesenice", 'SI-163' => "Jezersko", 'SI-042' => "Juršinci", 'SI-043' => "Kamnik", 'SI-044' => "Kanal", 'SI-045' => "Kidričevo", 'SI-046' => "Kobarid", 'SI-047' => "Kobilje", 'SI-049' => "Komen", 'SI-164' => "Komenda", 'SI-050' => "Koper/Capodistria", 'SI-197' => "Kosanjevica na Krki", 'SI-165' => "Kostel", 'SI-051' => "Kozje", 'SI-048' => "Kočevje", 'SI-052' => "Kranj", 'SI-053' => "Kranjska Gora", 'SI-166' => "Križevci", 'SI-054' => "Krško", 'SI-055' => "Kungota", 'SI-056' => "Kuzma", 'SI-057' => "Laško", 'SI-058' => "Lenart", 'SI-059' => "Lendava/Lendva", 'SI-060' => "Litija", 'SI-061' => "Ljubljana", 'SI-062' => "Ljubno", 'SI-063' => "Ljutomer", 'SI-208' => "Log-Dragomer", 'SI-064' => "Logatec", 'SI-167' => "Lovrenc na Pohorju", 'SI-065' => "Loška dolina", 'SI-066' => "Loški Potok", 'SI-068' => "Lukovica", 'SI-067' => "Luče", 'SI-069' => "Majšperk", 'SI-198' => "Makole", 'SI-070' => "Maribor", 'SI-168' => "Markovci", 'SI-071' => "Medvode", 'SI-072' => "Mengeš", 'SI-073' => "Metlika", 'SI-074' => "Mežica", 'SI-169' => "Miklavž na Dravskem polju", 'SI-075' => "Miren-Kostanjevica", 'SI-170' => "Mirna Peč", 'SI-076' => "Mislinja", 'SI-199' => "Mokronog-Trebelno", 'SI-078' => "Moravske Toplice", 'SI-077' => "Moravče", 'SI-079' => "Mozirje", 'SI-080' => "Murska Sobota", 'SI-081' => "Muta", 'SI-082' => "Naklo", 'SI-083' => "Nazarje", 'SI-084' => "Nova Gorica", 'SI-085' => "Novo mesto", 'SI-086' => "Odranci", 'SI-171' => "Oplotnica", 'SI-087' => "Ormož", 'SI-088' => "Osilnica", 'SI-089' => "Pesnica", 'SI-090' => "Piran/Pirano", 'SI-091' => "Pivka", 'SI-172' => "Podlehnik", 'SI-093' => "Podvelka", 'SI-092' => "Podčetrtek", 'SI-200' => "Poljčane", 'SI-173' => "Polzela", 'SI-094' => "Postojna", 'SI-174' => "Prebold", 'SI-095' => "Preddvor", 'SI-175' => "Prevalje", 'SI-096' => "Ptuj", 'SI-097' => "Puconci", 'SI-100' => "Radenci", 'SI-099' => "Radeče", 'SI-101' => "Radlje ob Dravi", 'SI-102' => "Radovljica", 'SI-103' => "Ravne na Koroškem", 'SI-176' => "Razkrižje", 'SI-098' => "Rače-Fram", 'SI-201' => "Renče-Vogrsko", 'SI-209' => "Rečica ob Savinji", 'SI-104' => "Ribnica", 'SI-177' => "Ribnica na Pohorju", 'SI-107' => "Rogatec", 'SI-106' => "Rogaška Slatina", 'SI-105' => "Rogašovci", 'SI-108' => "Ruše", 'SI-178' => "Selnica ob Dravi", 'SI-109' => "Semič", 'SI-110' => "Sevnica", 'SI-111' => "Sežana", 'SI-112' => "Slovenj Gradec", 'SI-113' => "Slovenska Bistrica", 'SI-114' => "Slovenske Konjice", 'SI-179' => "Sodražica", 'SI-180' => "Solčava", 'SI-202' => "Središče ob Dravi", 'SI-115' => "Starče", 'SI-203' => "Straža", 'SI-181' => "Sveta Ana", 'SI-182' => "Sveta Andraž v Slovenskih Goricah", 'SI-204' => "Sveta Trojica v Slovenskih Goricah", 'SI-116' => "Sveti Jurij", 'SI-210' => "Sveti Jurij v Slovenskih Goricah", 'SI-205' => "Sveti Tomaž", 'SI-184' => "Tabor", 'SI-010' => "Tišina", 'SI-128' => "Tolmin", 'SI-129' => "Trbovlje", 'SI-130' => "Trebnje", 'SI-185' => "Trnovska vas", 'SI-186' => "Trzin", 'SI-131' => "Tržič", 'SI-132' => "Turnišče", 'SI-133' => "Velenje", 'SI-187' => "Velika Polana", 'SI-134' => "Velike Lašče", 'SI-188' => "Veržej", 'SI-135' => "Videm", 'SI-136' => "Vipava", 'SI-137' => "Vitanje", 'SI-138' => "Vodice", 'SI-139' => "Vojnik", 'SI-189' => "Vransko", 'SI-140' => "Vrhnika", 'SI-141' => "Vuzenica", 'SI-142' => "Zagorje ob Savi", 'SI-143' => "Zavrč", 'SI-144' => "Zreče", 'SI-015' => "Črenšovci", 'SI-016' => "Črna na Koroškem", 'SI-017' => "Črnomelj", 'SI-033' => "Šalovci", 'SI-183' => "Šempeter-Vrtojba", 'SI-118' => "Šentilj", 'SI-119' => "Šentjernej", 'SI-120' => "Šentjur", 'SI-211' => "Šentrupert", 'SI-117' => "Šenčur", 'SI-121' => "Škocjan", 'SI-122' => "Škofja Loka", 'SI-123' => "Škofljica", 'SI-124' => "Šmarje pri Jelšah", 'SI-206' => "Šmarjeske Topliče", 'SI-125' => "Šmartno ob Paki", 'SI-194' => "Šmartno pri Litiji", 'SI-126' => "Šoštanj", 'SI-127' => "Štore", 'SI-190' => "Žalec", 'SI-146' => "Železniki", 'SI-191' => "Žetale", 'SI-147' => "Žiri", 'SI-192' => "Žirovnica", 'SI-193' => "Žužemberk"], "South Africa" => ['ZA-EC' => "Eastern Cape", 'ZA-FS' => "Free State", 'ZA-GT' => "Gauteng", 'ZA-NL' => "Kwazulu-Natal", 'ZA-LP' => "Limpopo", 'ZA-MP' => "Mpumalanga", 'ZA-NW' => "North-West (South Africa)", 'ZA-NC' => "Northern Cape", 'ZA-WC' => "Western Cape"], "Spain" => ['ES-C' => "A Coruña", 'ES-AB' => "Albacete", 'ES-A' => "Alicante", 'ES-AL' => "Almería", 'ES-AN' => "Andalucía", 'ES-AR' => "Aragón", 'ES-O' => "Asturias", 'ES-AS' => "Asturias, Principado de", 'ES-BA' => "Badajoz", 'ES-PM' => "Balears", 'ES-B' => "Barcelona", 'ES-BU' => "Burgos", 'ES-CN' => "Canarias", 'ES-S' => "Cantabria", 'ES-CS' => "Castellón", 'ES-CL' => "Castilla y León", 'ES-CM' => "Castilla-La Mancha", 'ES-CT' => "Catalunya", 'ES-CE' => "Ceuta", 'ES-CR' => "Ciudad Real", 'ES-CU' => "Cuenca", 'ES-CC' => "Cáceres", 'ES-CA' => "Cádiz", 'ES-CO' => "Córdoba", 'ES-EX' => "Extremadura", 'ES-GA' => "Galicia", 'ES-GI' => "Girona", 'ES-GR' => "Granada", 'ES-GU' => "Guadalajara", 'ES-SS' => "Guipúzcoa / Gipuzkoa", 'ES-H' => "Huelva", 'ES-HU' => "Huesca", 'ES-IB' => "Illes Balears", 'ES-J' => "Jaén", 'ES-LO' => "La Rioja", 'ES-GC' => "Las Palmas", 'ES-LE' => "León", 'ES-L' => "Lleida", 'ES-LU' => "Lugo", 'ES-M' => "Madrid", 'ES-MD' => "Madrid, Comunidad de", 'ES-ML' => "Melilla", 'ES-MU' => "Murcia", 'ES-MC' => "Murcia, Región de", 'ES-MA' => "Málaga", 'ES-NA' => "Navarra / Nafarroa", 'ES-NC' => "Navarra, Comunidad Foral de / Nafarroako Foru Komunitatea", 'ES-OR' => "Ourense", 'ES-P' => "Palencia", 'ES-PV' => "País Vasco / Euskal Herria", 'ES-PO' => "Pontevedra", 'ES-SA' => "Salamanca", 'ES-TF' => "Santa Cruz de Tenerife", 'ES-SG' => "Segovia", 'ES-SE' => "Sevilla", 'ES-SO' => "Soria", 'ES-T' => "Tarragona", 'ES-TE' => "Teruel", 'ES-TO' => "Toledo", 'ES-V' => "Valencia / València", 'ES-VC' => "Valenciana, Comunidad / Valenciana, Comunitat", 'ES-VA' => "Valladolid", 'ES-BI' => "Vizcayaa / Bizkaia", 'ES-ZA' => "Zamora", 'ES-Z' => "Zaragoza", 'ES-VI' => "Álava", 'ES-AV' => "Ávila"], "Sweden" => ['SE-K' => "Blekinge län", 'SE-W' => "Dalarnas län", 'SE-I' => "Gotlands län", 'SE-X' => "Gävleborgs län", 'SE-N' => "Hallands län", 'SE-Z' => "Jämtlande län", 'SE-F' => "Jönköpings län", 'SE-H' => "Kalmar län", 'SE-G' => "Kronobergs län", 'SE-BD' => "Norrbottens län", 'SE-M' => "Skåne län", 'SE-AB' => "Stockholms län", 'SE-D' => "Södermanlands län", 'SE-C' => "Uppsala län", 'SE-S' => "Värmlands län", 'SE-AC' => "Västerbottens län", 'SE-Y' => "Västernorrlands län", 'SE-U' => "Västmanlands län", 'SE-O' => "Västra Götalands län", 'SE-T' => "Örebro län", 'SE-E' => "Östergötlands län"], "Switzerland" => ['CH-AG' => "Aargau", 'CH-AR' => "Appenzell Ausserrhoden", 'CH-AI' => "Appenzell Innerrhoden", 'CH-BL' => "Basel-Landschaft", 'CH-BS' => "Basel-Stadt", 'CH-BE' => "Bern", 'CH-FR' => "Fribourg", 'CH-GE' => "Genève", 'CH-GL' => "Glarus", 'CH-GR' => "Graubünden", 'CH-JU' => "Jura", 'CH-LU' => "Luzern", 'CH-NE' => "Neuchâtel", 'CH-NW' => "Nidwalden", 'CH-OW' => "Obwalden", 'CH-SG' => "Sankt Gallen", 'CH-SH' => "Schaffhausen", 'CH-SZ' => "Schwyz", 'CH-SO' => "Solothurn", 'CH-TG' => "Thurgau", 'CH-TI' => "Ticino", 'CH-UR' => "Uri", 'CH-VS' => "Valais", 'CH-VD' => "Vaud", 'CH-ZG' => "Zug", 'CH-ZH' => "Zürich"], "Taiwan" => ['TW-CHA' => "Changhua", 'TW-CYI' => "Chiay City", 'TW-CYQ' => "Chiayi", 'TW-HSQ' => "Hsinchu", 'TW-HSZ' => "Hsinchui City", 'TW-HUA' => "Hualien", 'TW-ILA' => "Ilan", 'TW-KHQ' => "Kaohsiung", 'TW-KHH' => "Kaohsiung City", 'TW-KEE' => "Keelung City", 'TW-MIA' => "Miaoli", 'TW-NAN' => "Nantou", 'TW-PEN' => "Penghu", 'TW-PIF' => "Pingtung", 'TW-TXQ' => "Taichung", 'TW-TXG' => "Taichung City", 'TW-TNQ' => "Tainan", 'TW-TNN' => "Tainan City", 'TW-TPQ' => "Taipei", 'TW-TPE' => "Taipei City", 'TW-TTT' => "Taitung", 'TW-TAO' => "Taoyuan", 'TW-YUN' => "Yunlin"], "Thailand" => ['TH-37' => "Amnat Charoen", 'TH-15' => "Ang Thong", 'TH-31' => "Buri Ram", 'TH-24' => "Chachoengsao", 'TH-18' => "Chai Nat", 'TH-36' => "Chaiyaphum", 'TH-22' => "Chanthaburi", 'TH-50' => "Chiang Mai", 'TH-57' => "Chiang Rai", 'TH-20' => "Chon Buri", 'TH-86' => "Chumphon", 'TH-46' => "Kalasin", 'TH-62' => "Kamphaeng Phet", 'TH-71' => "Kanchanaburi", 'TH-40' => "Khon Kaen", 'TH-81' => "Krabi", 'TH-10' => "Krung Thep Maha Nakhon Bangkok", 'TH-52' => "Lampang", 'TH-51' => "Lamphun", 'TH-42' => "Loei", 'TH-16' => "Lop Buri", 'TH-58' => "Mae Hong Son", 'TH-44' => "Maha Sarakham", 'TH-49' => "Mukdahan", 'TH-26' => "Nakhon Nayok", 'TH-73' => "Nakhon Pathom", 'TH-48' => "Nakhon Phanom", 'TH-30' => "Nakhon Ratchasima", 'TH-60' => "Nakhon Sawan", 'TH-80' => "Nakhon Si Thammarat", 'TH-55' => "Nan", 'TH-96' => "Narathiwat", 'TH-39' => "Nong Bua Lam Phu", 'TH-43' => "Nong Khai", 'TH-12' => "Nonthaburi", 'TH-13' => "Pathum Thani", 'TH-94' => "Pattani", 'TH-82' => "Phangnga", 'TH-93' => "Phatthalung", 'TH-S' => "Phatthaya", 'TH-56' => "Phayao", 'TH-67' => "Phetchabun", 'TH-76' => "Phetchaburi", 'TH-66' => "Phichit", 'TH-65' => "Phitsanulok", 'TH-14' => "Phra Nakhon Si Ayutthaya", 'TH-54' => "Phrae", 'TH-83' => "Phuket", 'TH-25' => "Prachin Buri", 'TH-77' => "Prachuap Khiri Khan", 'TH-85' => "Ranong", 'TH-70' => "Ratchaburi", 'TH-21' => "Rayong", 'TH-45' => "Roi Et", 'TH-27' => "Sa Kaeo", 'TH-47' => "Sakon Nakhon", 'TH-11' => "Samut Prakan", 'TH-74' => "Samut Sakhon", 'TH-75' => "Samut Songkhram", 'TH-19' => "Saraburi", 'TH-91' => "Satun", 'TH-33' => "Si Sa Ket", 'TH-17' => "Sing Buri", 'TH-90' => "Songkhla", 'TH-64' => "Sukhothai", 'TH-72' => "Suphan Buri", 'TH-84' => "Surat Thani", 'TH-32' => "Surin", 'TH-63' => "Tak", 'TH-92' => "Trang", 'TH-23' => "Trat", 'TH-34' => "Ubon Ratchathani", 'TH-41' => "Udon Thani", 'TH-61' => "Uthai Thani", 'TH-53' => "Uttaradit", 'TH-95' => "Yala", 'TH-35' => "Yasothon"], "Turkey" => ['TR-01' => "Adana", 'TR-02' => "Adıyaman", 'TR-03' => "Afyon", 'TR-68' => "Aksaray", 'TR-05' => "Amasya", 'TR-06' => "Ankara", 'TR-07' => "Antalya", 'TR-75' => "Ardahan", 'TR-08' => "Artvin", 'TR-09' => "Aydın", 'TR-04' => "Ağrı", 'TR-10' => "Balıkesir", 'TR-74' => "Bartın", 'TR-72' => "Batman", 'TR-69' => "Bayburt", 'TR-11' => "Bilecik", 'TR-12' => "Bingöl", 'TR-13' => "Bitlis", 'TR-14' => "Bolu", 'TR-15' => "Burdur", 'TR-16' => "Bursa", 'TR-20' => "Denizli", 'TR-21' => "Diyarbakır", 'TR-81' => "Düzce", 'TR-22' => "Edirne", 'TR-23' => "Elazığ", 'TR-24' => "Erzincan", 'TR-25' => "Erzurum", 'TR-26' => "Eskişehir", 'TR-27' => "Gaziantep", 'TR-28' => "Giresun", 'TR-29' => "Gümüşhane", 'TR-30' => "Hakkâri", 'TR-31' => "Hatay", 'TR-32' => "Isparta", 'TR-76' => "Iğdır", 'TR-46' => "Kahramanmaraş", 'TR-78' => "Karabük", 'TR-70' => "Karaman", 'TR-36' => "Kars", 'TR-37' => "Kastamonu", 'TR-38' => "Kayseri", 'TR-79' => "Kilis", 'TR-41' => "Kocaeli", 'TR-42' => "Konya", 'TR-43' => "Kütahya", 'TR-39' => "Kırklareli", 'TR-71' => "Kırıkkale", 'TR-40' => "Kırşehir", 'TR-44' => "Malatya", 'TR-45' => "Manisa", 'TR-47' => "Mardin", 'TR-48' => "Muğla", 'TR-49' => "Muş", 'TR-50' => "Nevşehir", 'TR-51' => "Niğde", 'TR-52' => "Ordu", 'TR-80' => "Osmaniye", 'TR-53' => "Rize", 'TR-54' => "Sakarya", 'TR-55' => "Samsun", 'TR-56' => "Siirt", 'TR-57' => "Sinop", 'TR-58' => "Sivas", 'TR-59' => "Tekirdağ", 'TR-60' => "Tokat", 'TR-61' => "Trabzon", 'TR-62' => "Tunceli", 'TR-64' => "Uşak", 'TR-65' => "Van", 'TR-77' => "Yalova", 'TR-66' => "Yozgat", 'TR-67' => "Zonguldak", 'TR-17' => "Çanakkale", 'TR-18' => "Çankırı", 'TR-19' => "Çorum", 'TR-34' => "İstanbul", 'TR-35' => "İzmir", 'TR-33' => "İçel", 'TR-63' => "Şanlıurfa", 'TR-73' => "Şırnak"], "Ukraine" => ['UA-71' => "Cherkas'ka Oblast'", 'UA-74' => "Chernihivs'ka Oblast'", 'UA-77' => "Chernivets'ka Oblast'", 'UA-12' => "Dnipropetrovs'ka Oblast'", 'UA-14' => "Donets'ka Oblast'", 'UA-26' => "Ivano-Frankivs'ka Oblast'", 'UA-63' => "Kharkivs'ka Oblast'", 'UA-65' => "Khersons'ka Oblast'", 'UA-68' => "Khmel'nyts'ka Oblast'", 'UA-35' => "Kirovohrads'ka Oblast'", 'UA-32' => "Kyïvs'ka Oblast'", 'UA-30' => "Kyïvs'ka mis'ka rada", 'UA-46' => "L'vivs'ka Oblast'", 'UA-09' => "Luhans'ka Oblast'", 'UA-48' => "Mykolaïvs'ka Oblast'", 'UA-51' => "Odes'ka Oblast'", 'UA-53' => "Poltavs'ka Oblast'", 'UA-43' => "Respublika Krym", 'UA-56' => "Rivnens'ka Oblast'", 'UA-40' => "Sevastopol", 'UA-59' => "Sums 'ka Oblast'", 'UA-61' => "Ternopil's'ka Oblast'", 'UA-05' => "Vinnyts'ka Oblast'", 'UA-07' => "Volyns'ka Oblast'", 'UA-21' => "Zakarpats'ka Oblast'", 'UA-23' => "Zaporiz'ka Oblast'", 'UA-18' => "Zhytomyrs'ka Oblast'"], "United Arab Emirates" => ['AE-AJ' => "'Ajmān", 'AE-AZ' => "Abū Ȥaby [Abu Dhabi]", 'AE-FU' => "Al Fujayrah", 'AE-SH' => "Ash Shāriqah", 'AE-DU' => "Dubayy", 'AE-RK' => "Ra’s al Khaymah", 'AE-UQ' => "Umm al Qaywayn"], "United Kingdom" => ['GB-ABE' => "Aberdeen City", 'GB-ABD' => "Aberdeenshire", 'GB-ANS' => "Angus", 'GB-ANT' => "Antrim", 'GB-ARD' => "Ards", 'GB-AGB' => "Argyll and Bute", 'GB-ARM' => "Armagh", 'GB-BLA' => "Ballymena", 'GB-BLY' => "Ballymoney", 'GB-BNB' => "Banbridge", 'GB-BDG' => "Barking and Dagenham", 'GB-BNE' => "Barnet", 'GB-BNS' => "Barnsley", 'GB-BAS' => "Bath and North East Somerset", 'GB-BDF' => "Bedford", 'GB-BFS' => "Belfast", 'GB-BEX' => "Bexley", 'GB-BIR' => "Birmingham", 'GB-BBD' => "Blackburn with Darwen", 'GB-BPL' => "Blackpool", 'GB-BGW' => "Blaenau Gwent", 'GB-BOL' => "Bolton", 'GB-BMH' => "Bournemouth", 'GB-BRC' => "Bracknell Forest", 'GB-BRD' => "Bradford", 'GB-BEN' => "Brent", 'GB-BGE' => "Bridgend (Pen-y-bont ar Ogwr)", 'GB-BNH' => "Brighton and Hove", 'GB-BST' => "Bristol, City of", 'GB-BRY' => "Bromley", 'GB-BKM' => "Buckinghamshire", 'GB-BUR' => "Bury", 'GB-CAY' => "Caerphilly (Caerffili)", 'GB-CLD' => "Calderdale", 'GB-CAM' => "Cambridgeshire", 'GB-CMD' => "Camden", 'GB-CRF' => "Cardiff (Caerdydd)", 'GB-CMN' => "Carmarthenshire (Sir Gaerfyrddin)", 'GB-CKF' => "Carrickfergus", 'GB-CSR' => "Castlereagh", 'GB-CBF' => "Central Bedfordshire", 'GB-CGN' => "Ceredigion (Sir Ceredigion)", 'GB-CHE' => "Cheshire East", 'GB-CHW' => "Cheshire West and Chester", 'GB-CLK' => "Clackmannanshire", 'GB-CLR' => "Coleraine", 'GB-CWY' => "Conwy", 'GB-CKT' => "Cookstown", 'GB-CON' => "Cornwall", 'GB-COV' => "Coventry", 'GB-CGV' => "Craigavon", 'GB-CRY' => "Croydon", 'GB-CMA' => "Cumbria", 'GB-DAL' => "Darlington", 'GB-DEN' => "Denbighshire (Sir Ddinbych)", 'GB-DER' => "Derby", 'GB-DBY' => "Derbyshire", 'GB-DRY' => "Derry", 'GB-DEV' => "Devon", 'GB-DNC' => "Doncaster", 'GB-DOR' => "Dorset", 'GB-DOW' => "Down", 'GB-DUD' => "Dudley", 'GB-DGY' => "Dumfries and Galloway", 'GB-DND' => "Dundee City", 'GB-DGN' => "Dungannon", 'GB-DUR' => "Durham", 'GB-EAL' => "Ealing", 'GB-EAY' => "East Ayrshire", 'GB-EDU' => "East Dunbartonshire", 'GB-ELN' => "East Lothian", 'GB-ERW' => "East Renfrewshire", 'GB-ERY' => "East Riding of Yorkshire", 'GB-ESX' => "East Sussex", 'GB-EDH' => "Edinburgh, City of", 'GB-ELS' => "Eilean Siar", 'GB-ENF' => "Enfield", 'GB-ENG' => "England", 'GB-EAW' => "England and Wales", 'GB-ESS' => "Essex", 'GB-FAL' => "Falkirk", 'GB-FER' => "Fermanagh", 'GB-FIF' => "Fife", 'GB-FLN' => "Flintshire (Sir y Fflint)", 'GB-GAT' => "Gateshead", 'GB-GLG' => "Glasgow City", 'GB-GLS' => "Gloucestershire", 'GB-GBN' => "Great Britain", 'GB-GRE' => "Greenwich", 'GB-GWN' => "Gwynedd", 'GB-HCK' => "Hackney", 'GB-HAL' => "Halton", 'GB-HMF' => "Hammersmith and Fulham", 'GB-HAM' => "Hampshire", 'GB-HRY' => "Haringey", 'GB-HRW' => "Harrow", 'GB-HPL' => "Hartlepool", 'GB-HAV' => "Havering", 'GB-HEF' => "Herefordshire", 'GB-HRT' => "Hertfordshire", 'GB-HLD' => "Highland", 'GB-HIL' => "Hillingdon", 'GB-HNS' => "Hounslow", 'GB-IVC' => "Inverclyde", 'GB-AGY' => "Isle of Anglesey (Sir Ynys Môn)", 'GB-IOW' => "Isle of Wight", 'GB-ISL' => "Islington", 'GB-KEC' => "Kensington and Chelsea", 'GB-KEN' => "Kent", 'GB-KHL' => "Kingston upon Hull", 'GB-KTT' => "Kingston upon Thames", 'GB-KIR' => "Kirklees", 'GB-KWL' => "Knowsley", 'GB-LBH' => "Lambeth", 'GB-LAN' => "Lancashire", 'GB-LRN' => "Larne", 'GB-LDS' => "Leeds", 'GB-LCE' => "Leicester", 'GB-LEC' => "Leicestershire", 'GB-LEW' => "Lewisham", 'GB-LMV' => "Limavady", 'GB-LIN' => "Lincolnshire", 'GB-LSB' => "Lisburn", 'GB-LIV' => "Liverpool", 'GB-LND' => "London, City of", 'GB-LUT' => "Luton", 'GB-MFT' => "Magherafelt", 'GB-MAN' => "Manchester", 'GB-MDW' => "Medway", 'GB-MTY' => "Merthyr Tydfil (Merthyr Tudful)", 'GB-MRT' => "Merton", 'GB-MDB' => "Middlesbrough", 'GB-MLN' => "Midlothian", 'GB-MIK' => "Milton Keynes", 'GB-MON' => "Monmouthshire (Sir Fynwy)", 'GB-MRY' => "Moray", 'GB-MYL' => "Moyle", 'GB-NTL' => "Neath Port Talbot (Castell-nedd Port Talbot)", 'GB-NET' => "Newcastle upon Tyne", 'GB-NWM' => "Newham", 'GB-NWP' => "Newport (Casnewydd)", 'GB-NYM' => "Newry and Mourne", 'GB-NTA' => "Newtownabbey", 'GB-NFK' => "Norfolk", 'GB-NAY' => "North Ayrshire", 'GB-NDN' => "North Down", 'GB-NEL' => "North East Lincolnshire", 'GB-NLK' => "North Lanarkshire", 'GB-NLN' => "North Lincolnshire", 'GB-NSM' => "North Somerset", 'GB-NTY' => "North Tyneside", 'GB-NYK' => "North Yorkshire", 'GB-NTH' => "Northamptonshire", 'GB-NIR' => "Northern Ireland", 'GB-NBL' => "Northumberland", 'GB-NGM' => "Nottingham", 'GB-NTT' => "Nottinghamshire", 'GB-OLD' => "Oldham", 'GB-OMH' => "Omagh", 'GB-ORK' => "Orkney Islands", 'GB-OXF' => "Oxfordshire", 'GB-PEM' => "Pembrokeshire (Sir Benfro)", 'GB-PKN' => "Perth and Kinross", 'GB-PTE' => "Peterborough", 'GB-PLY' => "Plymouth", 'GB-POL' => "Poole", 'GB-POR' => "Portsmouth", 'GB-POW' => "Powys", 'GB-RDG' => "Reading", 'GB-RDB' => "Redbridge", 'GB-RCC' => "Redcar and Cleveland", 'GB-RFW' => "Renfrewshire", 'GB-RCT' => "Rhondda, Cynon, Taff (Rhondda, Cynon, Taf)", 'GB-RIC' => "Richmond upon Thames", 'GB-RCH' => "Rochdale", 'GB-ROT' => "Rotherham", 'GB-RUT' => "Rutland", 'GB-SLF' => "Salford", 'GB-SAW' => "Sandwell", 'GB-SCT' => "Scotland", 'GB-SCB' => "Scottish Borders, The", 'GB-SFT' => "Sefton", 'GB-SHF' => "Sheffield", 'GB-ZET' => "Shetland Islands", 'GB-SHR' => "Shropshire", 'GB-SLG' => "Slough", 'GB-SOL' => "Solihull", 'GB-SOM' => "Somerset", 'GB-SAY' => "South Ayrshire", 'GB-SGC' => "South Gloucestershire", 'GB-SLK' => "South Lanarkshire", 'GB-STY' => "South Tyneside", 'GB-STH' => "Southampton", 'GB-SOS' => "Southend-on-Sea", 'GB-SWK' => "Southwark", 'GB-SHN' => "St. Helens", 'GB-STS' => "Staffordshire", 'GB-STG' => "Stirling", 'GB-SKP' => "Stockport", 'GB-STT' => "Stockton-on-Tees", 'GB-STE' => "Stoke-on-Trent", 'GB-STB' => "Strabane", 'GB-SFK' => "Suffolk", 'GB-SND' => "Sunderland", 'GB-SRY' => "Surrey", 'GB-STN' => "Sutton", 'GB-SWA' => "Swansea (Abertawe)", 'GB-SWD' => "Swindon", 'GB-TAM' => "Tameside", 'GB-TFW' => "Telford and Wrekin", 'GB-THR' => "Thurrock", 'GB-TOB' => "Torbay", 'GB-TOF' => "Torfaen (Tor-faen)", 'GB-TWH' => "Tower Hamlets", 'GB-TRF' => "Trafford", 'GB-UKM' => "United Kingdom", 'GB-VGL' => "Vale of Glamorgan, The (Bro Morgannwg)", 'GB-WKF' => "Wakefield", 'GB-WLS' => "Wales", 'GB-WLL' => "Walsall", 'GB-WFT' => "Waltham Forest", 'GB-WND' => "Wandsworth", 'GB-WRT' => "Warrington", 'GB-WAR' => "Warwickshire", 'GB-WBK' => "West Berkshire", 'GB-WDU' => "West Dunbartonshire", 'GB-WLN' => "West Lothian", 'GB-WSX' => "West Sussex", 'GB-WSM' => "Westminster", 'GB-WGN' => "Wigan", 'GB-WNM' => "Windsor and Maidenhead", 'GB-WRL' => "Wirral", 'GB-WOK' => "Wokingham", 'GB-WLV' => "Wolverhampton", 'GB-WOR' => "Worcestershire", 'GB-WRX' => "Wrexham (Wrecsam)", 'GB-YOR' => "York"], "United States" => ['US-AL' => "Alabama", 'US-AK' => "Alaska", 'US-AS' => "American Samoa, Samoa Americana", 'US-AZ' => "Arizona", 'US-AR' => "Arkansas", 'US-CA' => "California", 'US-CO' => "Colorado", 'US-CT' => "Connecticut", 'US-DE' => "Delaware", 'US-DC' => "District of Columbia, Disricte de Columbia", 'US-FL' => "Florida", 'US-GA' => "Georgia, Geòrgia", 'US-GU' => "Guam", 'US-HI' => "Hawaii", 'US-ID' => "Idaho", 'US-IL' => "Illinois", 'US-IN' => "Indiana", 'US-IA' => "Iowa", 'US-KS' => "Kansas", 'US-KY' => "Kentucky", 'US-LA' => "Louisiana", 'US-ME' => "Maine", 'US-MD' => "Maryland", 'US-MA' => "Massachusetts", 'US-MI' => "Michigan", 'US-MN' => "Minnesota", 'US-MS' => "Mississippi", 'US-MO' => "Missouri", 'US-MT' => "Montana", 'US-NE' => "Nebraska", 'US-NV' => "Nevada", 'US-NH' => "New Hampshire", 'US-NJ' => "New Jersey", 'US-NM' => "New Mexico", 'US-NY' => "New York", 'US-NC' => "North Carolina", 'US-ND' => "North Dakota", 'US-MP' => "Northern Mariana Islands, Illes Marianes del Nord", 'US-OH' => "Ohio", 'US-OK' => "Oklahoma", 'US-OR' => "Oregon", 'US-PA' => "Pennsylvania", 'US-PR' => "Puerto Rico", 'US-RI' => "Rhode Island", 'US-SC' => "South Carolina", 'US-SD' => "South Dakota", 'US-TN' => "Tennessee", 'US-TX' => "Texas", 'US-UM' => "United States Minor Outlying Islands, Illes Perifèriques Menors dels EUA", 'US-UT' => "Utah", 'US-VT' => "Vermont", 'US-VI' => "Virgin Islands, Illes Verge", 'US-VA' => "Virginia", 'US-WA' => "Washington", 'US-WV' => "West Virginia", 'US-WI' => "Wisconsin", 'US-WY' => "Wyoming"], "Vietnam" => ['VN-44' => "An Giang", 'VN-43' => "Bà Rịa - Vũng Tàu", 'VN-57' => "Bình Dương", 'VN-58' => "Bình Phước", 'VN-40' => "Bình Thuận", 'VN-31' => "Bình Định", 'VN-55' => "Bạc Liêu", 'VN-54' => "Bắc Giang", 'VN-53' => "Bắc Kạn", 'VN-56' => "Bắc Ninh", 'VN-50' => "Bến Tre", 'VN-04' => "Cao Bằng", 'VN-59' => "Cà Mau", 'VN-48' => "Cần Thơ", 'VN-30' => "Gia Lai", 'VN-14' => "Hoà Bình", 'VN-03' => "Hà Giang", 'VN-63' => "Hà Nam", 'VN-64' => "Hà Nội, thủ đô", 'VN-15' => "Hà Tây", 'VN-23' => "Hà Tỉnh", 'VN-66' => "Hưng Yên", 'VN-61' => "Hải Duong", 'VN-62' => "Hải Phòng, thành phố", 'VN-73' => "Hậu Giang", 'VN-65' => "Hồ Chí Minh, thành phố [Sài Gòn]", 'VN-34' => "Khánh Hòa", 'VN-47' => "Kiên Giang", 'VN-28' => "Kon Tum", 'VN-01' => "Lai Châu", 'VN-41' => "Long An", 'VN-02' => "Lào Cai", 'VN-35' => "Lâm Đồng", 'VN-09' => "Lạng Sơn", 'VN-67' => "Nam Định", 'VN-22' => "Nghệ An", 'VN-18' => "Ninh Bình", 'VN-36' => "Ninh Thuận", 'VN-68' => "Phú Thọ", 'VN-32' => "Phú Yên", 'VN-24' => "Quảng Bình", 'VN-27' => "Quảng Nam", 'VN-29' => "Quảng Ngãi", 'VN-13' => "Quảng Ninh", 'VN-25' => "Quảng Trị", 'VN-52' => "Sóc Trăng", 'VN-05' => "Sơn La", 'VN-21' => "Thanh Hóa", 'VN-20' => "Thái Bình", 'VN-69' => "Thái Nguyên", 'VN-26' => "Thừa Thiên-Huế", 'VN-46' => "Tiền Giang", 'VN-51' => "Trà Vinh", 'VN-07' => "Tuyên Quang", 'VN-37' => "Tây Ninh", 'VN-49' => "Vĩnh Long", 'VN-70' => "Vĩnh Phúc", 'VN-06' => "Yên Bái", 'VN-71' => "Điện Biên", 'VN-60' => "Đà Nẵng, thành phố", 'VN-33' => "Đắc Lắk", 'VN-72' => "Đắk Nông", 'VN-39' => "Đồng Nai", 'VN-45' => "Đồng Tháp"]]; protected function getInput() { if ($this->get('group') == 'regions') { $this->use_tree_select = \true; } return parent::getInput(); } protected function getListOptions(array $attributes): array|int { $options = []; foreach ($this->{$attributes['group']} as $key => $val) { if (is_array($val)) { $option = self::getOption($key, $key); $option->level = 0; $option->heading = \true; $option->no_checkbox = \true; $options[] = $option; foreach ($val as $sub_key => $sub_val) { $option = self::getOption($sub_key, $sub_val); $option->level = 1; $options[] = $option; } continue; } $option = self::getOption($key, $val); $option->level = 0; $options[] = $option; } return $options; } private static function getOption(string $key, mixed $val): object { if (!$val) { return JHtml::_('select.option', '-', ' ', 'value', 'text', \true); } if ($key[0] == '-') { return JHtml::_('select.option', '-', $val, 'value', 'text', \true); } $val = RL_Form::prepareSelectItem($val); $option = JHtml::_('select.option', $key, $val); return $option; } private function cleanRegions($regions): array { } private function getRegionArray(): void { } private function getRegionArrayByFile(): string { } private function getRegionName($country, $region): string { } } Field/TextAreaField.php 0000604 00000002205 15172746170 0010766 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Form\Field\TextareaField as JTextareaField; use RegularLabs\Library\Document as RL_Document; class TextAreaField extends JTextareaField { protected $layout = 'regularlabs.form.field.textarea'; protected function getLayoutData() { RL_Document::script('regularlabs.textarea'); $data = parent::getLayoutData(); $extraData = ['show_insert_date_name' => (bool) $this->element['show_insert_date_name'] ?? \false, 'add_separator' => (bool) $this->element['add_separator'] ?? \true]; return [...$data, ...$extraData]; } protected function getLayoutPaths() { $paths = parent::getLayoutPaths(); $paths[] = JPATH_LIBRARIES . '/regularlabs/layouts'; return $paths; } } Field/TagsField.php 0000604 00000003065 15172746170 0010154 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use RegularLabs\Library\DB as RL_DB; use RegularLabs\Library\Form\FormField as RL_FormField; class TagsField extends RL_FormField { static $options; public bool $is_select_list = \true; public bool $use_ajax = \true; public bool $use_tree_select = \true; public function getNamesByIds(array $values, array $attributes): array { $query = $this->db->getQuery(\true)->select('a.title')->from('#__tags AS a')->where(RL_DB::is('a.id', $values))->order('a.title'); $this->db->setQuery($query); return $this->db->loadColumn(); } protected function getOptions() { if (!is_null(self::$options)) { return self::$options; } $query = $this->db->getQuery(\true)->select('a.id as value, a.title as text, a.parent_id AS parent')->from('#__tags AS a')->select('COUNT(DISTINCT b.id) - 1 AS level')->join('LEFT', '#__tags AS b ON a.lft > b.lft AND a.rgt < b.rgt')->where('a.alias <> ' . $this->db->quote('root'))->where('a.published IN (0,1)')->group('a.id')->order('a.lft ASC'); $this->db->setQuery($query); self::$options = $this->db->loadObjectList(); return self::$options; } } Field/FieldField.php 0000604 00000005110 15172746170 0010272 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\HTML\HTMLHelper as JHtml; use Joomla\CMS\Language\Text as JText; use RegularLabs\Library\ArrayHelper as RL_Array; use RegularLabs\Library\Cache; use RegularLabs\Library\DB as RL_DB; use RegularLabs\Library\Form\Form; use RegularLabs\Library\Form\FormField as RL_FormField; class FieldField extends RL_FormField { public bool $is_select_list = \true; public function getNameById(string $value, array $attributes): string { return RL_Array::implode($this->getNamesByIds([$value], $attributes)); } public function getNamesByIds(array $values, array $attributes): array { $db = RL_DB::get(); $query = RL_DB::getQuery()->select('DISTINCT a.id, a.type, a.title as name')->from('#__fields AS a')->where('a.state = 1')->where(RL_DB::is('a.id', $values))->order('a.title'); $db->setQuery($query); $fields = $db->loadObjectList(); return Form::getNamesWithExtras($fields, ['type']); } protected function getOptions() { $fields = $this->getFields(); $options = []; $options[] = JHtml::_('select.option', '', '- ' . JText::_('RL_SELECT_FIELD') . ' -'); foreach ($fields as $field) { $key = $field->{$this->get('key', 'id')} ?? $field->id; $options[] = JHtml::_('select.option', $key, $field->title . ' [' . $field->type . ']'); } if ($this->get('show_custom')) { $options[] = JHtml::_('select.option', 'custom', '- ' . JText::_('RL_CUSTOM') . ' -'); } return $options; } private function getFields(): array { $context = $this->get('context', 'com_content.article'); $cache = new Cache([__METHOD__, $context]); if ($cache->exists()) { return $cache->get(); } $db = RL_DB::get(); $query = RL_DB::getQuery()->select('DISTINCT a.id, a.type, a.name, a.title')->from('#__fields AS a')->where('a.state = 1')->where('a.only_use_in_subform = 0')->where(RL_DB::isNot('a.type', ['subform', 'repeatable']))->where(RL_DB::is('a.context', $context))->order('a.title'); $db->setQuery($query); $fields = $db->loadObjectList(); return $cache->set($fields); } } Field/UsersField.php 0000604 00000005307 15172746170 0010360 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\HTML\HTMLHelper as JHtml; use Joomla\CMS\Language\Text as JText; use RegularLabs\Library\DB as RL_DB; use RegularLabs\Library\Form\Form; use RegularLabs\Library\Form\FormField as RL_FormField; class UsersField extends RL_FormField { static $users; static $users_count; public $attributes = ['show_current' => \false]; public bool $is_select_list = \true; public bool $use_ajax = \true; public function getNamesByIds(array $values, array $attributes): array { $query = $this->db->getQuery(\true)->select('u.name, u.username, u.id, u.block as disabled')->from('#__users AS u')->where(RL_DB::is('u.id', $values))->order('name'); $this->db->setQuery($query); $users = $this->db->loadObjectList(); if (in_array('current', $values)) { array_unshift($users, (object) ['id' => 'current', 'name' => JText::_('RL_CURRENT_USER'), 'add_id' => \false]); } return Form::getNamesWithExtras($users, ['username', 'id', 'disabled']); } protected function getListOptions(array $attributes): array|int { if ($this->max_list_count && $this->getUsersCount() > $this->max_list_count) { return -1; } $users = $this->getUsers(); $options = $this->getOptionsByList($users, ['username', 'id', 'disabled'], 0, $this->get('username_as_value') ? 'username' : 'id'); if (!empty($attributes['show_current'])) { array_unshift($options, JHtml::_('select.option', 'current', '- ' . JText::_('RL_CURRENT_USER') . ' -')); } return $options; } private function getUsers(): array { if (!is_null(self::$users)) { return self::$users; } $query = $this->db->getQuery(\true)->select('u.name, u.username, u.id, u.block as disabled')->from('#__users AS u')->order('name'); $this->db->setQuery($query); self::$users = $this->db->loadObjectList(); return self::$users; } private function getUsersCount(): int { if (!is_null(self::$users_count)) { return self::$users_count; } $query = $this->db->getQuery(\true)->select('COUNT(*)')->from('#__users AS u'); $this->db->setQuery($query); self::$users_count = $this->db->loadResult(); return self::$users_count; } } Field/JCompatibilityField.php 0000604 00000002427 15172746170 0012202 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Language\Text as JText; use RegularLabs\Library\Document as RL_Document; use RegularLabs\Library\Form\FormField as RL_FormField; use RegularLabs\Library\Version; class JCompatibilityField extends RL_FormField { protected function getInput() { $extension = $this->get('extension'); if (empty($extension)) { return ''; } $jversion = Version::getMajorJoomlaVersion(); if ($jversion == 4) { return ''; } RL_Document::useStyle('webcomponent.joomla-alert'); RL_Document::useScript('webcomponent.joomla-alert'); return '<joomla-alert type="danger" dismiss="true" class="joomla-alert--show" role="alert">' . JText::sprintf('RL_NOT_COMPATIBLE_WITH_JOOMLA_VERSION', JText::_($extension), $jversion) . '</joomla-alert>'; } protected function getLabel() { return ''; } } Field/AgentsField.php 0000604 00000006673 15172746170 0010507 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\HTML\HTMLHelper as JHtml; use Joomla\CMS\Language\Text as JText; use RegularLabs\Library\Form\FormField as RL_FormField; class AgentsField extends RL_FormField { public $attributes = ['group' => 'os']; public bool $is_select_list = \true; public function getNamesByIds(array $values, array $attributes): array { $agents = $this->getAgents($attributes); $names = []; foreach ($agents as $agent) { if (!in_array($agent[1], $values)) { continue; } $names[] = $agent[0]; } return $names; } protected function getListOptions(array $attributes): array|int { $agents = $this->getAgents($attributes); $options = []; foreach ($agents as $agent) { $option = JHtml::_('select.option', $agent[1], $agent[0]); $options[] = $option; } return $options; } private function getAgents(array $attributes): array { $agents = []; switch ($attributes['group']) { /* OS */ case 'os': $agents[] = ['Windows', 'Windows']; $agents[] = ['Mac OS', '#(Mac OS|Mac_PowerPC|Macintosh)#']; $agents[] = ['Linux', '#(Linux|X11)#']; $agents[] = ['Open BSD', 'OpenBSD']; $agents[] = ['Sun OS', 'SunOS']; $agents[] = ['QNX', 'QNX']; $agents[] = ['BeOS', 'BeOS']; $agents[] = ['OS/2', 'OS/2']; break; /* Browsers */ case 'browser': $agents[] = ['Chrome', 'Chrome']; $agents[] = ['Firefox', 'Firefox']; $agents[] = ['Microsoft Edge', 'MSIE Edge']; // missing MSIE is added to agent string in RegularLabs\Component\Conditions\Administrator\Condition\Agent\Agent $agents[] = ['Internet Explorer', 'MSIE [0-9]']; // missing MSIE is added to agent string in RegularLabs\Component\Conditions\Administrator\Condition\Agent\Agent $agents[] = ['Opera', 'Opera']; $agents[] = ['Safari', 'Safari']; break; /* Mobile browsers */ case 'mobile': $agents[] = [JText::_('JALL'), 'mobile']; $agents[] = ['Android', 'Android']; $agents[] = ['Android Chrome', '#Android.*Chrome#']; $agents[] = ['Blackberry', 'Blackberry']; $agents[] = ['IE Mobile', 'IEMobile']; $agents[] = ['iPad', 'iPad']; $agents[] = ['iPhone', 'iPhone']; $agents[] = ['iPod Touch', 'iPod']; $agents[] = ['NetFront', 'NetFront']; $agents[] = ['Nokia', 'NokiaBrowser']; $agents[] = ['Opera Mini', 'Opera Mini']; $agents[] = ['Opera Mobile', 'Opera Mobi']; $agents[] = ['UC Browser', 'UC Browser']; break; default: break; } return $agents; } } Field/VersionField.php 0000604 00000003201 15172746170 0010673 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Factory as JFactory; use RegularLabs\Library\Form\FormField as RL_FormField; use RegularLabs\Library\Version as RL_Version; class VersionField extends RL_FormField { protected function getInput() { $extension = $this->get('extension'); $xml = $this->get('xml'); if (!$xml && $this->form->getValue('element')) { if ($this->form->getValue('folder')) { $xml = 'plugins/' . $this->form->getValue('folder') . '/' . $this->form->getValue('element') . '/' . $this->form->getValue('element') . '.xml'; } else { $xml = 'administrator/modules/' . $this->form->getValue('element') . '/' . $this->form->getValue('element') . '.xml'; } if (!file_exists(JPATH_SITE . '/' . $xml)) { return ''; } } if (empty($extension) || empty($xml)) { return ''; } $user = JFactory::getApplication()->getIdentity() ?: JFactory::getUser(); $authorise = $user->authorise('core.manage', 'com_installer'); if (!$authorise) { return ''; } return RL_Version::getMessage($extension); } protected function getLabel() { return ''; } } Field/IsInstalledField.php 0000604 00000001713 15172746170 0011467 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use RegularLabs\Library\Extension as RL_Extension; use RegularLabs\Library\Form\FormField as RL_FormField; class IsInstalledField extends RL_FormField { protected $layout = 'joomla.form.field.hidden'; protected function getLabel() { $this->value = (int) RL_Extension::isInstalled($this->get('extension'), $this->get('extension_type', 'component'), $this->get('folder', 'system')); return $this->getControlGroupEnd() . rtrim($this->getRenderer($this->layout)->render($this->getLayoutData()), \PHP_EOL) . $this->getControlGroupStart(); } } Field/DownloadKeyField.php 0000604 00000001762 15172746170 0011500 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Layout\FileLayout as JFileLayout; use RegularLabs\Library\Document as RL_Document; use RegularLabs\Library\Form\FormField as RL_FormField; class DownloadKeyField extends RL_FormField { protected function getInput() { RL_Document::script('regularlabs.script'); RL_Document::script('regularlabs.downloadkey'); return (new JFileLayout('regularlabs.form.field.downloadkey', JPATH_SITE . '/libraries/regularlabs/layouts'))->render(['id' => $this->id, 'extension' => strtolower($this->get('extension', 'all')), 'use_modal' => $this->get('use-modal', \true)]); } } Field/IconToggleField.php 0000604 00000001773 15172746170 0011314 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Layout\FileLayout as JFileLayout; use RegularLabs\Library\Form\FormField as RL_FormField; class IconToggleField extends RL_FormField { protected function getInput() { return (new JFileLayout('regularlabs.form.field.icontoggle', JPATH_SITE . '/libraries/regularlabs/layouts'))->render(['id' => $this->id, 'name' => $this->name, 'icon1' => strtolower($this->get('icon1', 'arrow-down')), 'icon2' => $this->get('icon2', 'arrow-up'), 'text1' => $this->get('text1', ''), 'text2' => $this->get('text2', ''), 'class1' => $this->get('class1', ''), 'class2' => $this->get('class2', '')]); } } Field/UserGroupsField.php 0000604 00000003005 15172746170 0011366 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use RegularLabs\Library\DB as RL_DB; use RegularLabs\Library\Form\FormField as RL_FormField; class UserGroupsField extends RL_FormField { static $options; public bool $is_select_list = \true; public bool $use_tree_select = \true; // public bool $use_ajax = true; public function getNamesByIds(array $values, array $attributes): array { $query = $this->db->getQuery(\true)->select('a.title')->from('#__usergroups AS a')->where(RL_DB::is('a.id', $values))->order('a.lft ASC'); $this->db->setQuery($query); return $this->db->loadColumn(); } protected function getOptions() { if (!empty(self::$options)) { return self::$options; } $query = $this->db->getQuery(\true)->select('a.id as value, a.title as text, a.parent_id AS parent')->from('#__usergroups AS a')->select('COUNT(DISTINCT b.id) AS level')->join('LEFT', '#__usergroups AS b ON a.lft > b.lft AND a.rgt < b.rgt')->group('a.id')->order('a.lft ASC'); $this->db->setQuery($query); self::$options = $this->db->loadObjectList(); return self::$options; } } Field/BlockField.php 0000604 00000003400 15172746170 0010301 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use Joomla\CMS\Form\FormHelper as JFormHelper; use RegularLabs\Library\Form\FormField as RL_FormField; class BlockField extends RL_FormField { protected $hiddenDescription = \true; protected function getInput() { if ($this->get('end', 0)) { return $this->getControlGroupEnd() . '</fieldset>' . $this->getControlGroupStart(); } $title = $this->get('label'); $description = $this->get('description'); $class = $this->get('class'); $no_default_class = $this->get('no_default_class'); $html = []; $attributes = 'class="' . ($no_default_class ? '' : 'options-form ') . $class . '"'; if ($this->get('showon')) { $encodedConditions = json_encode(JFormHelper::parseShowOnConditions($this->get('showon'), $this->formControl, $this->group)); $attributes .= " data-showon='" . $encodedConditions . "'"; } $html[] = '<fieldset ' . $attributes . '>'; if ($title) { $html[] = '<legend>' . $this->prepareText($title) . '</legend>'; } if ($description) { $html[] = '<div class="form-text mb-3">' . $this->prepareText($description) . '</div>'; } return $this->getControlGroupEnd() . implode('', $html) . $this->getControlGroupStart(); } protected function getLabel() { return ''; } } Field/ShowOnField.php 0000604 00000002641 15172746170 0010472 0 ustar 00 <?php /** * @package Regular Labs Library * @version 25.7.12430 * * @author Peter van Westen <info@regularlabs.com> * @link https://regularlabs.com * @copyright Copyright © 2025 Regular Labs All Rights Reserved * @license GNU General Public License version 2 or later */ namespace RegularLabs\Library\Form\Field; defined('_JEXEC') or die; use RegularLabs\Library\Form\FormField as RL_FormField; use RegularLabs\Library\RegEx as RL_RegEx; use RegularLabs\Library\ShowOn as RL_ShowOn; class ShowOnField extends RL_FormField { protected function getInput() { $value = (string) $this->get('value'); $class = $this->get('class', ''); if (!$value) { return $this->getControlGroupEnd() . RL_ShowOn::close() . $this->getControlGroupStart(); } $formControl = $this->get('form', $this->formControl); $formControl = $formControl == 'root' ? '' : $formControl; while (str_starts_with($value, '../')) { $value = substr($value, 3); if (str_contains($formControl, '[')) { $formControl = RL_RegEx::replace('^(.*)\[.*?\]$', '\1', $formControl); } } return $this->getControlGroupEnd() . RL_ShowOn::open($value, $formControl, $this->group, $class) . $this->getControlGroupStart(); } protected function getLabel() { return ''; } } HtmlView.php 0000644 00000014504 15173020265 0007021 0 ustar 00 <?php /** * @package Joomla.Site * @subpackage com_content * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\Component\Content\Site\View\Form; use Joomla\CMS\Factory; use Joomla\CMS\Helper\TagsHelper; use Joomla\CMS\Language\Multilanguage; use Joomla\CMS\Language\Text; use Joomla\CMS\MVC\View\GenericDataException; use Joomla\CMS\MVC\View\HtmlView as BaseHtmlView; use Joomla\CMS\Plugin\PluginHelper; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * HTML Article View class for the Content component * * @since 1.5 */ class HtmlView extends BaseHtmlView { /** * The Form object * * @var \Joomla\CMS\Form\Form */ protected $form; /** * The item being created * * @var \stdClass */ protected $item; /** * The page to return to after the article is submitted * * @var string */ protected $return_page = ''; /** * The model state * * @var \Joomla\CMS\Object\CMSObject */ protected $state; /** * The page parameters * * @var \Joomla\Registry\Registry|null * * @since 4.0.0 */ protected $params = null; /** * The page class suffix * * @var string * * @since 4.0.0 */ protected $pageclass_sfx = ''; /** * The user object * * @var \Joomla\CMS\User\User * * @since 4.0.0 */ protected $user = null; /** * Should we show a captcha form for the submission of the article? * * @var boolean * * @since 3.7.0 */ protected $captchaEnabled = false; /** * Should we show Save As Copy button? * * @var boolean * @since 4.1.0 */ protected $showSaveAsCopy = false; /** * Execute and display a template script. * * @param string $tpl The name of the template file to parse; automatically searches through the template paths. * * @return void|boolean */ public function display($tpl = null) { $app = Factory::getApplication(); $user = $app->getIdentity(); // Get model data. $this->state = $this->get('State'); $this->item = $this->get('Item'); $this->form = $this->get('Form'); $this->return_page = $this->get('ReturnPage'); if (empty($this->item->id)) { $catid = $this->state->params->get('catid'); if ($this->state->params->get('enable_category') == 1 && $catid) { $authorised = $user->authorise('core.create', 'com_content.category.' . $catid); } else { $authorised = $user->authorise('core.create', 'com_content') || count($user->getAuthorisedCategories('com_content', 'core.create')); } } else { $authorised = $this->item->params->get('access-edit'); } if ($authorised !== true) { $app->enqueueMessage(Text::_('JERROR_ALERTNOAUTHOR'), 'error'); $app->setHeader('status', 403, true); return false; } $this->item->tags = new TagsHelper(); if (!empty($this->item->id)) { $this->item->tags->getItemTags('com_content.article', $this->item->id); $this->item->images = json_decode($this->item->images); $this->item->urls = json_decode($this->item->urls); $tmp = new \stdClass(); $tmp->images = $this->item->images; $tmp->urls = $this->item->urls; $this->form->bind($tmp); } // Check for errors. if (count($errors = $this->get('Errors'))) { throw new GenericDataException(implode("\n", $errors), 500); } // Create a shortcut to the parameters. $params = &$this->state->params; // Escape strings for HTML output $this->pageclass_sfx = htmlspecialchars($params->get('pageclass_sfx', '')); $this->params = $params; // Override global params with article specific params $this->params->merge($this->item->params); $this->user = $user; // Propose current language as default when creating new article if (empty($this->item->id) && Multilanguage::isEnabled() && $params->get('enable_category') != 1) { $lang = $this->getLanguage()->getTag(); $this->form->setFieldAttribute('language', 'default', $lang); } $captchaSet = $params->get('captcha', Factory::getApplication()->get('captcha', '0')); foreach (PluginHelper::getPlugin('captcha') as $plugin) { if ($captchaSet === $plugin->name) { $this->captchaEnabled = true; break; } } // If the article is being edited and the current user has permission to create article if ( $this->item->id && ($user->authorise('core.create', 'com_content') || \count($user->getAuthorisedCategories('com_content', 'core.create'))) ) { $this->showSaveAsCopy = true; } $this->_prepareDocument(); parent::display($tpl); } /** * Prepares the document * * @return void */ protected function _prepareDocument() { $app = Factory::getApplication(); // Because the application sets a default page title, // we need to get it from the menu item itself $menu = $app->getMenu()->getActive(); if ($menu) { $this->params->def('page_heading', $this->params->get('page_title', $menu->title)); } else { $this->params->def('page_heading', Text::_('COM_CONTENT_FORM_EDIT_ARTICLE')); } $title = $this->params->def('page_title', Text::_('COM_CONTENT_FORM_EDIT_ARTICLE')); $this->setDocumentTitle($title); $app->getPathway()->addItem($title); if ($this->params->get('menu-meta_description')) { $this->getDocument()->setDescription($this->params->get('menu-meta_description')); } if ($this->params->get('robots')) { $this->getDocument()->setMetaData('robots', $this->params->get('robots')); } } } FormFactoryInterface.php 0000644 00000001416 15173135670 0011343 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Interface defining a factory which can create Form objects * * @since 4.0.0 */ interface FormFactoryInterface { /** * Method to get an instance of a form. * * @param string $name The name of the form. * @param array $options An array of form options. * * @return Form * * @since 4.0.0 */ public function createForm(string $name, array $options = []): Form; } Filter/TelFilter.php 0000644 00000007502 15173135670 0010410 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Filter; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormFilterInterface; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Filter class for phone numbers * * @since 4.0.0 */ class TelFilter implements FormFilterInterface { /** * Method to filter a field value. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return mixed The filtered value. * * @since 4.0.0 */ public function filter(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { $value = trim($value); // Does it match the NANP pattern? if (preg_match('/^(?:\+?1[-. ]?)?\(?([2-9][0-8][0-9])\)?[-. ]?([2-9][0-9]{2})[-. ]?([0-9]{4})$/', $value) == 1) { $number = (string) preg_replace('/[^\d]/', '', $value); if (substr($number, 0, 1) === '1') { $number = substr($number, 1); } if (substr($number, 0, 2) === '+1') { $number = substr($number, 2); } $result = '1.' . $number; } elseif (preg_match('/^\+(?:[0-9] ?){6,14}[0-9]$/', $value) == 1) { // If not, does it match ITU-T? $countrycode = substr($value, 0, strpos($value, ' ')); $countrycode = (string) preg_replace('/[^\d]/', '', $countrycode); $number = strstr($value, ' '); $number = (string) preg_replace('/[^\d]/', '', $number); $result = $countrycode . '.' . $number; } elseif (preg_match('/^\+[0-9]{1,3}\.[0-9]{4,14}(?:x.+)?$/', $value) == 1) { // If not, does it match EPP? if (strstr($value, 'x')) { $xpos = strpos($value, 'x'); $value = substr($value, 0, $xpos); } $result = str_replace('+', '', $value); } elseif (preg_match('/[0-9]{1,3}\.[0-9]{4,14}$/', $value) == 1) { // Maybe it is already ccc.nnnnnnn? $result = $value; } else { // If not, can we make it a string of digits? $value = (string) preg_replace('/[^\d]/', '', $value); if ($value != null && \strlen($value) <= 15) { $length = \strlen($value); // If it is fewer than 13 digits assume it is a local number if ($length <= 12) { $result = '.' . $value; } else { // If it has 13 or more digits let's make a country code. $cclen = $length - 12; $result = substr($value, 0, $cclen) . '.' . substr($value, $cclen); } } else { // If not let's not save anything. $result = ''; } } return $result; } } Filter/UrlFilter.php 0000644 00000007107 15173135670 0010427 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Filter; use Joomla\CMS\Filter\InputFilter; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormFilterInterface; use Joomla\CMS\String\PunycodeHelper; use Joomla\CMS\Uri\Uri; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Filter class for URLs * * @since 4.0.0 */ class UrlFilter implements FormFilterInterface { /** * Method to filter a field value. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return mixed The filtered value. * * @since 4.0.0 */ public function filter(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { if (empty($value)) { return false; } // This cleans some of the more dangerous characters but leaves special characters that are valid. $value = InputFilter::getInstance()->clean($value, 'html'); $value = trim($value); // <>" are never valid in a uri see https://www.ietf.org/rfc/rfc1738.txt $value = str_replace(['<', '>', '"'], '', $value); // Check for a protocol $protocol = parse_url($value, PHP_URL_SCHEME); // If there is no protocol and the relative option is not specified, // we assume that it is an external URL and prepend http:// if ( ((string) $element['type'] === 'url' && !$protocol && !$element['relative']) || ((string) $element['type'] !== 'url' && !$protocol) ) { $protocol = 'http'; // If it looks like an internal link, then add the root. if (substr($value, 0, 9) === 'index.php') { $value = Uri::root() . $value; } else { // Otherwise we treat it as an external link. // Put the url back together. $value = $protocol . '://' . $value; } } elseif (!$protocol && $element['relative']) { // If relative URLS are allowed we assume that URLs without protocols are internal. $host = Uri::getInstance('SERVER')->getHost(); // If it starts with the host string, just prepend the protocol. if (substr($value, 0) === $host) { $value = 'http://' . $value; } elseif (substr($value, 0, 1) !== '/') { // Otherwise if it doesn't start with "/" prepend the prefix of the current site. $value = Uri::root(true) . '/' . $value; } } $value = PunycodeHelper::urlToPunycode($value); return $value; } } Filter/RawFilter.php 0000644 00000003177 15173135670 0010421 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Filter; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormFilterInterface; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Filter class for raw values * * @since 4.0.0 */ class RawFilter implements FormFilterInterface { /** * Method to filter a field value. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return mixed The filtered value. * * @since 4.0.0 */ public function filter(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { return $value; } } Filter/RulesFilter.php 0000644 00000003724 15173135670 0010760 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Filter; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormFilterInterface; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Filter class for rules * * @since 4.0.0 */ class RulesFilter implements FormFilterInterface { /** * Method to filter a field value. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return mixed The filtered value. * * @since 4.0.0 */ public function filter(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { $return = []; foreach ((array) $value as $action => $ids) { // Build the rules array. $return[$action] = []; foreach ($ids as $id => $p) { if ($p !== '') { $return[$action][$id] = ($p == '1' || $p === 'true'); } } } return $return; } } Filter/SafehtmlFilter.php 0000644 00000003543 15173135670 0011430 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Filter; use Joomla\CMS\Filter\InputFilter; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormFilterInterface; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Filter class for safe HTML * * @since 4.0.0 */ class SafehtmlFilter implements FormFilterInterface { /** * Method to filter a field value. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return mixed The filtered value. * * @since 4.0.0 */ public function filter(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { return InputFilter::getInstance( [], [], InputFilter::ONLY_BLOCK_DEFINED_TAGS, InputFilter::ONLY_BLOCK_DEFINED_ATTRIBUTES )->clean($value, 'html'); } } Filter/UnsetFilter.php 0000644 00000003171 15173135670 0010760 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Filter; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormFilterInterface; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Filter class to unset * * @since 4.0.0 */ class UnsetFilter implements FormFilterInterface { /** * Method to filter a field value. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return mixed The filtered value. * * @since 4.0.0 */ public function filter(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { return null; } } Filter/IntarrayFilter.php 0000644 00000004115 15173135670 0011452 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Filter; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormFilterInterface; use Joomla\Registry\Registry; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Filter class for integer arrays * * @since 4.0.0 */ class IntarrayFilter implements FormFilterInterface { /** * Method to filter a field value. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return mixed The filtered value. * * @since 4.0.0 */ public function filter(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { if (strtoupper((string) $element['filter']) === 'INT_ARRAY') { @trigger_error('`INT_ARRAY` form filter is deprecated and will be removed in 5.0. Use `Intarray` instead', E_USER_DEPRECATED); } if (\is_object($value)) { $value = get_object_vars($value); } $value = \is_array($value) ? $value : [$value]; $value = ArrayHelper::toInteger($value); return $value; } } Rule/CssIdentifierSubstringRule.php 0000644 00000005777 15173135670 0013500 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 3.10.7 */ class CssIdentifierSubstringRule extends FormRule { /** * Method to test if a string is a valid CSS identifier substring * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 3.10.7 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { // If the field is empty and not required, the field is valid. $required = ((string) $element['required'] === 'true' || (string) $element['required'] === 'required'); if (!$required && empty($value) && $value !== '0') { return true; } /** * The following regex rules are based on the Html::cleanCssIdentifier method from Drupal * https://github.com/drupal/drupal/blob/8.8.5/core/lib/Drupal/Component/Utility/Html.php#L116-L130 * * with the addition for Joomla that we allow the colon (U+003A) and the @ (U+0040). */ /** * Valid characters in a CSS identifier are: * - the hyphen (U+002D) * - a-z (U+0030 - U+0039) * - A-Z (U+0041 - U+005A) * - the underscore (U+005F) * - the colon (U+003A) * - the @ sign (U+0040) * - 0-9 (U+0061 - U+007A) * - ISO 10646 characters U+00A1 and higher */ // Make sure we allow multiple classes to be added $cssIdentifiers = explode(' ', $value); foreach ($cssIdentifiers as $identifier) { if (preg_match('/[^\\x{002D}\\x{0030}-\\x{0039}\\x{0040}-\\x{005A}\\x{005F}\\x{003A}\\x{0061}-\\x{007A}\\x{00A1}-\\x{FFFF}]/u', $identifier)) { return false; } } return true; } } Rule/SubformRule.php 0000644 00000005640 15173135670 0010446 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\Field\SubformField; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form rule to validate subforms field-wise. * * @since 3.9.7 */ class SubformRule extends FormRule { /** * Method to test given values for a subform.. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 3.9.7 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { // Get the form field object. $field = $form->getField($element['name'], $group); if (!($field instanceof SubformField)) { throw new \UnexpectedValueException(sprintf('%s is no subform field.', $element['name'])); } if ($value === null) { return true; } $subForm = $field->loadSubForm(); // Multiple values: Validate every row. if ($field->multiple) { foreach ($value as $row) { if ($subForm->validate($row) === false) { // Pass the first error that occurred on the subform validation. $errors = $subForm->getErrors(); if (!empty($errors[0])) { return $errors[0]; } return false; } } } else { // Single value. if ($subForm->validate($value) === false) { // Pass the first error that occurred on the subform validation. $errors = $subForm->getErrors(); if (!empty($errors[0])) { return $errors[0]; } return false; } } return true; } } Rule/PasswordRule.php 0000644 00000017147 15173135670 0010640 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\CMS\Language\Text; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 3.1.2 */ class PasswordRule extends FormRule { /** * Method to test if two values are not equal. To use this rule, the form * XML needs a validate attribute of equals and a field attribute * that is equal to the field to test against. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 3.1.2 * @throws \InvalidArgumentException * @throws \UnexpectedValueException */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { $meter = isset($element['strengthmeter']) ? ' meter="0"' : '1'; $threshold = isset($element['threshold']) ? (int) $element['threshold'] : 66; $minimumLength = isset($element['minimum_length']) ? (int) $element['minimum_length'] : 12; $minimumIntegers = isset($element['minimum_integers']) ? (int) $element['minimum_integers'] : 0; $minimumSymbols = isset($element['minimum_symbols']) ? (int) $element['minimum_symbols'] : 0; $minimumUppercase = isset($element['minimum_uppercase']) ? (int) $element['minimum_uppercase'] : 0; $minimumLowercase = isset($element['minimum_lowercase']) ? (int) $element['minimum_lowercase'] : 0; // In the installer we don't have any access to the // database yet so use the hard coded default settings if ( !Factory::getApplication()->isClient('installation') && !Factory::getApplication()->isClient('cli_installation') ) { // If we have parameters from com_users, use those instead. // Some of these may be empty for legacy reasons. $params = ComponentHelper::getParams('com_users'); if (!empty($params)) { $minimumLengthp = $params->get('minimum_length', 12); $minimumIntegersp = $params->get('minimum_integers', 0); $minimumSymbolsp = $params->get('minimum_symbols', 0); $minimumUppercasep = $params->get('minimum_uppercase', 0); $minimumLowercasep = $params->get('minimum_lowercase', 0); $meterp = $params->get('meter'); $thresholdp = $params->get('threshold', 66); empty($minimumLengthp) ?: $minimumLength = (int) $minimumLengthp; empty($minimumIntegersp) ?: $minimumIntegers = (int) $minimumIntegersp; empty($minimumSymbolsp) ?: $minimumSymbols = (int) $minimumSymbolsp; empty($minimumUppercasep) ?: $minimumUppercase = (int) $minimumUppercasep; empty($minimumLowercasep) ?: $minimumLowercase = (int) $minimumLowercasep; empty($meterp) ?: $meter = $meterp; empty($thresholdp) ?: $threshold = $thresholdp; } } // If the field is empty and not required, the field is valid. $required = ((string) $element['required'] === 'true' || (string) $element['required'] === 'required'); if (!$required && empty($value)) { return true; } $valueLength = \strlen($value); // We set a maximum length to prevent abuse since it is unfiltered. if ($valueLength > 4096) { Factory::getApplication()->enqueueMessage(Text::_('JFIELD_PASSWORD_TOO_LONG'), 'error'); } // We don't allow white space inside passwords $valueTrim = trim($value); // Set a variable to check if any errors are made in password $validPassword = true; if (\strlen($valueTrim) !== $valueLength) { Factory::getApplication()->enqueueMessage( Text::_('JFIELD_PASSWORD_SPACES_IN_PASSWORD'), 'error' ); $validPassword = false; } // Minimum number of integers required if (!empty($minimumIntegers)) { $nInts = preg_match_all('/[0-9]/', $value, $imatch); if ($nInts < $minimumIntegers) { Factory::getApplication()->enqueueMessage( Text::plural('JFIELD_PASSWORD_NOT_ENOUGH_INTEGERS_N', $minimumIntegers), 'error' ); $validPassword = false; } } // Minimum number of symbols required if (!empty($minimumSymbols)) { $nsymbols = preg_match_all('[\W]', $value, $smatch); if ($nsymbols < $minimumSymbols) { Factory::getApplication()->enqueueMessage( Text::plural('JFIELD_PASSWORD_NOT_ENOUGH_SYMBOLS_N', $minimumSymbols), 'error' ); $validPassword = false; } } // Minimum number of upper case ASCII characters required if (!empty($minimumUppercase)) { $nUppercase = preg_match_all('/[A-Z]/', $value, $umatch); if ($nUppercase < $minimumUppercase) { Factory::getApplication()->enqueueMessage( Text::plural('JFIELD_PASSWORD_NOT_ENOUGH_UPPERCASE_LETTERS_N', $minimumUppercase), 'error' ); $validPassword = false; } } // Minimum number of lower case ASCII characters required if (!empty($minimumLowercase)) { $nLowercase = preg_match_all('/[a-z]/', $value, $umatch); if ($nLowercase < $minimumLowercase) { Factory::getApplication()->enqueueMessage( Text::plural('JFIELD_PASSWORD_NOT_ENOUGH_LOWERCASE_LETTERS_N', $minimumLowercase), 'error' ); $validPassword = false; } } // Minimum length option if (!empty($minimumLength)) { if (\strlen((string) $value) < $minimumLength) { Factory::getApplication()->enqueueMessage( Text::plural('JFIELD_PASSWORD_TOO_SHORT_N', $minimumLength), 'error' ); $validPassword = false; } } // If valid has violated any rules above return false. if (!$validPassword) { return false; } return true; } } Rule/CssIdentifierRule.php 0000644 00000006505 15173135670 0011565 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 4.0.0 */ class CssIdentifierRule extends FormRule { /** * Method to test if the file path is valid * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 4.0.0 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { // If the field is empty and not required, the field is valid. $required = ((string) $element['required'] === 'true' || (string) $element['required'] === 'required'); if (!$required && empty($value) && $value !== '0') { return true; } // Make sure we allow multiple classes to be added $cssIdentifiers = explode(' ', $value); foreach ($cssIdentifiers as $i => $identifier) { /** * The following regex rules are based on the Html::cleanCssIdentifier method from Drupal * https://github.com/drupal/drupal/blob/8.8.5/core/lib/Drupal/Component/Utility/Html.php#L116-L130 * * with the addition for Joomla that we allow the colon (U+003A) and the @ (U+0040). */ /** * Valid characters in a CSS identifier are: * - the hyphen (U+002D) * - a-z (U+0030 - U+0039) * - A-Z (U+0041 - U+005A) * - the underscore (U+005F) * - the colon (U+003A) * - the @-sign (U+0040) * - 0-9 (U+0061 - U+007A) * - ISO 10646 characters U+00A1 and higher */ if (preg_match('/[^\\x{002D}\\x{0030}-\\x{0039}\\x{0040}-\\x{005A}\\x{005F}\\x{003A}\\x{0061}-\\x{007A}\\x{00A1}-\\x{FFFF}]/u', $identifier)) { return false; } /** * Full identifiers cannot start with a digit, two hyphens, or a hyphen followed by a digit. */ if (preg_match('/^[0-9]/', $identifier) || preg_match('/^(-[0-9])|^(--)/', $identifier)) { return false; } } return true; } } Rule/ColorRule.php 0000644 00000004437 15173135670 0010112 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 1.7.0 */ class ColorRule extends FormRule { /** * Method to test for a valid color in hexadecimal. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 1.7.0 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { $value = trim($value); // If the field is empty and not required, the field is valid. $required = ((string) $element['required'] === 'true' || (string) $element['required'] === 'required'); if (!$required && empty($value)) { return true; } if ($value[0] != '#') { return false; } // Remove the leading # if present to validate the numeric part $value = ltrim($value, '#'); // The value must be 6 or 3 characters long if (!((\strlen($value) == 6 || \strlen($value) == 3) && ctype_xdigit($value))) { return false; } return true; } } Rule/UrlRule.php 0000644 00000012401 15173135670 0007564 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Filter\InputFilter; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\CMS\Language\Text; use Joomla\Registry\Registry; use Joomla\String\StringHelper; use Joomla\Uri\UriHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 1.7.0 */ class UrlRule extends FormRule { /** * Method to test an external or internal url for all valid parts. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 1.7.0 * @link https://www.w3.org/Addressing/URL/url-spec.txt * @see \Joomla\String\StringHelper */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { // If the field is empty and not required, the field is valid. $required = ((string) $element['required'] === 'true' || (string) $element['required'] === 'required'); if (!$required && empty($value)) { return true; } // Check the value for XSS payloads if ((string) $element['disableXssCheck'] !== 'true' && InputFilter::checkAttribute(['href', $value])) { $element->addAttribute('message', Text::sprintf('JLIB_FORM_VALIDATE_FIELD_URL_INJECTION_DETECTED', $element['name'])); return false; } $urlParts = UriHelper::parse_url($value); // See https://www.w3.org/Addressing/URL/url-spec.txt // Use the full list or optionally specify a list of permitted schemes. if ($element['schemes'] == '') { $scheme = ['http', 'https', 'ftp', 'ftps', 'gopher', 'mailto', 'news', 'prospero', 'telnet', 'rlogin', 'sftp', 'tn3270', 'wais', 'mid', 'cid', 'nntp', 'tel', 'urn', 'ldap', 'file', 'fax', 'modem', 'git', ]; } else { $scheme = explode(',', $element['schemes']); } /* * Note that parse_url() does not always parse accurately without a scheme, * but at least the path should be set always. Note also that parse_url() * returns False for seriously malformed URLs instead of an associative array. * @link https://www.php.net/manual/en/function.parse-url.php */ if ($urlParts === false || !\array_key_exists('scheme', $urlParts)) { /* * The function parse_url() returned false (seriously malformed URL) or no scheme * was found and the relative option is not set: in both cases the field is not valid. */ if ($urlParts === false || !$element['relative']) { $element->addAttribute('message', Text::sprintf('JLIB_FORM_VALIDATE_FIELD_URL_SCHEMA_MISSING', $value, implode(', ', $scheme))); return false; } // The best we can do for the rest is make sure that the path exists and is valid UTF-8. if (!\array_key_exists('path', $urlParts) || !StringHelper::valid((string) $urlParts['path'])) { return false; } // The internal URL seems to be good. return true; } // Scheme found, check all parts found. $urlScheme = (string) $urlParts['scheme']; $urlScheme = strtolower($urlScheme); if (\in_array($urlScheme, $scheme) == false) { return false; } // For some schemes here must be two slashes. $scheme = ['http', 'https', 'ftp', 'ftps', 'gopher', 'wais', 'prospero', 'sftp', 'telnet', 'git']; if (\in_array($urlScheme, $scheme) && substr($value, \strlen($urlScheme), 3) !== '://') { return false; } // The best we can do for the rest is make sure that the strings are valid UTF-8 // and the port is an integer. if (\array_key_exists('host', $urlParts) && !StringHelper::valid((string) $urlParts['host'])) { return false; } if (\array_key_exists('port', $urlParts) && 0 === (int) $urlParts['port']) { return false; } if (\array_key_exists('path', $urlParts) && !StringHelper::valid((string) $urlParts['path'])) { return false; } return true; } } Rule/CalendarRule.php 0000644 00000004236 15173135670 0010542 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Date\Date; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform * * @since 3.7.0 */ class CalendarRule extends FormRule { /** * Method to test the calendar value for a valid parts. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 3.7.0 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { // If the field is empty and not required, the field is valid. $required = ((string) $element['required'] === 'true' || (string) $element['required'] === 'required'); if (!$required && empty($value)) { return true; } if (strtolower($value) === 'now') { return true; } try { return Factory::getDate($value) instanceof Date; } catch (\Exception $e) { return false; } } } Rule/UsernameRule.php 0000644 00000005234 15173135670 0010607 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Database\DatabaseAwareInterface; use Joomla\Database\DatabaseAwareTrait; use Joomla\Database\ParameterType; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 1.7.0 */ class UsernameRule extends FormRule implements DatabaseAwareInterface { use DatabaseAwareTrait; /** * Method to test the username for uniqueness. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 1.7.0 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { // Get the database object and a new query object. $db = $this->getDatabase(); $query = $db->getQuery(true); // Get the extra field check attribute. $userId = ($form instanceof Form) ? (int) $form->getValue('id') : 0; // Build the query. $query->select('COUNT(*)') ->from($db->quoteName('#__users')) ->where( [ $db->quoteName('username') . ' = :username', $db->quoteName('id') . ' <> :userId', ] ) ->bind(':username', $value) ->bind(':userId', $userId, ParameterType::INTEGER); // Set and query the database. $db->setQuery($query); $duplicate = (bool) $db->loadResult(); if ($duplicate) { return false; } return true; } } Rule/TelRule.php 0000644 00000007170 15173135670 0007555 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform * * @since 1.7.0 */ class TelRule extends FormRule { /** * Method to test the url for a valid parts. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 1.7.0 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { // If the field is empty and not required, the field is valid. $required = ((string) $element['required'] === 'true' || (string) $element['required'] === 'required'); if (!$required && empty($value)) { return true; } /* * @link http://www.nanpa.com/ * @link http://tools.ietf.org/html/rfc4933 * @link http://www.itu.int/rec/T-REC-E.164/en * * Regex by Steve Levithan * @link http://blog.stevenlevithan.com/archives/validate-phone-number * @note that valid ITU-T and EPP must begin with +. */ $regexarray = [ 'NANP' => '/^(?:\+?1[-. ]?)?\(?([2-9][0-8][0-9])\)?[-. ]?([2-9][0-9]{2})[-. ]?([0-9]{4})$/', 'ITU-T' => '/^\+(?:[0-9] ?){6,14}[0-9]$/', 'EPP' => '/^\+[0-9]{1,3}\.[0-9]{4,14}(?:x.+)?$/', ]; if (isset($element['plan'])) { $plan = (string) $element['plan']; if ($plan === 'northamerica' || $plan === 'us') { $plan = 'NANP'; } elseif ($plan === 'International' || $plan === 'int' || $plan === 'missdn' || !$plan) { $plan = 'ITU-T'; } elseif ($plan === 'IETF') { $plan = 'EPP'; } $regex = $regexarray[$plan]; // Test the value against the regular expression. if (preg_match($regex, $value) == false) { return false; } } else { /* * If the rule is set but no plan is selected just check that there are between * 7 and 15 digits inclusive and no illegal characters (but common number separators * are allowed). */ $cleanvalue = preg_replace('/[+. \-(\)]/', '', $value); $regex = '/^[0-9]{7,15}?$/'; if (preg_match($regex, $cleanvalue) == true) { return true; } else { return false; } } return true; } } Rule/OptionsRule.php 0000644 00000006233 15173135670 0010463 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * Requires the value entered be one of the options in a field of type="list" * * @since 1.7.0 */ class OptionsRule extends FormRule { /** * Method to test the value. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 1.7.0 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { // Check if the field is required. $required = ((string) $element['required'] === 'true' || (string) $element['required'] === 'required'); // Check if the value is empty. $blank = empty($value) && $value !== '0' && $value !== 0 && $value !== 0.0; if (!$required && $blank) { return true; } // Make an array of all available option values. $options = []; // Create the field $field = null; if ($form) { $field = $form->getField((string) $element->attributes()->name, $group); } // When the field exists, the real options are fetched. // This is needed for fields which do have dynamic options like from a database. if ($field && \is_array($field->options)) { foreach ($field->options as $opt) { $options[] = $opt->value; } } else { foreach ($element->option as $opt) { $options[] = $opt->attributes()->value; } } // There may be multiple values in the form of an array (if the element is checkboxes, for example). if (\is_array($value)) { // If all values are in the $options array, $diff will be empty and the options valid. $diff = array_diff($value, $options); return empty($diff); } else { // In this case value must be a string return \in_array((string) $value, $options); } } } Rule/BooleanRule.php 0000644 00000001534 15173135670 0010406 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\FormRule; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 1.7.0 */ class BooleanRule extends FormRule { /** * The regular expression to use in testing a form field value. * * @var string * @since 1.7.0 */ protected $regex = '^(?:[01]|true|false)$'; /** * The regular expression modifiers to use when testing a form field value. * * @var string * @since 1.7.0 */ protected $modifiers = 'i'; } Rule/ExistsRule.php 0000644 00000005062 15173135670 0010306 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Database\DatabaseAwareInterface; use Joomla\Database\DatabaseAwareTrait; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form rule class to determine if a value exists in a database table. * * @since 3.9.0 */ class ExistsRule extends FormRule implements DatabaseAwareInterface { use DatabaseAwareTrait; /** * Method to test the username for uniqueness. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 3.9.0 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { $value = trim($value); $existsTable = (string) $element['exists_table']; $existsColumn = (string) $element['exists_column']; // We cannot validate without a table name if ($existsTable === '') { return true; } // Assume a default column name of `id` if ($existsColumn === '') { $existsColumn = 'id'; } $db = $this->getDatabase(); // Set and query the database. $exists = $db->setQuery( $db->getQuery(true) ->select('COUNT(*)') ->from($db->quoteName($existsTable)) ->where($db->quoteName($existsColumn) . ' = ' . $db->quote($value)) )->loadResult(); return (int) $exists > 0; } } Rule/FolderPathExistsRule.php 0000644 00000005027 15173135670 0012260 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Form\Form; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla CMS. * * @since 4.0.0 */ class FolderPathExistsRule extends FilePathRule { /** * Method to test if the folder path is valid and points to an existing folder below the Joomla root * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid and points to an existing folder below the Joomla root, false otherwise. * * @since 4.0.0 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { if (!parent::test($element, $value, $group, $input, $form)) { return false; } // If the field is empty and not required so the previous test hasn't failed, the field is valid. if ($value === '' || $value === null) { return true; } // Spaces only would result in Joomla root which is not allowed if (!trim($value)) { return false; } $pathCleaned = rtrim(Path::clean(JPATH_ROOT . '/' . $value), \DIRECTORY_SEPARATOR); $rootCleaned = rtrim(Path::clean(JPATH_ROOT), \DIRECTORY_SEPARATOR); // JPATH_ROOT is not allowed if ($pathCleaned === $rootCleaned) { return false; } return Folder::exists($pathCleaned); } } Rule/CaptchaRule.php 0000644 00000004647 15173135670 0010402 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Captcha\Captcha; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Framework. * * @since 2.5 */ class CaptchaRule extends FormRule { /** * Method to test if the Captcha is correct. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 2.5 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { $app = Factory::getApplication(); $default = $app->get('captcha'); if ($app->isClient('site')) { $default = $app->getParams()->get('captcha', $default); } $plugin = $element['plugin'] ? (string) $element['plugin'] : $default; $namespace = $element['namespace'] ?: $form->getName(); // Use 0 for none if ($plugin === 0 || $plugin === '0') { return true; } try { $captcha = Captcha::getInstance((string) $plugin, ['namespace' => (string) $namespace]); return $captcha->checkAnswer($value); } catch (\RuntimeException $e) { $app->enqueueMessage($e->getMessage(), 'error'); } return false; } } Rule/NumberRule.php 0000644 00000004600 15173135670 0010254 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 3.5 */ class NumberRule extends FormRule { /** * Method to test the range for a number value using min and max attributes. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 3.5 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { // Check if the field is required. $required = ((string) $element['required'] === 'true' || (string) $element['required'] === 'required'); // If the value is empty and the field is not required return True. if (($value === '' || $value === null) && ! $required) { return true; } $float_value = (float) $value; if (isset($element['min'])) { $min = (float) $element['min']; if ($min > $float_value) { return false; } } if (isset($element['max'])) { $max = (float) $element['max']; if ($max < $float_value) { return false; } } return true; } } Rule/UserIdRule.php 0000644 00000005215 15173135670 0010222 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Database\DatabaseAwareInterface; use Joomla\Database\DatabaseAwareTrait; use Joomla\Database\ParameterType; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 4.0.0 */ class UserIdRule extends FormRule implements DatabaseAwareInterface { use DatabaseAwareTrait; /** * Method to test the validity of a Joomla User. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param ?string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 4.0.0 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { // Check if the field is required. $required = ((string) $element['required'] === 'true' || (string) $element['required'] === 'required'); // If the value is empty, null or has the value 0 and the field is not required return true else return false if (($value === '' || $value === null || (string) $value === '0')) { return !$required; } // Get the database object and a new query object. $db = $this->getDatabase(); $query = $db->getQuery(true); // Build the query. $query->select('COUNT(*)') ->from($db->quoteName('#__users')) ->where($db->quoteName('id') . ' = :userId') ->bind(':userId', $value, ParameterType::INTEGER); // Set and query the database. return (bool) $db->setQuery($query)->loadResult(); } } Rule/FilePathRule.php 0000644 00000005632 15173135670 0010526 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright Copyright (C) 2005 - 2020 Open Source Matters, Inc. All rights reserved. * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 3.9.21 */ class FilePathRule extends FormRule { /** * Method to test if the file path is valid * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 3.9.21 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { $value = trim($value); // If the field is empty and not required, the field is valid. $required = ((string) $element['required'] == 'true' || (string) $element['required'] == 'required'); if (!$required && empty($value)) { return true; } // Get the exclude setting from the xml $exclude = (array) explode('|', (string) $element['exclude']); // Exclude current folder '.' to be safe from full path disclosure $exclude[] = '.'; // Check the exclude setting $path = preg_split('/[\/\\\\]/', $value); if (in_array(strtolower($path[0]), $exclude) || empty($path[0])) { return false; } // Prepend the root path $value = JPATH_ROOT . '/' . $value; // Check if $value is a valid path, which includes not allowing to break out of the current path try { Path::check($value); } catch (\Exception $e) { // When there is an exception in the check path this is not valid return false; } // When there are no exception this rule should pass. // See: https://github.com/joomla/joomla-cms/issues/30500#issuecomment-683290162 return true; } } Rule/TimeRule.php 0000644 00000014137 15173135670 0007730 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\CMS\Language\Text; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 4.0.0 */ class TimeRule extends FormRule { /** * Method to test the range for a number value using min and max attributes. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 4.0.0 * * @throws \Exception */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null): bool { // Check if the field is required. $required = ((string) $element['required'] === 'true' || (string) $element['required'] === 'required'); // If the value is empty and the field is not required return True. if (($value === '' || $value === null) && !$required) { return true; } $stringValue = (string) $value; // If the length of a field is smaller than 5 return error message if (strlen($stringValue) !== 5 && !isset($element['step'])) { Factory::getApplication()->enqueueMessage( Text::_('JLIB_FORM_FIELD_INVALID_TIME_INPUT'), 'warning' ); return false; } // If the third symbol isn't a ':' return error message if ($stringValue[2] !== ':') { Factory::getApplication()->enqueueMessage( Text::_('JLIB_FORM_FIELD_INVALID_TIME_INPUT'), 'warning' ); return false; } // If the are other symbols except of numbers and ':' return error message if (!preg_match('#^[0-9:]+$#', $stringValue)) { Factory::getApplication()->enqueueMessage( Text::_('JLIB_FORM_FIELD_INVALID_TIME_INPUT'), 'warning' ); return false; } // If min and max is set if (isset($element['min']) && isset($element['max'])) { $min = $element['min'][0] . $element['min'][1]; $max = $element['max'][0] . $element['max'][1]; // If the input is smaller than the set min return error message if (intval($min) > intval($stringValue[0] . $stringValue[1])) { Factory::getApplication()->enqueueMessage( Text::_('JLIB_FORM_FIELD_INVALID_MIN_TIME', $min), 'warning' ); return false; } // If the input is greater than the set max return error message if (intval($max) < intval($stringValue[0] . $stringValue[1])) { Factory::getApplication()->enqueueMessage( Text::_('JLIB_FORM_FIELD_INVALID_MAX_TIME'), 'warning' ); return false; } // If the hour input is equal to the set max but the minutes input is greater than zero return error message if (intval($max) === intval($stringValue[0] . $stringValue[1])) { if (intval($element['min'][3] . $element['min'][4]) !== 0) { Factory::getApplication()->enqueueMessage( Text::_('JLIB_FORM_FIELD_INVALID_MAX_TIME'), 'warning' ); return false; } } } // If the first symbol is greater than 2 return error message if (intval($stringValue[0]) > 2) { Factory::getApplication()->enqueueMessage( Text::_('JLIB_FORM_FIELD_INVALID_TIME_INPUT'), 'warning' ); return false; } // If the first symbol is greater than 2 and the second symbol is greater than 3 return error message if (intval($stringValue[0]) === 2 && intval($stringValue[1]) > 3) { Factory::getApplication()->enqueueMessage( Text::_('JLIB_FORM_FIELD_INVALID_TIME_INPUT'), 'warning' ); return false; } // If the fourth symbol is greater than 5 return error message if (intval($stringValue[3]) > 5) { Factory::getApplication()->enqueueMessage( Text::_('JLIB_FORM_FIELD_INVALID_TIME_INPUT'), 'warning' ); return false; } // If the step is set return same error messages as above but taking into a count that there 8 and not 5 symbols if (isset($element['step'])) { if ( strlen($stringValue) !== 8 || intval($stringValue[5]) !== ':' || intval($stringValue[6]) > 5 ) { Factory::getApplication()->enqueueMessage( Text::_('JLIB_FORM_FIELD_INVALID_TIME_INPUT_SECONDS'), 'warning' ); return false; } } return true; } } Rule/EmailRule.php 0000644 00000017251 15173135670 0010061 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\CMS\Language\Text; use Joomla\CMS\String\PunycodeHelper; use Joomla\Database\DatabaseAwareInterface; use Joomla\Database\DatabaseAwareTrait; use Joomla\Database\ParameterType; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 1.7.0 */ class EmailRule extends FormRule implements DatabaseAwareInterface { use DatabaseAwareTrait; /** * The regular expression to use in testing a form field value. * * @var string * @since 1.7.0 * @link https://www.w3.org/TR/html/sec-forms.html#email-state-typeemail */ protected $regex = "^[a-zA-Z0-9.!#$%&'*+\/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])" . "?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)*$"; /** * Method to test the email address and optionally check for uniqueness. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return mixed Boolean true if field value is valid. * * @since 1.7.0 * @throws \UnexpectedValueException */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { // If the field is empty and not required, the field is valid. $required = ((string) $element['required'] === 'true' || (string) $element['required'] === 'required'); if (!$required && empty($value)) { return true; } // If the tld attribute is present, change the regular expression to require at least 2 characters for it. $tld = ((string) $element['tld'] === 'tld' || (string) $element['tld'] === 'required'); if ($tld) { $this->regex = "^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])" . '?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+$'; } // Determine if the multiple attribute is present $multiple = ((string) $element['multiple'] === 'true' || (string) $element['multiple'] === 'multiple'); if (!$multiple) { // Handle idn email addresses by converting to punycode. $value = PunycodeHelper::emailToPunycode($value); // Test the value against the regular expression. if (!parent::test($element, $value, $group, $input, $form)) { throw new \UnexpectedValueException(Text::_('JLIB_DATABASE_ERROR_VALID_MAIL')); } } else { $values = explode(',', $value); foreach ($values as $value) { // Handle idn email addresses by converting to punycode. $value = PunycodeHelper::emailToPunycode($value); // Test the value against the regular expression. if (!parent::test($element, $value, $group, $input, $form)) { throw new \UnexpectedValueException(Text::_('JLIB_DATABASE_ERROR_VALID_MAIL')); } } } /** * validDomains value should consist of component name and the name of domain list field in component's configuration, separated by a dot. * This allows different components and contexts to use different lists. * If value is incomplete, com_users.domains is used as fallback. */ $validDomains = (string) $element['validDomains'] !== '' && (string) $element['validDomains'] !== 'false'; if ($validDomains && !$multiple) { $config = explode('.', $element['validDomains'], 2); if (\count($config) > 1) { $domains = ComponentHelper::getParams($config[0])->get($config[1]); } else { $domains = ComponentHelper::getParams('com_users')->get('domains'); } if ($domains) { $emailDomain = explode('@', $value); $emailDomain = $emailDomain[1]; $emailParts = array_reverse(explode('.', $emailDomain)); $emailCount = \count($emailParts); $allowed = true; foreach ($domains as $domain) { $domainParts = array_reverse(explode('.', $domain->name)); $status = 0; // Don't run if the email has less segments than the rule. if ($emailCount < \count($domainParts)) { continue; } foreach ($emailParts as $key => $emailPart) { if (!isset($domainParts[$key]) || $domainParts[$key] == $emailPart || $domainParts[$key] == '*') { $status++; } } // All segments match, check whether to allow the domain or not. if ($status === $emailCount) { if ($domain->rule == 0) { $allowed = false; } else { $allowed = true; } } } // If domain is not allowed, fail validation. Otherwise continue. if (!$allowed) { throw new \UnexpectedValueException(Text::sprintf('JGLOBAL_EMAIL_DOMAIN_NOT_ALLOWED', $emailDomain)); } } } // Check if we should test for uniqueness. This only can be used if multiple is not true $unique = ((string) $element['unique'] === 'true' || (string) $element['unique'] === 'unique'); if ($unique && !$multiple) { // Get the database object and a new query object. $db = $this->getDatabase(); $query = $db->getQuery(true); // Get the extra field check attribute. $userId = ($form instanceof Form) ? (int) $form->getValue('id') : 0; // Build the query. $query->select('COUNT(*)') ->from($db->quoteName('#__users')) ->where( [ $db->quoteName('email') . ' = :email', $db->quoteName('id') . ' <> :userId', ] ) ->bind(':email', $value) ->bind(':userId', $userId, ParameterType::INTEGER); // Set and query the database. $db->setQuery($query); $duplicate = (bool) $db->loadResult(); if ($duplicate) { throw new \UnexpectedValueException(Text::_('JLIB_DATABASE_ERROR_EMAIL_INUSE')); } } return true; } } Rule/EqualsRule.php 0000644 00000005176 15173135670 0010267 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 1.7.0 */ class EqualsRule extends FormRule { /** * Method to test if two values are equal. To use this rule, the form * XML needs a validate attribute of equals and a field attribute * that is equal to the field to test against. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 1.7.0 * @throws \InvalidArgumentException * @throws \UnexpectedValueException */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { $field = (string) $element['field']; // Check that a validation field is set. if (!$field) { throw new \UnexpectedValueException(sprintf('$field empty in %s::test', \get_class($this))); } if (\is_null($form)) { throw new \InvalidArgumentException(sprintf('The value for $form must not be null in %s', \get_class($this))); } if (\is_null($input)) { throw new \InvalidArgumentException(sprintf('The value for $input must not be null in %s', \get_class($this))); } $test = $input->get($field); if (isset($group) && $group !== '') { $test = $input->get($group . '.' . $field); } // Test the two values against each other. return $value == $test; } } Rule/RulesRule.php 0000644 00000010002 15173135670 0010107 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Access\Access; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 1.7.0 */ class RulesRule extends FormRule { /** * Method to test the value. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 1.7.0 */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { // Get the possible field actions and the ones posted to validate them. $fieldActions = self::getFieldActions($element); $valueActions = self::getValueActions($value); // Make sure that all posted actions are in the list of possible actions for the field. foreach ($valueActions as $action) { if (!\in_array($action, $fieldActions)) { return false; } } return true; } /** * Method to get the list of permission action names from the form field value. * * @param mixed $value The form field value to validate. * * @return string[] A list of permission action names from the form field value. * * @since 1.7.0 */ protected function getValueActions($value) { $actions = []; // Iterate over the asset actions and add to the actions. foreach ((array) $value as $name => $rules) { $actions[] = $name; } return $actions; } /** * Method to get the list of possible permission action names for the form field. * * @param \SimpleXMLElement $element The \SimpleXMLElement object representing the `<field>` tag for the form field object. * * @return string[] A list of permission action names from the form field element definition. * * @since 1.7.0 */ protected function getFieldActions(\SimpleXMLElement $element) { $actions = []; // Initialise some field attributes. $section = $element['section'] ? (string) $element['section'] : ''; $component = $element['component'] ? (string) $element['component'] : ''; // Get the asset actions for the element. $elActions = Access::getActionsFromFile( JPATH_ADMINISTRATOR . '/components/' . $component . '/access.xml', "/access/section[@name='" . $section . "']/" ); if ($elActions) { // Iterate over the asset actions and add to the actions. foreach ($elActions as $item) { $actions[] = $item->name; } } // Iterate over the children and add to the actions. foreach ($element->children() as $el) { if ($el->getName() === 'action') { $actions[] = (string) $el['name']; } } return $actions; } } Rule/NotequalsRule.php 0000644 00000004617 15173135670 0011007 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormRule; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 1.7.0 */ class NotequalsRule extends FormRule { /** * Method to test if two values are not equal. To use this rule, the form * XML needs a validate attribute of equals and a field attribute * that is equal to the field to test against. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 1.7.0 * @throws \InvalidArgumentException * @throws \UnexpectedValueException */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { $field = (string) $element['field']; // Check that a validation field is set. if (!$field) { throw new \UnexpectedValueException(sprintf('$field empty in %s::test', \get_class($this))); } if ($input === null) { throw new \InvalidArgumentException(sprintf('The value for $input must not be null in %s', \get_class($this))); } // Test the two values against each other. if ($value != $input->get($field)) { return true; } return false; } } Rule/ModuleLayoutRule.php 0000644 00000002242 15173135670 0011447 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2021 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Rule; use Joomla\CMS\Form\FormRule; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Rule class for the Joomla Platform. * * @since 3.9.26 */ class ModuleLayoutRule extends FormRule { /** * The regular expression to use in testing a module layout field value. * * A valid module layout field value consists of * - optionally a template name with only characters, numbers, hyphens and * underscores, which can also be just "_" for layouts provided by the * module, followed by a colon. * - the base name of the layout file, not starting with a dot and with * only characters, numbers, dots and hyphens but no underscores (see * method "getInput" of the "ModuleLayout" field). * * @var string * @since 3.9.26 */ protected $regex = '^([A-Za-z0-9_-]+:)?[A-Za-z0-9-][A-Za-z0-9\.-]*$'; } FormHelper.php 0000644 00000040476 15173135670 0007343 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form; use Joomla\CMS\Filesystem\Path; use Joomla\String\Normalise; use Joomla\String\StringHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form's helper class. * Provides a storage for filesystem's paths where Form's entities reside and methods for creating those entities. * Also stores objects with entities' prototypes for further reusing. * * @since 1.7.0 */ class FormHelper { /** * Array with paths where entities(field, rule, form) can be found. * * Array's structure: * * paths: * {ENTITY_NAME}: * - /path/1 * - /path/2 * * @var array[] * @since 1.7.0 */ protected static $paths; /** * The class namespaces. * * @var array[] * @since 3.8.0 */ protected static $prefixes = ['field' => [], 'form' => [], 'rule' => [], 'filter' => []]; /** * Static array of Form's entity objects for re-use. * Prototypes for all fields and rules are here. * * Array's structure: * entities: * {ENTITY_NAME}: * {KEY}: {OBJECT} * * @var array[] * @since 1.7.0 */ protected static $entities = ['field' => [], 'form' => [], 'rule' => [], 'filter' => []]; /** * Method to load a form field object given a type. * * @param string $type The field type. * @param boolean $new Flag to toggle whether we should get a new instance of the object. * * @return FormField|boolean FormField object on success, false otherwise. * * @since 1.7.0 */ public static function loadFieldType($type, $new = true) { return self::loadType('field', $type, $new); } /** * Method to load a form rule object given a type. * * @param string $type The rule type. * @param boolean $new Flag to toggle whether we should get a new instance of the object. * * @return FormRule|boolean FormRule object on success, false otherwise. * * @since 1.7.0 */ public static function loadRuleType($type, $new = true) { return self::loadType('rule', $type, $new); } /** * Method to load a form filter object given a type. * * @param string $type The rule type. * @param boolean $new Flag to toggle whether we should get a new instance of the object. * * @return FormFilterInterface|boolean FormRule object on success, false otherwise. * * @since 4.0.0 */ public static function loadFilterType($type, $new = true) { return self::loadType('filter', $type, $new); } /** * Method to load a form entity object given a type. * Each type is loaded only once and then used as a prototype for other objects of same type. * Please, use this method only with those entities which support types (forms don't support them). * * @param string $entity The entity. * @param string $type The entity type. * @param boolean $new Flag to toggle whether we should get a new instance of the object. * * @return mixed Entity object on success, false otherwise. * * @since 1.7.0 */ protected static function loadType($entity, $type, $new = true) { // Reference to an array with current entity's type instances $types = &self::$entities[$entity]; $key = md5($type); // Return an entity object if it already exists and we don't need a new one. if (isset($types[$key]) && $new === false) { return $types[$key]; } $class = self::loadClass($entity, $type); if ($class === false) { return false; } // Instantiate a new type object. $types[$key] = new $class(); return $types[$key]; } /** * Attempt to import the FormField class file if it isn't already imported. * You can use this method outside of Form for loading a field for inheritance or composition. * * @param string $type Type of a field whose class should be loaded. * * @return string|boolean Class name on success or false otherwise. * * @since 1.7.0 */ public static function loadFieldClass($type) { return self::loadClass('field', $type); } /** * Attempt to import the FormRule class file if it isn't already imported. * You can use this method outside of Form for loading a rule for inheritance or composition. * * @param string $type Type of a rule whose class should be loaded. * * @return string|boolean Class name on success or false otherwise. * * @since 1.7.0 */ public static function loadRuleClass($type) { return self::loadClass('rule', $type); } /** * Attempt to import the FormFilter class file if it isn't already imported. * You can use this method outside of Form for loading a filter for inheritance or composition. * * @param string $type Type of a filter whose class should be loaded. * * @return string|boolean Class name on success or false otherwise. * * @since 4.0.0 */ public static function loadFilterClass($type) { return self::loadClass('filter', $type); } /** * Load a class for one of the form's entities of a particular type. * Currently, it makes sense to use this method for the "field" and "rule" entities * (but you can support more entities in your subclass). * * @param string $entity One of the form entities (field or rule). * @param string $type Type of an entity. * * @return string|boolean Class name on success or false otherwise. * * @since 1.7.0 */ protected static function loadClass($entity, $type) { // Check if there is a class in the registered namespaces foreach (self::addPrefix($entity) as $prefix) { // Treat underscores as namespace $name = Normalise::toSpaceSeparated($type); $name = str_ireplace(' ', '\\', ucwords($name)); $subPrefix = ''; if (strpos($name, '.')) { list($subPrefix, $name) = explode('.', $name); $subPrefix = ucfirst($subPrefix) . '\\'; } // Compile the classname $class = rtrim($prefix, '\\') . '\\' . $subPrefix . ucfirst($name) . ucfirst($entity); // Check if the class exists if (class_exists($class)) { return $class; } } $prefix = 'J'; if (strpos($type, '.')) { list($prefix, $type) = explode('.', $type); } $class = StringHelper::ucfirst($prefix, '_') . 'Form' . StringHelper::ucfirst($entity, '_') . StringHelper::ucfirst($type, '_'); if (class_exists($class)) { return $class; } // Get the field search path array. $paths = self::addPath($entity); // If the type is complex, add the base type to the paths. if ($pos = strpos($type, '_')) { // Add the complex type prefix to the paths. for ($i = 0, $n = \count($paths); $i < $n; $i++) { // Derive the new path. $path = $paths[$i] . '/' . strtolower(substr($type, 0, $pos)); // If the path does not exist, add it. if (!\in_array($path, $paths)) { $paths[] = $path; } } // Break off the end of the complex type. $type = substr($type, $pos + 1); } // Try to find the class file. $type = strtolower($type) . '.php'; foreach ($paths as $path) { $file = Path::find($path, $type); if (!$file) { continue; } require_once $file; if (class_exists($class)) { break; } } // Check for all if the class exists. return class_exists($class) ? $class : false; } /** * Method to add a path to the list of field include paths. * * @param string|string[] $new A path or array of paths to add. * * @return string[] The list of paths that have been added. * * @since 1.7.0 */ public static function addFieldPath($new = null) { return self::addPath('field', $new); } /** * Method to add a path to the list of form include paths. * * @param string|string[] $new A path or array of paths to add. * * @return string[] The list of paths that have been added. * * @since 1.7.0 */ public static function addFormPath($new = null) { return self::addPath('form', $new); } /** * Method to add a path to the list of rule include paths. * * @param string|string[] $new A path or array of paths to add. * * @return string[] The list of paths that have been added. * * @since 1.7.0 */ public static function addRulePath($new = null) { return self::addPath('rule', $new); } /** * Method to add a path to the list of filter include paths. * * @param string|string[] $new A path or array of paths to add. * * @return string[] The list of paths that have been added. * * @since 4.0.0 */ public static function addFilterPath($new = null) { return self::addPath('filter', $new); } /** * Method to add a path to the list of include paths for one of the form's entities. * Currently supported entities: field, rule and form. You are free to support your own in a subclass. * * @param string $entity Form's entity name for which paths will be added. * @param string|string[] $new A path or array of paths to add. * * @return string[] The list of paths that have been added. * * @since 1.7.0 */ protected static function addPath($entity, $new = null) { if (!isset(self::$paths[$entity])) { self::$paths[$entity] = []; } // Reference to an array with paths for current entity $paths = &self::$paths[$entity]; // Force the new path(s) to an array. settype($new, 'array'); // Add the new paths to the stack if not already there. foreach ($new as $path) { $path = \trim($path); if (!\in_array($path, $paths)) { \array_unshift($paths, $path); } } return $paths; } /** * Method to add a namespace prefix to the list of field lookups. * * @param string|string[] $new A namespaces or array of namespaces to add. * * @return string[] The list of namespaces that have been added. * * @since 3.8.0 */ public static function addFieldPrefix($new = null) { return self::addPrefix('field', $new); } /** * Method to add a namespace to the list of form lookups. * * @param string|string[] $new A namespace or array of namespaces to add. * * @return string[] The list of namespaces that have been added. * * @since 3.8.0 */ public static function addFormPrefix($new = null) { return self::addPrefix('form', $new); } /** * Method to add a namespace to the list of rule lookups. * * @param string|string[] $new A namespace or array of namespaces to add. * * @return string[] The list of namespaces that have been added. * * @since 3.8.0 */ public static function addRulePrefix($new = null) { return self::addPrefix('rule', $new); } /** * Method to add a namespace to the list of filter lookups. * * @param string|string[] $new A namespace or array of namespaces to add. * * @return string[] The list of namespaces that have been added. * * @since 4.0.0 */ public static function addFilterPrefix($new = null) { return self::addPrefix('filter', $new); } /** * Method to add a namespace to the list of namespaces for one of the form's entities. * Currently supported entities: field, rule and form. You are free to support your own in a subclass. * * @param string $entity Form's entity name for which paths will be added. * @param string|string[] $new A namespace or array of namespaces to add. * * @return string[] The list of namespaces that have been added. * * @since 3.8.0 */ protected static function addPrefix($entity, $new = null) { // Reference to an array with namespaces for current entity $prefixes = &self::$prefixes[$entity]; // Add the default entity's search namespace if not set. if (empty($prefixes)) { $prefixes[] = __NAMESPACE__ . '\\' . ucfirst($entity); } // Force the new namespace(s) to an array. settype($new, 'array'); // Add the new paths to the stack if not already there. foreach ($new as $prefix) { $prefix = trim($prefix); if (\in_array($prefix, $prefixes)) { continue; } array_unshift($prefixes, $prefix); } return $prefixes; } /** * Parse the show on conditions * * @param string $showOn Show on conditions. * @param string $formControl Form name. * @param string $group The dot-separated form group path. * * @return array[] Array with show on conditions. * * @since 3.7.0 */ public static function parseShowOnConditions($showOn, $formControl = null, $group = null) { // Process the showon data. if (!$showOn) { return []; } $formPath = $formControl ?: ''; if ($group) { $groups = explode('.', $group); // An empty formControl leads to invalid shown property // Use the 1st part of the group instead to avoid. if (empty($formPath) && isset($groups[0])) { $formPath = $groups[0]; array_shift($groups); } foreach ($groups as $group) { $formPath .= '[' . $group . ']'; } } $showOnData = []; $showOnParts = preg_split('#(\[AND\]|\[OR\])#', $showOn, -1, PREG_SPLIT_DELIM_CAPTURE); $op = ''; foreach ($showOnParts as $showOnPart) { if (($showOnPart === '[AND]') || $showOnPart === '[OR]') { $op = trim($showOnPart, '[]'); continue; } $compareEqual = strpos($showOnPart, '!:') === false; $showOnPartBlocks = explode(($compareEqual ? ':' : '!:'), $showOnPart, 2); $dotPos = strpos($showOnPartBlocks[0], '.'); if ($dotPos === false) { $field = $formPath ? $formPath . '[' . $showOnPartBlocks[0] . ']' : $showOnPartBlocks[0]; } else { if ($dotPos === 0) { $fieldName = substr($showOnPartBlocks[0], 1); $field = $formControl ? $formControl . '[' . $fieldName . ']' : $fieldName; } else { if ($formControl) { $field = $formControl . ('[' . str_replace('.', '][', $showOnPartBlocks[0]) . ']'); } else { $groupParts = explode('.', $showOnPartBlocks[0]); $field = array_shift($groupParts) . '[' . join('][', $groupParts) . ']'; } } } $showOnData[] = [ 'field' => $field, 'values' => explode(',', $showOnPartBlocks[1]), 'sign' => $compareEqual === true ? '=' : '!=', 'op' => $op, ]; if ($op !== '') { $op = ''; } } return $showOnData; } } FormFilterInterface.php 0000644 00000002767 15173135670 0011173 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Interface for a filter class. * * @since 4.0.0 */ interface FormFilterInterface { /** * Method to filter a field value. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return mixed The filtered value. * * @since 4.0.0 */ public function filter(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null); } FormFactory.php 0000644 00000001726 15173135670 0007526 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form; use Joomla\Database\DatabaseAwareTrait; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Default factory for creating Form objects * * @since 4.0.0 */ class FormFactory implements FormFactoryInterface { use DatabaseAwareTrait; /** * Method to get an instance of a form. * * @param string $name The name of the form. * @param array $options An array of form options. * * @return Form * * @since 4.0.0 */ public function createForm(string $name, array $options = []): Form { $form = new Form($name, $options); $form->setDatabase($this->getDatabase()); return $form; } } FormRule.php 0000644 00000006350 15173135670 0007024 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt * * Remove phpcs exception with deprecated constant JCOMPAT_UNICODE_PROPERTIES * @phpcs:disable PSR1.Files.SideEffects */ namespace Joomla\CMS\Form; \defined('JPATH_PLATFORM') or die; use Joomla\Registry\Registry; // Detect if we have full UTF-8 and unicode PCRE support. if (!\defined('JCOMPAT_UNICODE_PROPERTIES')) { /** * Flag indicating UTF-8 and PCRE support is present * * @const boolean * @since 1.6 * * @deprecated 4.0 will be removed in 6.0 * Will be removed without replacement (Also remove phpcs exception) */ \define('JCOMPAT_UNICODE_PROPERTIES', (bool) @preg_match('/\pL/u', 'a')); } /** * Form Rule class for the Joomla Platform. * * @since 1.6 */ class FormRule { /** * The regular expression to use in testing a form field value. * * @var string * @since 1.6 */ protected $regex; /** * The regular expression modifiers to use when testing a form field value. * * @var string * @since 1.6 */ protected $modifiers = ''; /** * Method to test the value. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * @param ?Registry $input An optional Registry object with the entire data set to validate against the entire form. * @param ?Form $form The form object for which the field is being tested. * * @return boolean True if the value is valid, false otherwise. * * @since 1.6 * @throws \UnexpectedValueException if rule is invalid. */ public function test(\SimpleXMLElement $element, $value, $group = null, Registry $input = null, Form $form = null) { // Check for a valid regex. if (empty($this->regex)) { throw new \UnexpectedValueException(sprintf('%s has invalid regex.', \get_class($this))); } // Detect if we have full UTF-8 and unicode PCRE support. static $unicodePropertiesSupport = null; if ($unicodePropertiesSupport === null) { $unicodePropertiesSupport = (bool) @\preg_match('/\pL/u', 'a'); } // Add unicode property support if available. if ($unicodePropertiesSupport) { $this->modifiers = (strpos($this->modifiers, 'u') !== false) ? $this->modifiers : $this->modifiers . 'u'; } // Test the value against the regular expression. if (preg_match(\chr(1) . $this->regex . \chr(1) . $this->modifiers, $value)) { return true; } return false; } } FormFactoryAwareInterface.php 0000644 00000001423 15173135670 0012321 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Interface to be implemented by classes depending on a form factory. * * @since 4.0.0 */ interface FormFactoryAwareInterface { /** * Set the form factory to use. * * @param FormFactoryInterface $factory The form factory to use. * * @return FormFactoryAwareInterface This method is chainable. * * @since 4.0.0 */ public function setFormFactory(FormFactoryInterface $factory); } Field/MeterField.php 0000644 00000013460 15173135670 0010334 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Form\FormField; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides a meter to show value in a range. * * @link https://html.spec.whatwg.org/multipage/input.html#text-(type=text)-state-and-search-state-(type=search) * @since 3.2 */ class MeterField extends FormField { /** * The form field type. * * @var string * @since 3.2 */ protected $type = 'Meter'; /** * Whether the field is active or not. * * @var boolean * @since 3.2 */ protected $active = false; /** * Whether the field is animated or not. * * @var boolean * @since 3.2 */ protected $animated = true; /** * The min value of the progress bar * * @var int * @since 4.4.0 */ protected $min = 0; /** * The max value of the progress bar * * @var int * @since 4.0.0 */ protected $max = 100; /** * The width of the progress bar * * @var string * @since 4.4.0 */ protected $width; /** * The color of the progress bar * * @var string * @since 4.4.0 */ protected $color; /** * The striped class for the progress bar * * @var boolean * @since 4.0.0 */ protected $striped; /** * Name of the layout being used to render the field * * @var string * @since 3.7 */ protected $layout = 'joomla.form.field.meter'; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'active': case 'width': case 'animated': case 'color': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'max': case 'min': $this->$name = (int) $value; break; case 'width': case 'color': $this->$name = (string) $value; break; case 'active': $value = (string) $value; $this->active = ($value === 'true' || $value === $name || $value === '1'); break; case 'animated': $value = (string) $value; $this->animated = !($value === 'false' || $value === 'off' || $value === '0'); break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { $this->width = isset($this->element['width']) ? (string) $this->element['width'] : ''; $this->color = isset($this->element['color']) ? (string) $this->element['color'] : ''; $active = (string) $this->element['active']; $this->active = ($active === 'true' || $active === 'on' || $active === '1'); $animated = (string) $this->element['animated']; $this->animated = !($animated === 'false' || $animated === 'off' || $animated === '0'); } return $return; } /** * Method to get the field input markup. * * @return string The field input markup. * * @since 3.2 */ protected function getInput() { // Trim the trailing line in the layout file return rtrim($this->getRenderer($this->layout)->render($this->getLayoutData()), PHP_EOL); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.5 */ protected function getLayoutData() { $data = parent::getLayoutData(); // Initialize some field attributes. $extraData = [ 'width' => $this->width, 'color' => $this->color, 'animated' => $this->animated, 'active' => $this->active, 'max' => $this->max, 'min' => $this->min, ]; return array_merge($data, $extraData); } } Field/ModulepositionField.php 0000644 00000012304 15173135670 0012266 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Module Position field. * * @since 1.6 */ class ModulepositionField extends TextField { /** * The form field type. * * @var string * @since 1.6 */ protected $type = 'ModulePosition'; /** * The client ID. * * @var integer * @since 3.2 */ protected $clientId; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { if ($name === 'clientId') { return $this->clientId; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'clientId': $this->clientId = (int) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $result = parent::setup($element, $value, $group); if ($result === true) { // Get the client id. $clientId = $this->element['client_id']; if (!isset($clientId)) { $clientName = $this->element['client']; if (isset($clientName)) { $client = ApplicationHelper::getClientInfo($clientName, true); $clientId = $client->id; } } if (!isset($clientId) && $this->form instanceof Form) { $clientId = $this->form->getValue('client_id'); } $this->clientId = (int) $clientId; } return $result; } /** * Method to get the field input markup. * * @return string The field input markup. * * @since 1.6 */ protected function getInput() { // Build the script. $script = []; $script[] = ' function jSelectPosition_' . $this->id . '(name) {'; $script[] = ' document.getElementById("' . $this->id . '").value = name;'; $script[] = ' jModalClose();'; $script[] = ' }'; // Add the script to the document head. Factory::getDocument()->addScriptDeclaration(implode("\n", $script)); // Setup variables for display. $html = []; $link = 'index.php?option=com_modules&view=positions&layout=modal&tmpl=component&function=jSelectPosition_' . $this->id . '&client_id=' . $this->clientId; // The current user display field. $html[] = '<div class="input-append">'; $html[] = parent::getInput() . '<a class="btn" title="' . Text::_('COM_MODULES_CHANGE_POSITION_TITLE') . '" href="' . $link . '" data-bs-toggle="modal" data-bs-target="#modulePositionModal">' . Text::_('COM_MODULES_CHANGE_POSITION_BUTTON') . '</a>'; $html[] = HTMLHelper::_( 'bootstrap.renderModal', 'modulePositionModal', [ 'url' => $link, 'title' => Text::_('COM_MODULES_CHANGE_POSITION_BUTTON'), 'height' => '100%', 'width' => '100%', 'modalWidth' => '800', 'bodyHeight' => '450', 'footer' => '<button type="button" class="btn btn-secondary" data-bs-dismiss="modal" aria-hidden="true">' . Text::_('JLIB_HTML_BEHAVIOR_CLOSE') . '</button>', ] ); $html[] = '</div>'; return implode("\n", $html); } } Field/ContentlanguageField.php 0000644 00000002030 15173135670 0012365 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\HTML\HTMLHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Provides a list of content languages * * @see \Joomla\CMS\Form\Field\LanguageField for a select list of application languages. * @since 1.6 */ class ContentlanguageField extends ListField { /** * The form field type. * * @var string * @since 1.6 */ public $type = 'ContentLanguage'; /** * Method to get the field options for content languages. * * @return object[] The options the field is going to show. * * @since 1.6 */ protected function getOptions() { return array_merge(parent::getOptions(), HTMLHelper::_('contentlanguage.existing')); } } Field/MediaField.php 0000644 00000032251 15173135670 0010276 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Form\FormField; use Joomla\CMS\Helper\MediaHelper; use Joomla\CMS\Uri\Uri; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Provides a modal media selector including upload mechanism * * @since 1.6 */ class MediaField extends FormField { /** * The form field type. * * @var string * @since 1.6 */ protected $type = 'Media'; /** * The authorField. * * @var string * @since 3.2 */ protected $authorField; /** * The asset. * * @var string * @since 3.2 */ protected $asset; /** * The link. * * @var string * @since 3.2 */ protected $link; /** * Modal width. * * @var integer * @since 3.4.5 */ protected $width; /** * Modal height. * * @var integer * @since 3.4.5 */ protected $height; /** * The preview. * * @var string * @since 3.2 */ protected $preview; /** * The directory. * * @var string * @since 3.2 */ protected $directory; /** * The previewWidth. * * @var integer * @since 3.2 */ protected $previewWidth; /** * The previewHeight. * * @var integer * @since 3.2 */ protected $previewHeight; /** * The folder. * * @var string * @since 4.3.0 */ protected $folder; /** * Comma separated types of files for Media Manager * Possible values: images,audios,videos,documents * * @var string * @since 4.0.0 */ protected $types; /** * Layout to render * * @var string * @since 3.5 */ protected $layout = 'joomla.form.field.media'; /** * The parent class of the field * * @var string * @since 4.0.0 */ protected $parentclass; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'authorField': case 'asset': case 'link': case 'width': case 'height': case 'preview': case 'directory': case 'previewWidth': case 'previewHeight': case 'folder': case 'types': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'authorField': case 'asset': case 'link': case 'preview': case 'directory': case 'folder': case 'types': $this->$name = (string) $value; break; case 'height': case 'previewWidth': case 'previewHeight': case 'width': $this->$name = (int) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $result = parent::setup($element, $value, $group); if ($result === true) { $assetField = $this->element['asset_field'] ? (string) $this->element['asset_field'] : 'asset_id'; $this->authorField = $this->element['created_by_field'] ? (string) $this->element['created_by_field'] : 'created_by'; $this->asset = $this->form->getValue($assetField) ?: (string) $this->element['asset_id']; $this->link = (string) $this->element['link']; $this->width = isset($this->element['width']) ? (int) $this->element['width'] : 800; $this->height = isset($this->element['height']) ? (int) $this->element['height'] : 500; $this->preview = (string) $this->element['preview']; $this->directory = (string) $this->element['directory']; $this->previewWidth = isset($this->element['preview_width']) ? (int) $this->element['preview_width'] : 200; $this->previewHeight = isset($this->element['preview_height']) ? (int) $this->element['preview_height'] : 200; $this->types = isset($this->element['types']) ? (string) $this->element['types'] : 'images'; } return $result; } /** * Method to get the field input markup for a media selector. * Use attributes to identify specific created_by and asset_id fields * * @return string The field input markup. * * @since 1.6 */ protected function getInput() { if (empty($this->layout)) { throw new \UnexpectedValueException(sprintf('%s has no layout assigned.', $this->name)); } return $this->getRenderer($this->layout)->render($this->getLayoutData()); } /** * Get the data that is going to be passed to the layout * * @return array */ public function getLayoutData() { // Get the basic field data $data = parent::getLayoutData(); $asset = $this->asset; if ($asset === '') { $asset = Factory::getApplication()->getInput()->get('option'); } // Value in new format such as images/headers/blue-flower.jpg#joomlaImage://local-images/headers/blue-flower.jpg?width=700&height=180 if ($this->value && strpos($this->value, '#') !== false) { $uri = new Uri(explode('#', $this->value)[1]); $adapter = $uri->getHost(); $path = $uri->getPath(); // Remove filename from stored path to get the path to the folder which file is stored $pos = strrpos($path, '/'); if ($pos !== false) { $path = substr($path, 0, $pos); } if ($path === '') { $path = '/'; } $this->folder = $adapter . ':' . $path; } elseif ($this->value && is_file(JPATH_ROOT . '/' . $this->value)) { /** * Local image, for example images/sampledata/cassiopeia/nasa2-640.jpg. We need to validate and make sure * the top level folder is one of the directories configured in the filesystem local plugin to avoid an error * message being displayed when users click on Select button to select a new image. */ $paths = explode('/', Path::clean($this->value, '/')); // Remove filename from $paths array array_pop($paths); if (MediaHelper::isValidLocalDirectory($paths[0])) { $adapterName = array_shift($paths); $this->folder = 'local-' . $adapterName . ':/' . implode('/', $paths); } } elseif ($this->directory && is_dir(JPATH_ROOT . '/' . ComponentHelper::getParams('com_media')->get('image_path', 'images') . '/' . $this->directory)) { /** * This is the case where a folder is configured in directory attribute of the form field. The directory needs * to be a relative folder of the folder configured in Path to Images Folder config option of Media component. * Same with an already stored local image above, we need to validate and make sure the top level folder is one of the * directories configured in the filesystem local plugin. */ $path = ComponentHelper::getParams('com_media')->get('image_path', 'images') . '/' . $this->directory; $paths = explode('/', Path::clean($path, '/')); if (MediaHelper::isValidLocalDirectory($paths[0])) { $adapterName = array_shift($paths); $this->folder = 'local-' . $adapterName . ':/' . implode('/', $paths); } } elseif ($this->directory && strpos($this->directory, ':')) { /** * Directory contains adapter information and path, for example via programming or directly defined in xml * via directory attribute */ $this->folder = $this->directory; } else { $this->folder = ''; } $mediaTypes = array_map('trim', explode(',', $this->types)); $types = []; $imagesExt = array_map( 'trim', explode( ',', ComponentHelper::getParams('com_media')->get( 'image_extensions', 'bmp,gif,jpg,jpeg,png,webp' ) ) ); $audiosExt = array_map( 'trim', explode( ',', ComponentHelper::getParams('com_media')->get( 'audio_extensions', 'mp3,m4a,mp4a,ogg' ) ) ); $videosExt = array_map( 'trim', explode( ',', ComponentHelper::getParams('com_media')->get( 'video_extensions', 'mp4,mp4v,mpeg,mov,webm' ) ) ); $documentsExt = array_map( 'trim', explode( ',', ComponentHelper::getParams('com_media')->get( 'doc_extensions', 'doc,odg,odp,ods,odt,pdf,ppt,txt,xcf,xls,csv' ) ) ); $imagesAllowedExt = []; $audiosAllowedExt = []; $videosAllowedExt = []; $documentsAllowedExt = []; // Cleanup the media types array_map( function ($mediaType) use (&$types, &$imagesAllowedExt, &$audiosAllowedExt, &$videosAllowedExt, &$documentsAllowedExt, $imagesExt, $audiosExt, $videosExt, $documentsExt) { switch ($mediaType) { case 'images': $types[] = '0'; $imagesAllowedExt = $imagesExt; break; case 'audios': $types[] = '1'; $audiosAllowedExt = $audiosExt; break; case 'videos': $types[] = '2'; $videosAllowedExt = $videosExt; break; case 'documents': $types[] = '3'; $documentsAllowedExt = $documentsExt; break; default: break; } }, $mediaTypes ); sort($types); $extraData = [ 'asset' => $asset, 'authorField' => $this->authorField, 'authorId' => $this->form->getValue($this->authorField), 'folder' => $this->folder, 'link' => $this->link, 'preview' => $this->preview, 'previewHeight' => $this->previewHeight, 'previewWidth' => $this->previewWidth, 'mediaTypes' => implode(',', $types), 'imagesExt' => $imagesExt, 'audiosExt' => $audiosExt, 'videosExt' => $videosExt, 'documentsExt' => $documentsExt, 'imagesAllowedExt' => $imagesAllowedExt, 'audiosAllowedExt' => $audiosAllowedExt, 'videosAllowedExt' => $videosAllowedExt, 'documentsAllowedExt' => $documentsAllowedExt, ]; return array_merge($data, $extraData); } } Field/ModulelayoutField.php 0000644 00000017555 15173135670 0011754 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormField; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\Database\ParameterType; use Joomla\Filesystem\Folder; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field to display a list of the layouts for module display from the module or template overrides. * * @since 1.6 */ class ModulelayoutField extends FormField { /** * The form field type. * * @var string * @since 1.6 */ protected $type = 'ModuleLayout'; /** * Method to get the field input for module layouts. * * @return string The field input. * * @since 1.6 */ protected function getInput() { // Get the client id. $clientId = $this->element['client_id']; if ($clientId === null && $this->form instanceof Form) { $clientId = $this->form->getValue('client_id'); } $clientId = (int) $clientId; $client = ApplicationHelper::getClientInfo($clientId); // Get the module. $module = (string) $this->element['module']; if (empty($module) && ($this->form instanceof Form)) { $module = $this->form->getValue('module'); } $module = preg_replace('#\W#', '', $module); // Get the template. $template = (string) $this->element['template']; $template = preg_replace('#\W#', '', $template); // Get the style. $template_style_id = 0; if ($this->form instanceof Form) { $template_style_id = $this->form->getValue('template_style_id', null, 0); $template_style_id = (int) preg_replace('#\W#', '', $template_style_id); } // If an extension and view are present build the options. if ($module && $client) { // Load language file $lang = Factory::getLanguage(); $lang->load($module . '.sys', $client->path) || $lang->load($module . '.sys', $client->path . '/modules/' . $module); // Get the database object and a new query object. $db = $this->getDatabase(); $query = $db->getQuery(true); // Build the query. $query->select( [ $db->quoteName('element'), $db->quoteName('name'), ] ) ->from($db->quoteName('#__extensions', 'e')) ->where( [ $db->quoteName('e.client_id') . ' = :clientId', $db->quoteName('e.type') . ' = ' . $db->quote('template'), $db->quoteName('e.enabled') . ' = 1', ] ) ->bind(':clientId', $clientId, ParameterType::INTEGER); if ($template) { $query->where($db->quoteName('e.element') . ' = :template') ->bind(':template', $template); } if ($template_style_id) { $query->join('LEFT', $db->quoteName('#__template_styles', 's'), $db->quoteName('s.template') . ' = ' . $db->quoteName('e.element')) ->where($db->quoteName('s.id') . ' = :style') ->bind(':style', $template_style_id, ParameterType::INTEGER); } // Set the query and load the templates. $db->setQuery($query); $templates = $db->loadObjectList('element'); // Build the search paths for module layouts. $module_path = Path::clean($client->path . '/modules/' . $module . '/tmpl'); // Prepare array of component layouts $module_layouts = []; // Prepare the grouped list $groups = []; // Add the layout options from the module path. if (is_dir($module_path) && ($module_layouts = Folder::files($module_path, '^[^_]*\.php$'))) { // Create the group for the module $groups['_'] = []; $groups['_']['id'] = $this->id . '__'; $groups['_']['text'] = Text::sprintf('JOPTION_FROM_MODULE'); $groups['_']['items'] = []; foreach ($module_layouts as $file) { // Add an option to the module group $value = basename($file, '.php'); $text = $lang->hasKey($key = strtoupper($module . '_LAYOUT_' . $value)) ? Text::_($key) : $value; $groups['_']['items'][] = HTMLHelper::_('select.option', '_:' . $value, $text); } } // Loop on all templates if ($templates) { foreach ($templates as $template) { // Load language file $lang->load('tpl_' . $template->element . '.sys', $client->path) || $lang->load('tpl_' . $template->element . '.sys', $client->path . '/templates/' . $template->element); $template_path = Path::clean($client->path . '/templates/' . $template->element . '/html/' . $module); // Add the layout options from the template path. if (is_dir($template_path) && ($files = Folder::files($template_path, '^[^_]*\.php$'))) { foreach ($files as $i => $file) { // Remove layout that already exist in component ones if (\in_array($file, $module_layouts)) { unset($files[$i]); } } if (\count($files)) { // Create the group for the template $groups[$template->element] = []; $groups[$template->element]['id'] = $this->id . '_' . $template->element; $groups[$template->element]['text'] = Text::sprintf('JOPTION_FROM_TEMPLATE', $template->name); $groups[$template->element]['items'] = []; foreach ($files as $file) { // Add an option to the template group $value = basename($file, '.php'); $text = $lang->hasKey($key = strtoupper('TPL_' . $template->element . '_' . $module . '_LAYOUT_' . $value)) ? Text::_($key) : $value; $groups[$template->element]['items'][] = HTMLHelper::_('select.option', $template->element . ':' . $value, $text); } } } } } // Compute attributes for the grouped list $attr = $this->element['size'] ? ' size="' . (int) $this->element['size'] . '"' : ''; $attr .= $this->element['class'] ? ' class="' . (string) $this->element['class'] . '"' : ''; // Prepare HTML code $html = []; // Compute the current selected values $selected = [$this->value]; // Add a grouped list $html[] = HTMLHelper::_( 'select.groupedlist', $groups, $this->name, ['id' => $this->id, 'group.id' => 'id', 'list.attr' => $attr, 'list.select' => $selected] ); return implode($html); } else { return ''; } } } Field/ImagelistField.php 0000644 00000002136 15173135670 0011174 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Supports an HTML select list of image * * @since 1.7.0 */ class ImagelistField extends FilelistField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Imagelist'; /** * Method to get the list of images field options. * Use the filter attribute to specify allowable file extensions. * * @return object[] The field option objects. * * @since 1.7.0 */ protected function getOptions() { // Define the image file type filter. $this->fileFilter = '\.png$|\.gif$|\.jpg$|\.bmp$|\.ico$|\.jpeg$|\.psd$|\.eps$|\.avif$|\.webp$|\.heic$|\.wp2$'; // Get the field options. return parent::getOptions(); } } Field/SqlField.php 0000644 00000022704 15173135670 0010020 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\Database\Exception\ExecutionFailureException; use Joomla\Database\QueryInterface; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Supports a custom SQL select list * * @since 1.7.0 */ class SqlField extends ListField { /** * The form field type. * * @var string * @since 1.7.0 */ public $type = 'SQL'; /** * The keyField. * * @var string * @since 3.2 */ protected $keyField; /** * The valueField. * * @var string * @since 3.2 */ protected $valueField; /** * The translate. * * @var boolean * @since 3.2 */ protected $translate = false; /** * The header. * * @var mixed * @since 4.3.0 */ protected $header; /** * The query. * * @var string * @since 3.2 */ protected $query; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'keyField': case 'valueField': case 'translate': case 'header': case 'query': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'translate': $this->$name = (bool) $value; break; case 'keyField': case 'valueField': case 'header': case 'query': $this->$name = (string) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { // Check if its using the old way $this->query = (string) $this->element['query']; if (empty($this->query)) { // Get the query from the form $query = []; $defaults = []; $sql_select = (string) $this->element['sql_select']; $sql_from = (string) $this->element['sql_from']; if ($sql_select && $sql_from) { $query['select'] = $sql_select; $query['from'] = $sql_from; $query['join'] = (string) $this->element['sql_join']; $query['where'] = (string) $this->element['sql_where']; $query['group'] = (string) $this->element['sql_group']; $query['order'] = (string) $this->element['sql_order']; // Get the filters $filters = isset($this->element['sql_filter']) ? explode(',', $this->element['sql_filter']) : []; // Get the default value for query if empty foreach ($filters as $filter) { $name = "sql_default_{$filter}"; $attrib = (string) $this->element[$name]; if (!empty($attrib)) { $defaults[$filter] = $attrib; } } // Process the query $this->query = $this->processQuery($query, $filters, $defaults); } } $this->keyField = (string) $this->element['key_field'] ?: 'value'; $this->valueField = (string) $this->element['value_field'] ?: (string) $this->element['name']; $this->translate = (string) $this->element['translate'] ?: false; $this->header = (string) $this->element['header'] ?: false; } return $return; } /** * Method to process the query from form. * * @param string[] $conditions The conditions from the form. * @param string[] $filters The columns to filter. * @param string[] $defaults The defaults value to set if condition is empty. * * @return QueryInterface The query object. * * @since 3.5 */ protected function processQuery($conditions, $filters, $defaults) { // Get the database object. $db = $this->getDatabase(); // Get the query object $query = $db->getQuery(true); // Select fields $query->select($conditions['select']); // From selected table $query->from($conditions['from']); // Join over the groups if (!empty($conditions['join'])) { $query->join('LEFT', $conditions['join']); } // Where condition if (!empty($conditions['where'])) { $query->where($conditions['where']); } // Group by if (!empty($conditions['group'])) { $query->group($conditions['group']); } // Process the filters if (\is_array($filters)) { // @TODO: Loading the filtering value from the request need to be deprecated. $html_filters = $this->context ? Factory::getApplication()->getUserStateFromRequest($this->context . '.filter', 'filter', [], 'array') : false; $form = $this->form; foreach ($filters as $k => $value) { // Get the filter value from the linked filter field $filterFieldValue = $form->getValue($value, $this->group); if ($html_filters && !empty($html_filters[$value])) { $escape = $db->quote($db->escape($html_filters[$value]), false); $query->where("{$value} = {$escape}"); } elseif ($filterFieldValue !== null) { $escape = $db->quote($db->escape($filterFieldValue), false); $query->where("{$value} = {$escape}"); } elseif (!empty($defaults[$value])) { $escape = $db->quote($db->escape($defaults[$value]), false); $query->where("{$value} = {$escape}"); } } } // Add order to query if (!empty($conditions['order'])) { $query->order($conditions['order']); } return $query; } /** * Method to get the custom field options. * Use the query attribute to supply a query to generate the list. * * @return object[] The field option objects. * * @since 1.7.0 */ protected function getOptions() { $options = []; // Initialize some field attributes. $key = $this->keyField; $value = $this->valueField; $header = $this->header; if ($this->query) { // Get the database object. $db = $this->getDatabase(); // Set the query and get the result list. $db->setQuery($this->query); try { $items = $db->loadObjectList(); } catch (ExecutionFailureException $e) { Factory::getApplication()->enqueueMessage(Text::_('JERROR_AN_ERROR_HAS_OCCURRED'), 'error'); } } // Add header. if (!empty($header)) { $header_title = Text::_($header); $options[] = HTMLHelper::_('select.option', '', $header_title); } // Build the field options. if (!empty($items)) { foreach ($items as $item) { if ($this->translate == true) { $options[] = HTMLHelper::_('select.option', $item->$key, Text::_($item->$value)); } else { $options[] = HTMLHelper::_('select.option', $item->$key, $item->$value); } } } // Merge any additional options in the XML definition. $options = array_merge(parent::getOptions(), $options); return $options; } } Field/WorkflowComponentSectionsField.php 0000644 00000003353 15173135670 0014465 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Workflow\WorkflowServiceInterface; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Framework. * * @since 4.0.0 */ class WorkflowComponentSectionsField extends ComponentsField { /** * The form field type. * * @var string * @since 4.0.0 */ protected $type = 'WorkflowComponentSections'; /** * Method to get a list of options for a list input. * * @return object[] An array of JHtml options. * * @since 4.0.0 */ protected function getOptions() { $app = Factory::getApplication(); $items = parent::getOptions(); $options = []; $options[] = HTMLHelper::_('select.option', ' ', Text::_('JNONE')); foreach ($items as $item) { if (substr($item->value, 0, 4) !== 'com_') { continue; } $component = $app->bootComponent($item->value); if (!($component instanceof WorkflowServiceInterface)) { continue; } foreach ($component->getWorkflowContexts() as $extension => $text) { $options[] = HTMLHelper::_('select.option', $extension, Text::sprintf('JWORKFLOW_FIELD_COMPONENT_SECTIONS_TEXT', $item->text, $text)); } } return $options; } } Field/WorkflowstageField.php 0000644 00000011660 15173135670 0012116 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Workflow Stages field. * * @since 4.0.0 */ class WorkflowstageField extends GroupedlistField { /** * The form field type. * * @var string * @since 4.0.0 */ protected $type = 'Workflowstage'; /** * The component and section separated by ".". * * @var string * @since 4.0.0 */ protected $extension = ''; /** * Show only the stages which has an item attached * * @var boolean * @since 4.0.0 */ protected $activeonly = false; /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @since 4.0.0 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $result = parent::setup($element, $value, $group); if ($result) { if (\strlen($element['extension'])) { $this->extension = (string) $element['extension']; } else { $this->extension = Factory::getApplication()->getInput()->getCmd('extension'); } if ((string) $element['activeonly'] === '1' || (string) $element['activeonly'] === 'true') { $this->activeonly = true; } } return $result; } /** * Method to get the field option groups. * * @return array[] The field option objects as a nested array in groups. * * @since 4.0.0 * @throws \UnexpectedValueException */ protected function getGroups() { $db = $this->getDatabase(); $query = $db->getQuery(true); // Select distinct stages for existing articles $query ->select( [ 'DISTINCT ' . $db->quoteName('ws.id', 'workflow_stage_id'), $db->quoteName('ws.title', 'workflow_stage_title'), $db->quoteName('w.title', 'workflow_title'), $db->quoteName('w.id', 'workflow_id'), $db->quoteName('w.ordering', 'ordering'), $db->quoteName('ws.ordering', 'workflow_stage_ordering'), ] ) ->from($db->quoteName('#__workflow_stages', 'ws')) ->from($db->quoteName('#__workflows', 'w')) ->where( [ $db->quoteName('ws.workflow_id') . ' = ' . $db->quoteName('w.id'), $db->quoteName('w.extension') . ' = :extension', ] ) ->bind(':extension', $this->extension) ->order( [ $db->quoteName('w.ordering'), $db->quoteName('ws.ordering'), ] ); if ($this->activeonly) { $query ->from($db->quoteName('#__workflow_associations', 'wa')) ->where( [ $db->quoteName('wa.stage_id') . ' = ' . $db->quoteName('ws.id'), $db->quoteName('wa.extension') . ' = :associationExtension', ] ) ->bind(':associationExtension', $this->extension); } $stages = $db->setQuery($query)->loadObjectList(); $workflowStages = []; // Grouping the stages by workflow foreach ($stages as $stage) { // Using workflow ID to differentiate workflows having same title $workflowStageKey = Text::_($stage->workflow_title) . ' (' . $stage->workflow_id . ')'; if (!\array_key_exists($workflowStageKey, $workflowStages)) { $workflowStages[$workflowStageKey] = []; } $workflowStages[$workflowStageKey][] = HTMLHelper::_('select.option', $stage->workflow_stage_id, Text::_($stage->workflow_stage_title)); } // Merge any additional options in the XML definition. return array_merge(parent::getGroups(), $workflowStages); } } Field/DatabaseconnectionField.php 0000644 00000004633 15173135670 0013046 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Language\Text; use Joomla\Database\DatabaseDriver; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides a list of available database connections, optionally limiting to * a given list. * * @see DatabaseDriver * @since 1.7.3 */ class DatabaseconnectionField extends ListField { /** * The form field type. * * @var string * @since 1.7.3 */ protected $type = 'Databaseconnection'; /** * Method to get the list of database options. * * This method produces a drop down list of available databases supported * by DatabaseDriver classes that are also supported by the application. * * @return array The field option objects. * * @since 1.7.3 * @see DatabaseDriver::getConnectors() */ protected function getOptions() { $options = []; // This gets the connectors available in the platform and supported by the server. $available = array_map('strtolower', DatabaseDriver::getConnectors()); /** * This gets the list of database types supported by the application. * This should be entered in the form definition as a comma separated list. * If no supported databases are listed, it is assumed all available databases * are supported. */ $supported = $this->element['supported']; if (!empty($supported)) { $supported = explode(',', $supported); foreach ($supported as $support) { if (\in_array($support, $available)) { $options[$support] = Text::_(ucfirst($support)); } } } else { foreach ($available as $support) { $options[$support] = Text::_(ucfirst($support)); } } // This will come into play if an application is installed that requires // a database that is not available on the server. if (empty($options)) { $options[''] = Text::_('JNONE'); } return $options; } } Field/EmailField.php 0000644 00000003262 15173135670 0010306 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides and input field for email addresses * * @link https://html.spec.whatwg.org/multipage/input.html#email-state-(type=email) * @see \Joomla\CMS\Form\Rule\EmailRule * @since 1.7.0 */ class EmailField extends TextField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Email'; /** * Name of the layout being used to render the field * * @var string * @since 3.7 */ protected $layout = 'joomla.form.field.email'; /** * Method to get the field input markup for email addresses. * * @return string The field input markup. * * @since 1.7.0 */ protected function getInput() { // Trim the trailing line in the layout file return rtrim($this->getRenderer($this->layout)->render($this->getLayoutData()), PHP_EOL); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.5 */ protected function getLayoutData() { $data = parent::getLayoutData(); $extraData = [ 'maxLength' => $this->maxLength, 'multiple' => $this->multiple, ]; return array_merge($data, $extraData); } } Field/RedirectStatusField.php 0000644 00000001555 15173135670 0012227 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Redirect Status field. * * @since 3.8.0 */ class RedirectStatusField extends PredefinedlistField { /** * The form field type. * * @var string * @since 3.8.0 */ public $type = 'Redirect_Status'; /** * Available statuses * * @var string[] * @since 3.8.0 */ protected $predefinedOptions = [ '-2' => 'JTRASHED', '0' => 'JDISABLED', '1' => 'JENABLED', '2' => 'JARCHIVED', '*' => 'JALL', ]; } Field/HeadertagField.php 0000644 00000002211 15173135670 0011134 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\HTML\HTMLHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla! CMS. * * @since 3.0 */ class HeadertagField extends ListField { /** * The form field type. * * @var string * @since 3.0 */ protected $type = 'HeaderTag'; /** * Method to get the field options. * * @return object[] The field option objects. * * @since 3.0 */ protected function getOptions() { $options = []; $tags = ['h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'div']; // Create one new option object for each tag foreach ($tags as $tag) { $tmp = HTMLHelper::_('select.option', $tag, $tag); $options[] = $tmp; } reset($options); return $options; } } Field/RulesField.php 0000644 00000022714 15173135670 0010354 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Access\Access; use Joomla\CMS\Access\Rules; use Joomla\CMS\Form\FormField; use Joomla\CMS\Helper\UserGroupsHelper; use Joomla\Database\ParameterType; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Field for assigning permissions to groups for a given asset * * @see JAccess * @since 1.7.0 */ class RulesField extends FormField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Rules'; /** * Name of the layout being used to render the field * * @var string * @since 4.0.0 */ protected $layout = 'joomla.form.field.rules'; /** * The section. * * @var string * @since 3.2 */ protected $section; /** * The component. * * @var string * @since 3.2 */ protected $component; /** * The assetField. * * @var string * @since 3.2 */ protected $assetField; /** * The flag which indicates if it is the global config * * @var bool * @since 4.3.0 */ protected $isGlobalConfig; /** * The asset rules * * @var Rules * @since 4.3.0 */ protected $assetRules; /** * The actions * * @var object[] * @since 4.3.0 */ protected $actions; /** * The groups * * @var object[] * @since 4.3.0 */ protected $groups; /** * The asset Id * * @var int * @since 4.3.0 */ protected $assetId; /** * The parent asset Id * * @var int * @since 4.3.0 */ protected $parentAssetId; /** * The flag to indicate that it is a new item * * @var bool * @since 4.3.0 */ protected $newItem; /** * The parent class of the field * * @var string * @since 4.0.0 */ protected $parentclass; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'section': case 'component': case 'assetField': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'section': case 'component': case 'assetField': $this->$name = (string) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { $this->section = $this->element['section'] ? (string) $this->element['section'] : ''; $this->component = $this->element['component'] ? (string) $this->element['component'] : ''; $this->assetField = $this->element['asset_field'] ? (string) $this->element['asset_field'] : 'asset_id'; } return $return; } /** * Method to get the field input markup for Access Control Lists. * Optionally can be associated with a specific component and section. * * @return string The field input markup. * * @since 1.7.0 * @todo: Add access check. */ protected function getInput() { // Initialise some field attributes. $section = $this->section; $assetField = $this->assetField; $component = empty($this->component) ? 'root.1' : $this->component; // Current view is global config? $this->isGlobalConfig = $component === 'root.1'; // Get the actions for the asset. $this->actions = Access::getActionsFromFile( JPATH_ADMINISTRATOR . '/components/' . $component . '/access.xml', "/access/section[@name='" . $section . "']/" ); if ($this->actions === false) { $this->actions = []; } // Iterate over the children and add to the actions. foreach ($this->element->children() as $el) { if ($el->getName() === 'action') { $this->actions[] = (object) [ 'name' => (string) $el['name'], 'title' => (string) $el['title'], 'description' => (string) $el['description'], ]; } } // Get the asset id. // Note that for global configuration, com_config injects asset_id = 1 into the form. $this->assetId = (int) $this->form->getValue($assetField); $this->newItem = empty($this->assetId) && $this->isGlobalConfig === false && $section !== 'component'; // If the asset id is empty (component or new item). if (empty($this->assetId)) { // Get the component asset id as fallback. $db = $this->getDatabase(); $query = $db->getQuery(true) ->select($db->quoteName('id')) ->from($db->quoteName('#__assets')) ->where($db->quoteName('name') . ' = :component') ->bind(':component', $component); $db->setQuery($query); $this->assetId = (int) $db->loadResult(); /** * @todo: incorrect info * When creating a new item (not saving) it uses the calculated permissions from the component (item <-> component <-> global config). * But if we have a section too (item <-> section(s) <-> component <-> global config) this is not correct. * Also, currently it uses the component permission, but should use the calculated permissions for achild of the component/section. */ } // If not in global config we need the parent_id asset to calculate permissions. if (!$this->isGlobalConfig) { // In this case we need to get the component rules too. $db = $this->getDatabase(); $query = $db->getQuery(true) ->select($db->quoteName('parent_id')) ->from($db->quoteName('#__assets')) ->where($db->quoteName('id') . ' = :assetId') ->bind(':assetId', $this->assetId, ParameterType::INTEGER); $db->setQuery($query); $this->parentAssetId = (int) $db->loadResult(); } // Get the rules for just this asset (non-recursive). $this->assetRules = Access::getAssetRules($this->assetId, false, false); // Get the available user groups. $this->groups = $this->getUserGroups(); // Trim the trailing line in the layout file return trim($this->getRenderer($this->layout)->render($this->getLayoutData())); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 4.0.0 */ protected function getLayoutData() { $data = parent::getLayoutData(); $extraData = [ 'groups' => $this->groups, 'section' => $this->section, 'actions' => $this->actions, 'assetId' => $this->assetId, 'newItem' => $this->newItem, 'assetRules' => $this->assetRules, 'isGlobalConfig' => $this->isGlobalConfig, 'parentAssetId' => $this->parentAssetId, 'component' => $this->component, ]; return array_merge($data, $extraData); } /** * Get a list of the user groups. * * @return object[] * * @since 1.7.0 */ protected function getUserGroups() { $options = UserGroupsHelper::getInstance()->getAll(); foreach ($options as &$option) { $option->value = $option->id; $option->text = $option->title; } return array_values($options); } } Field/LanguageField.php 0000644 00000005130 15173135670 0010776 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Language\LanguageHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Supports a list of installed application languages * * @see \Joomla\CMS\Form\Field\ContentlanguageField for a select list of content languages. * @since 1.7.0 */ class LanguageField extends ListField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Language'; /** * Method to get the field options. * * @return object[] The field option objects. * * @since 1.7.0 */ protected function getOptions() { // Initialize some field attributes. $client = (string) $this->element['client']; if ($client !== 'site' && $client !== 'administrator') { $client = 'site'; } // Make sure the languages are sorted base on locale instead of random sorting $languages = LanguageHelper::createLanguageList($this->value, \constant('JPATH_' . strtoupper($client)), true, true); if (\count($languages) > 1) { usort( $languages, function ($a, $b) { return strcmp($a['value'], $b['value']); } ); } // Merge any additional options in the XML definition. $options = array_merge( parent::getOptions(), $languages ); // Set the default value active language $langParams = ComponentHelper::getParams('com_languages'); switch ((string) $this->value) { case 'site': case 'frontend': case '0': $this->value = $langParams->get('site', 'en-GB'); break; case 'admin': case 'administrator': case 'backend': case '1': $this->value = $langParams->get('administrator', 'en-GB'); break; case 'active': case 'auto': $lang = Factory::getLanguage(); $this->value = $lang->getTag(); break; default: break; } return $options; } } Field/AuthorField.php 0000644 00000004167 15173135670 0010526 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field to load a list of content authors * * @since 3.2 */ class AuthorField extends ListField { /** * The form field type. * * @var string * @since 3.2 */ public $type = 'Author'; /** * Cached array of the category items. * * @var array[] * @since 3.2 */ protected static $options = []; /** * Method to get the options to populate list * * @return object[] The field option objects. * * @since 3.2 */ protected function getOptions() { // Accepted modifiers $hash = md5($this->element); if (!isset(static::$options[$hash])) { static::$options[$hash] = parent::getOptions(); $db = $this->getDatabase(); // Construct the query $query = $db->getQuery(true) ->select( [ $db->quoteName('u.id', 'value'), $db->quoteName('u.name', 'text'), ] ) ->from($db->quoteName('#__users', 'u')) ->join('INNER', $db->quoteName('#__content', 'c'), $db->quoteName('c.created_by') . ' = ' . $db->quoteName('u.id')) ->group( [ $db->quoteName('u.id'), $db->quoteName('u.name'), ] ) ->order($db->quoteName('u.name')); // Setup the query $db->setQuery($query); // Return the result if ($options = $db->loadObjectList()) { static::$options[$hash] = array_merge(static::$options[$hash], $options); } } return static::$options[$hash]; } } Field/AccessiblemediaField.php 0000644 00000013760 15173135670 0012320 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2020 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * The Field to load the form inside current form * * @since 4.0.0 */ class AccessiblemediaField extends SubformField { /** * The form field type. * * @var string * @since 4.0.0 */ protected $type = 'Accessiblemedia'; /** * The preview. * * @var string * @since 4.0.0 */ protected $preview; /** * The directory. * * @var string * @since 4.0.0 */ protected $directory; /** * The previewWidth. * * @var integer * @since 4.0.0 */ protected $previewWidth; /** * The previewHeight. * * @var integer * @since 4.0.0 */ protected $previewHeight; /** * Layout to render * * @var string * @since 4.0.0 */ protected $layout; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 4.0.0 */ public function __get($name) { switch ($name) { case 'directory': case 'preview': case 'previewHeight': case 'previewWidth': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 4.0.0 */ public function __set($name, $value) { switch ($name) { case 'directory': case 'preview': $this->$name = (string) $value; break; case 'previewHeight': case 'previewWidth': $this->$name = (int) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the <field /> tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. * * @return boolean True on success. * * @since 4.0.0 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { /** * When you have subforms which are not repeatable (i.e. a subform custom field with the * repeat attribute set to 0) you get an array here since the data comes from decoding the * JSON into an associative array, including the media subfield's data. * * However, this method expects an object or a string, not an array. Typecasting the array * to an object solves the data format discrepancy. */ $value = is_array($value) ? (object) $value : $value; /** * If the value is not a string, it is * most likely within a custom field of type subform * and the value is a stdClass with properties * imagefile and alt_text. So it is fine. */ if (\is_string($value)) { json_decode($value); // Check if value is a valid JSON string. if ($value !== '' && json_last_error() !== JSON_ERROR_NONE) { /** * If the value is not empty and is not a valid JSON string, * it is most likely a custom field created in Joomla 3 and * the value is a string that contains the file name. */ if (is_file(JPATH_ROOT . '/' . $value)) { $value = '{"imagefile":"' . $value . '","alt_text":""}'; } else { $value = ''; } } } elseif ( !is_object($value) || !property_exists($value, 'imagefile') || !property_exists($value, 'alt_text') ) { return false; } if (!parent::setup($element, $value, $group)) { return false; } $this->directory = (string) $this->element['directory']; $this->preview = (string) $this->element['preview']; $this->previewHeight = isset($this->element['preview_height']) ? (int) $this->element['preview_height'] : 200; $this->previewWidth = isset($this->element['preview_width']) ? (int) $this->element['preview_width'] : 200; $xml = <<<XML <?xml version="1.0" encoding="utf-8"?> <form> <fieldset name="accessiblemedia" label="JLIB_FORM_FIELD_PARAM_ACCESSIBLEMEDIA_LABEL" > <field name="imagefile" type="media" label="JLIB_FORM_FIELD_PARAM_ACCESSIBLEMEDIA_PARAMS_IMAGEFILE_LABEL" directory="$this->directory" preview="$this->preview" preview_width="$this->previewWidth" preview_height="$this->previewHeight" schemes="http,https,ftp,ftps,data,file" validate="url" relative="true" /> <field name="alt_text" type="text" label="JLIB_FORM_FIELD_PARAM_ACCESSIBLEMEDIA_PARAMS_ALT_TEXT_LABEL" /> <field name="alt_empty" type="checkbox" label="JLIB_FORM_FIELD_PARAM_ACCESSIBLEMEDIA_PARAMS_ALT_EMPTY_LABEL" description="JLIB_FORM_FIELD_PARAM_ACCESSIBLEMEDIA_PARAMS_ALT_EMPTY_DESC" /> </fieldset> </form> XML; $this->formsource = $xml; $this->layout = 'joomla.form.field.media.accessiblemedia'; return true; } } Field/TagField.php 0000644 00000023404 15173135670 0007772 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Helper\TagsHelper; use Joomla\CMS\Language\Multilanguage; use Joomla\Database\ParameterType; use Joomla\Utilities\ArrayHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * List of Tags field. * * @since 3.1 */ class TagField extends ListField { /** * A flexible tag list that respects access controls * * @var string * @since 3.1 */ public $type = 'Tag'; /** * Flag to work with nested tag field * * @var boolean * @since 3.1 */ public $isNested = null; /** * com_tags parameters * * @var \Joomla\Registry\Registry * @since 3.1 */ protected $comParams = null; /** * Name of the layout being used to render the field * * @var string * @since 4.0.0 */ protected $layout = 'joomla.form.field.tag'; /** * Constructor * * @since 3.1 */ public function __construct() { parent::__construct(); // Load com_tags config $this->comParams = ComponentHelper::getParams('com_tags'); } /** * Method to get the field input for a tag field. * * @return string The field input. * * @since 3.1 */ protected function getInput() { $data = $this->getLayoutData(); if (!\is_array($this->value) && !empty($this->value)) { if ($this->value instanceof TagsHelper) { if (empty($this->value->tags)) { $this->value = []; } else { $this->value = $this->value->tags; } } // String in format 2,5,4 if (\is_string($this->value)) { $this->value = explode(',', $this->value); } // Integer is given if (\is_int($this->value)) { $this->value = [$this->value]; } $data['value'] = $this->value; } $data['remoteSearch'] = $this->isRemoteSearch(); $data['options'] = $this->getOptions(); $data['isNested'] = $this->isNested(); $data['allowCustom'] = $this->allowCustom(); $data['minTermLength'] = (int) $this->comParams->get('min_term_length', 3); return $this->getRenderer($this->layout)->render($data); } /** * Method to get a list of tags * * @return object[] The field option objects. * * @since 3.1 */ protected function getOptions() { $published = (string) $this->element['published'] ?: [0, 1]; $app = Factory::getApplication(); $language = null; $options = []; // This limit is only used with isRemoteSearch $prefillLimit = 30; $isRemoteSearch = $this->isRemoteSearch(); $db = $this->getDatabase(); $query = $db->getQuery(true) ->select( [ $db->quoteName('a.id', 'value'), $db->quoteName('a.path'), $db->quoteName('a.title', 'text'), $db->quoteName('a.level'), $db->quoteName('a.published'), $db->quoteName('a.lft'), ] ) ->from($db->quoteName('#__tags', 'a')); // Limit Options in multilanguage if ($app->isClient('site') && Multilanguage::isEnabled()) { if (ComponentHelper::getParams('com_tags')->get('tag_list_language_filter') === 'current_language') { $language = [$app->getLanguage()->getTag(), '*']; } } elseif (!empty($this->element['language'])) { // Filter language if (strpos($this->element['language'], ',') !== false) { $language = explode(',', $this->element['language']); } else { $language = [$this->element['language']]; } } if ($language) { $query->whereIn($db->quoteName('a.language'), $language, ParameterType::STRING); } $query->where($db->quoteName('a.lft') . ' > 0'); // Filter on the published state if (is_numeric($published)) { $published = (int) $published; $query->where($db->quoteName('a.published') . ' = :published') ->bind(':published', $published, ParameterType::INTEGER); } elseif (\is_array($published)) { $published = ArrayHelper::toInteger($published); $query->whereIn($db->quoteName('a.published'), $published); } $query->order($db->quoteName('a.lft') . ' ASC'); // Preload only active values and 30 most used tags or fill up if ($isRemoteSearch) { // Load the most $prefillLimit used tags $topQuery = $db->getQuery(true) ->select($db->quoteName('tag_id')) ->from($db->quoteName('#__contentitem_tag_map')) ->group($db->quoteName('tag_id')) ->order('count(*)') ->setLimit($prefillLimit); $db->setQuery($topQuery); $topIds = $db->loadColumn(); // Merge the used values into the most used tags if (!empty($this->value) && is_array($this->value)) { $topIds = array_unique(array_merge($topIds, $this->value)); } // Set the default limit for the main query $query->setLimit($prefillLimit); if (!empty($topIds)) { // Filter the ids to the most used tags and the selected tags $preQuery = clone $query; $preQuery->clear('limit') ->whereIn($db->quoteName('a.id'), $topIds); $db->setQuery($preQuery); try { $options = $db->loadObjectList(); } catch (\RuntimeException $e) { return []; } // Limit the main query to the missing amount of tags $count = count($options); $prefillLimit = $prefillLimit - $count; $query->setLimit($prefillLimit); // Exclude the already loaded tags from the main query if ($count > 0) { $query->whereNotIn($db->quoteName('a.id'), ArrayHelper::getColumn($options, 'value')); } } } // Only execute the query if we need more tags not already loaded by the $preQuery query if (!$isRemoteSearch || $prefillLimit > 0) { // Get the options. $db->setQuery($query); try { $options = array_merge($options, $db->loadObjectList()); } catch (\RuntimeException $e) { return []; } } // Block the possibility to set a tag as it own parent if ($this->form->getName() === 'com_tags.tag') { $id = (int) $this->form->getValue('id', null, 0); foreach ($options as $option) { if ($option->value == $id) { $option->disable = true; } } } // Merge any additional options in the XML definition. $options = array_merge(parent::getOptions(), $options); // Prepare nested data if ($this->isNested()) { $this->prepareOptionsNested($options); } else { $options = TagsHelper::convertPathsToNames($options); } return $options; } /** * Add "-" before nested tags, depending on level * * @param object[] &$options Array of tags * * @return object[] The field option objects. * * @since 3.1 */ protected function prepareOptionsNested(&$options) { if ($options) { foreach ($options as &$option) { $repeat = (isset($option->level) && $option->level - 1 >= 0) ? $option->level - 1 : 0; $option->text = str_repeat('- ', $repeat) . $option->text; } } return $options; } /** * Determine if the field has to be tagnested * * @return boolean * * @since 3.1 */ public function isNested() { if ($this->isNested === null) { // If mode="nested" || ( mode not set & config = nested ) if ( isset($this->element['mode']) && (string) $this->element['mode'] === 'nested' || !isset($this->element['mode']) && $this->comParams->get('tag_field_ajax_mode', 1) == 0 ) { $this->isNested = true; } } return $this->isNested; } /** * Determines if the field allows or denies custom values * * @return boolean */ public function allowCustom() { if ($this->element['custom'] && \in_array((string) $this->element['custom'], ['0', 'false', 'deny'])) { return false; } return Factory::getUser()->authorise('core.create', 'com_tags'); } /** * Check whether need to enable AJAX search * * @return boolean * * @since 4.0.0 */ public function isRemoteSearch() { if ($this->element['remote-search']) { return !\in_array((string) $this->element['remote-search'], ['0', 'false', '']); } return $this->comParams->get('tag_field_ajax_mode', 1) == 1; } } Field/CaptchaField.php 0000644 00000012153 15173135670 0010621 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Captcha\Captcha; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormField; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Captcha field. * * @since 2.5 */ class CaptchaField extends FormField { /** * The field type. * * @var string * @since 2.5 */ protected $type = 'Captcha'; /** * The plugin of the captcha field. * * @var string * @since 4.3.0 */ protected $plugin; /** * The namespace of the captcha field. * * @var string * @since 4.3.0 */ protected $namespace; /** * The captcha base instance of our type. * * @var ?Captcha */ protected $_captcha; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'plugin': case 'namespace': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'plugin': case 'namespace': $this->$name = (string) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @since 2.5 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $result = parent::setup($element, $value, $group); $app = Factory::getApplication(); $default = $app->get('captcha'); if ($app->isClient('site')) { $default = $app->getParams()->get('captcha', $default); } $plugin = $this->element['plugin'] ? (string) $this->element['plugin'] : $default; $this->plugin = $plugin; if ($plugin === 0 || $plugin === '0' || $plugin === '' || $plugin === null) { $this->hidden = true; return false; } else { // Force field to be required. There's no reason to have a captcha if it is not required. // Obs: Don't put required="required" in the xml file, you just need to have validate="captcha" $this->required = true; if (strpos($this->class, 'required') === false) { $this->class .= ' required'; } } $this->namespace = $this->element['namespace'] ? (string) $this->element['namespace'] : $this->form->getName(); try { // Get an instance of the captcha class that we are using $this->_captcha = Captcha::getInstance($this->plugin, ['namespace' => $this->namespace]); /** * Give the captcha instance a possibility to react on the setup-process, * e.g. by altering the XML structure of the field, for example hiding the label * when using invisible captchas. */ $this->_captcha->setupField($this, $element); } catch (\RuntimeException $e) { $this->_captcha = null; Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); return false; } return $result; } /** * Method to get the field input. * * @return string The field input. * * @since 2.5 */ protected function getInput() { if ($this->hidden || $this->_captcha == null) { return ''; } try { return $this->_captcha->display($this->name, $this->id, $this->class); } catch (\RuntimeException $e) { Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); } return ''; } } Field/EditorField.php 0000644 00000022054 15173135670 0010505 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Editor\Editor; use Joomla\CMS\Factory; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * A textarea field for content creation * * @see JEditor * @since 1.6 */ class EditorField extends TextareaField { /** * The form field type. * * @var string * @since 1.6 */ public $type = 'Editor'; /** * The Editor object. * * @var Editor * @since 1.6 */ protected $editor; /** * The height of the editor. * * @var string * @since 3.2 */ protected $height; /** * The width of the editor. * * @var string * @since 3.2 */ protected $width; /** * The assetField of the editor. * * @var string * @since 3.2 */ protected $assetField; /** * The authorField of the editor. * * @var string * @since 3.2 */ protected $authorField; /** * The asset of the editor. * * @var string * @since 3.2 */ protected $asset; /** * The buttons of the editor. * * @var mixed * @since 3.2 */ protected $buttons; /** * The hide of the editor. * * @var string[] * @since 3.2 */ protected $hide; /** * The editorType of the editor. * * @var string[] * @since 3.2 */ protected $editorType; /** * The parent class of the field * * @var string * @since 4.0.0 */ protected $parentclass; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'height': case 'width': case 'assetField': case 'authorField': case 'asset': case 'buttons': case 'hide': case 'editorType': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'height': case 'width': case 'assetField': case 'authorField': case 'asset': $this->$name = (string) $value; break; case 'buttons': $value = (string) $value; if ($value === 'true' || $value === 'yes' || $value === '1') { $this->buttons = true; } elseif ($value === 'false' || $value === 'no' || $value === '0') { $this->buttons = false; } else { $this->buttons = explode(',', $value); } break; case 'hide': $value = (string) $value; $this->hide = $value ? explode(',', $value) : []; break; case 'editorType': // Can be in the form of: editor="desired|alternative". $this->editorType = explode('|', trim((string) $value)); break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $result = parent::setup($element, $value, $group); if ($result === true) { $this->height = $this->element['height'] ? (string) $this->element['height'] : '500'; $this->width = $this->element['width'] ? (string) $this->element['width'] : '100%'; $this->assetField = $this->element['asset_field'] ? (string) $this->element['asset_field'] : 'asset_id'; $this->authorField = $this->element['created_by_field'] ? (string) $this->element['created_by_field'] : 'created_by'; $this->asset = $this->form->getValue($this->assetField) ?: (string) $this->element['asset_id']; $buttons = (string) $this->element['buttons']; $hide = (string) $this->element['hide']; $editorType = (string) $this->element['editor']; if ($buttons === 'true' || $buttons === 'yes' || $buttons === '1') { $this->buttons = true; } elseif ($buttons === 'false' || $buttons === 'no' || $buttons === '0') { $this->buttons = false; } else { $this->buttons = !empty($hide) ? explode(',', $buttons) : []; } $this->hide = !empty($hide) ? explode(',', (string) $this->element['hide']) : []; $this->editorType = !empty($editorType) ? explode('|', trim($editorType)) : []; } return $result; } /** * Method to get the field input markup for the editor area * * @return string The field input markup. * * @since 1.6 */ protected function getInput() { // Get an editor object. $editor = $this->getEditor(); $params = [ 'autofocus' => $this->autofocus, 'readonly' => $this->readonly || $this->disabled, 'syntax' => (string) $this->element['syntax'], ]; return $editor->display( $this->name, htmlspecialchars($this->value, ENT_COMPAT, 'UTF-8'), $this->width, $this->height, $this->columns, $this->rows, $this->buttons ? (\is_array($this->buttons) ? array_merge($this->buttons, $this->hide) : $this->hide) : false, $this->id, $this->asset, $this->form->getValue($this->authorField), $params ); } /** * Method to get an Editor object based on the form field. * * @return Editor The Editor object. * * @since 1.6 */ protected function getEditor() { // Only create the editor if it is not already created. if (empty($this->editor)) { $editor = null; if ($this->editorType) { // Get the list of editor types. $types = $this->editorType; // Get the database object. $db = $this->getDatabase(); // Build the query. $query = $db->getQuery(true) ->select($db->quoteName('element')) ->from($db->quoteName('#__extensions')) ->where( [ $db->quoteName('element') . ' = :editor', $db->quoteName('folder') . ' = ' . $db->quote('editors'), $db->quoteName('enabled') . ' = 1', ] ); // Declare variable before binding. $element = ''; $query->bind(':editor', $element); $query->setLimit(1); // Iterate over the types looking for an existing editor. foreach ($types as $element) { // Check if the editor exists. $db->setQuery($query); $editor = $db->loadResult(); // If an editor was found stop looking. if ($editor) { break; } } } // Create the JEditor instance based on the given editor. if ($editor === null) { $editor = Factory::getApplication()->get('editor'); } $this->editor = Editor::getInstance($editor); } return $this->editor; } } Field/TimeField.php 0000644 00000010470 15173135670 0010154 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2019 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Form\FormField; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides a select list of integers with specified first, last and step values. * * @since 4.0.0 */ class TimeField extends FormField { /** * The form field type. * * @var string * @since 4.0.0 */ protected $type = 'Time'; /** * The allowable minimal value of the field. * * @var integer * @since 4.0.0 */ protected $min; /** * The allowable maximal value of the field. * * @var integer * @since 4.0.0 */ protected $max; /** * Steps between different values * * @var integer * @since 4.0.0 */ protected $step; /** * Name of the layout being used to render the field * * @var string * @since 4.0.0 */ protected $layout = 'joomla.form.field.time'; /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 4.0.0 */ public function __set($name, $value) { switch ($name) { case 'max': case 'min': case 'step': $this->$name = (int) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @see FormField::setup() * @return boolean True on success. * * @since 4.0.0 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { // It is better not to force any default limits if none is specified $this->max = isset($this->element['max']) ? (int) $this->element['max'] : null; $this->min = isset($this->element['min']) ? (int) $this->element['min'] : null; $this->step = isset($this->element['step']) ? (int) $this->element['step'] : null; } return $return; } /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 4.0.0 */ public function __get($name) { switch ($name) { case 'min': case 'max': case 'step': return $this->$name; } return parent::__get($name); } /** * Method to get the field input markup. * * @return string The field input markup. * * @since 4.0.0 */ protected function getInput() { return $this->getRenderer($this->layout)->render($this->getLayoutData()); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 4.0.0 */ protected function getLayoutData() { $data = parent::getLayoutData(); $extraData = [ 'min' => $this->min, 'max' => $this->max, 'step' => $this->step, ]; return array_merge($data, $extraData); } } Field/OrderingField.php 0000644 00000013105 15173135670 0011025 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Form\FormField; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\UCM\UCMType; use Joomla\Database\ParameterType; use Joomla\Database\QueryInterface; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Ordering field. * * @since 3.2 */ class OrderingField extends FormField { /** * The form field type. * * @var string * @since 3.2 */ protected $type = 'Ordering'; /** * The form field content type. * * @var string * @since 3.2 */ protected $contentType; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { if ($name === 'contentType') { return $this->contentType; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'contentType': $this->contentType = (string) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $result = parent::setup($element, $value, $group); if ($result === true) { $this->contentType = (string) $this->element['content_type']; } return $result; } /** * Method to get the field input markup. * * @return string The field input markup. * * @since 3.2 */ protected function getInput() { $html = []; $attr = ''; // Initialize some field attributes. $attr .= !empty($this->class) ? ' class="form-select' . $this->class . '"' : ' class="form-select"'; $attr .= $this->disabled ? ' disabled' : ''; $attr .= !empty($this->size) ? ' size="' . $this->size . '"' : ''; // Initialize JavaScript field attributes. $attr .= !empty($this->onchange) ? ' onchange="' . $this->onchange . '"' : ''; $itemId = (int) $this->getItemId(); $query = $this->getQuery(); // Create a read-only list (no name) with a hidden input to store the value. if ($this->readonly) { $html[] = HTMLHelper::_('list.ordering', '', $query, trim($attr), $this->value, $itemId ? 0 : 1, $this->id); $html[] = '<input type="hidden" name="' . $this->name . '" value="' . $this->value . '">'; } else { // Create a regular list. $html[] = HTMLHelper::_('list.ordering', $this->name, $query, trim($attr), $this->value, $itemId ? 0 : 1, $this->id); } return implode($html); } /** * Builds the query for the ordering list. * * @return QueryInterface The query for the ordering form field * * @since 3.2 */ protected function getQuery() { $categoryId = (int) $this->form->getValue('catid'); $ucmType = new UCMType(); $ucmRow = $ucmType->getType($ucmType->getTypeId($this->contentType)); $ucmMapCommon = json_decode($ucmRow->field_mappings)->common; if (\is_object($ucmMapCommon)) { $ordering = $ucmMapCommon->core_ordering; $title = $ucmMapCommon->core_title; } elseif (\is_array($ucmMapCommon)) { $ordering = $ucmMapCommon[0]->core_ordering; $title = $ucmMapCommon[0]->core_title; } $db = $this->getDatabase(); $query = $db->getQuery(true); $query->select([$db->quoteName($ordering, 'value'), $db->quoteName($title, 'text')]) ->from($db->quoteName(json_decode($ucmRow->table)->special->dbtable)) ->where($db->quoteName('catid') . ' = :categoryId') ->order($db->quoteName('ordering')) ->bind(':categoryId', $categoryId, ParameterType::INTEGER); return $query; } /** * Retrieves the current Item's Id. * * @return integer The current item ID * * @since 3.2 */ protected function getItemId() { return (int) $this->form->getValue('id'); } } Field/NumberField.php 0000644 00000013677 15173135670 0010522 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormField; use Joomla\CMS\Language\Text; use Joomla\CMS\Uri\Uri; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides a one line text box with up-down handles to set a number in the field. * * @link https://html.spec.whatwg.org/multipage/input.html#number-state-(type=number) * @since 3.2 */ class NumberField extends FormField { /** * The form field type. * * @var string * @since 3.2 */ protected $type = 'Number'; /** * The allowable maximum value of the field. * * @var float * @since 3.2 */ protected $max = null; /** * The allowable minimum value of the field. * * @var float * @since 3.2 */ protected $min = null; /** * The step by which value of the field increased or decreased. * * @var float * @since 3.2 */ protected $step = 0; /** * Name of the layout being used to render the field * * @var string * @since 3.7 */ protected $layout = 'joomla.form.field.number'; /** * The parent class of the field * * @var string * @since 4.0.0 */ protected $parentclass; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'max': case 'min': case 'step': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'step': case 'min': case 'max': $this->$name = (float) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { // It is better not to force any default limits if none is specified $this->max = isset($this->element['max']) ? (float) $this->element['max'] : null; $this->min = isset($this->element['min']) ? (float) $this->element['min'] : null; $this->step = isset($this->element['step']) ? (float) $this->element['step'] : 1; } return $return; } /** * Method to get the field input markup. * * @return string The field input markup. * * @since 3.2 */ protected function getInput() { if ($this->element['useglobal']) { $component = Factory::getApplication()->getInput()->getCmd('option'); // Get correct component for menu items if ($component === 'com_menus') { $link = $this->form->getData()->get('link'); $uri = new Uri($link); $component = $uri->getVar('option', 'com_menus'); } $params = ComponentHelper::getParams($component); $value = $params->get($this->fieldname); // Try with global configuration if (\is_null($value)) { $value = Factory::getApplication()->get($this->fieldname); } // Try with menu configuration if (\is_null($value) && Factory::getApplication()->getInput()->getCmd('option') === 'com_menus') { $value = ComponentHelper::getParams('com_menus')->get($this->fieldname); } if (!\is_null($value)) { $value = (string) $value; $this->hint = Text::sprintf('JGLOBAL_USE_GLOBAL_VALUE', $value); } } // Trim the trailing line in the layout file return rtrim($this->getRenderer($this->layout)->render($this->getLayoutData()), PHP_EOL); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.7 */ protected function getLayoutData() { $data = parent::getLayoutData(); // Initialize some field attributes. $extraData = [ 'max' => $this->max, 'min' => $this->min, 'step' => $this->step, 'value' => $this->value, ]; return array_merge($data, $extraData); } } Field/UserstateField.php 0000644 00000001450 15173135670 0011233 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Field to load a list of available users statuses * * @since 3.2 */ class UserstateField extends PredefinedlistField { /** * The form field type. * * @var string * @since 3.2 */ protected $type = 'UserState'; /** * Available statuses * * @var string[] * @since 3.2 */ protected $predefinedOptions = [ '0' => 'JENABLED', '1' => 'JDISABLED', ]; } Field/UseractiveField.php 0000644 00000002421 15173135670 0011365 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Field to show a list of available user active statuses * * @since 3.2 */ class UseractiveField extends PredefinedlistField { /** * The form field type. * * @var string * @since 3.2 */ protected $type = 'UserActive'; /** * Available statuses * * @var string[] * @since 3.2 */ protected $predefinedOptions = [ '0' => 'COM_USERS_ACTIVATED', '1' => 'COM_USERS_UNACTIVATED', ]; /** * Method to instantiate the form field object. * * @param Form $form The form to attach to the form field object. * * @since 1.7.0 */ public function __construct($form = null) { parent::__construct($form); // Load the required language $lang = Factory::getLanguage(); $lang->load('com_users', JPATH_ADMINISTRATOR); } } Field/HiddenField.php 0000644 00000002727 15173135670 0010457 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Form\FormField; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides a hidden field * * @link https://html.spec.whatwg.org/multipage/input.html#hidden-state-(type=hidden) * @since 1.7.0 */ class HiddenField extends FormField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Hidden'; /** * Name of the layout being used to render the field * * @var string * @since 3.7 */ protected $layout = 'joomla.form.field.hidden'; /** * Method to get the field input markup. * * @return string The field input markup. * * @since 1.7.0 */ protected function getInput() { // Trim the trailing line in the layout file return rtrim($this->getRenderer($this->layout)->render($this->getLayoutData()), PHP_EOL); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.7 */ protected function getLayoutData() { return parent::getLayoutData(); } } Field/CategoryField.php 0000644 00000006657 15173135670 0011047 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Log\Log; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Supports an HTML select list of categories * * @since 1.6 */ class CategoryField extends ListField { /** * The form field type. * * @var string * @since 1.6 */ public $type = 'Category'; /** * Method to get the field options for category * Use the extension attribute in a form to specify the.specific extension for * which categories should be displayed. * Use the show_root attribute to specify whether to show the global category root in the list. * * @return object[] The field option objects. * * @since 1.6 */ protected function getOptions() { $options = []; $extension = $this->element['extension'] ? (string) $this->element['extension'] : (string) $this->element['scope']; $published = (string) $this->element['published']; $language = (string) $this->element['language']; // Load the category options for a given extension. if (!empty($extension)) { // Filter over published state or not depending upon if it is present. $filters = []; if ($published) { $filters['filter.published'] = explode(',', $published); } // Filter over language depending upon if it is present. if ($language) { $filters['filter.language'] = explode(',', $language); } if ($filters === []) { $options = HTMLHelper::_('category.options', $extension); } else { $options = HTMLHelper::_('category.options', $extension, $filters); } // Verify permissions. If the action attribute is set, then we scan the options. if ((string) $this->element['action']) { // Get the current user object. $user = Factory::getUser(); foreach ($options as $i => $option) { /* * To take save or create in a category you need to have create rights for that category * unless the item is already in that category. * Unset the option if the user isn't authorised for it. In this field assets are always categories. */ if ($user->authorise('core.create', $extension . '.category.' . $option->value) === false) { unset($options[$i]); } } } if (isset($this->element['show_root'])) { array_unshift($options, HTMLHelper::_('select.option', '0', Text::_('JGLOBAL_ROOT'))); } } else { Log::add(Text::_('JLIB_FORM_ERROR_FIELDS_CATEGORY_ERROR_EXTENSION_EMPTY'), Log::WARNING, 'jerror'); } // Merge any additional options in the XML definition. $options = array_merge(parent::getOptions(), $options); return $options; } } Field/TransitionField.php 0000644 00000012527 15173135670 0011415 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\Database\ParameterType; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Workflow Transitions field. * * @since 4.0.0 */ class TransitionField extends GroupedlistField { /** * The form field type. * * @var string * @since 4.0.0 */ protected $type = 'Transition'; /** * The component and section separated by ".". * * @var string * @since 4.0.0 */ protected $extension; /** * The workflow stage to use. * * @var integer */ protected $workflowStage; /** * Method to setup the extension * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @since 4.0.0 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $result = parent::setup($element, $value, $group); if ($result) { $input = Factory::getApplication()->getInput(); if (\strlen($element['extension'])) { $this->extension = (string) $element['extension']; } else { $this->extension = $input->getCmd('extension'); } if (\strlen($element['workflow_stage'])) { $this->workflowStage = (int) $element['workflow_stage']; } else { $this->workflowStage = $input->getInt('id'); } } return $result; } /** * Method to get a list of options for a list input. * * @return array[] An array of HTMLHelper options. * * @since 4.0.0 */ protected function getGroups() { // Initialise variable. $db = $this->getDatabase(); $extension = $this->extension; $workflowStage = (int) $this->workflowStage; $query = $db->getQuery(true) ->select( [ $db->quoteName('t.id', 'value'), $db->quoteName('t.title', 'text'), ] ) ->from( [ $db->quoteName('#__workflow_transitions', 't'), $db->quoteName('#__workflow_stages', 's'), $db->quoteName('#__workflow_stages', 's2'), ] ) ->whereIn($db->quoteName('t.from_stage_id'), [-1, $workflowStage]) ->where( [ $db->quoteName('t.to_stage_id') . ' = ' . $db->quoteName('s.id'), $db->quoteName('s.workflow_id') . ' = ' . $db->quoteName('s2.workflow_id'), $db->quoteName('s.workflow_id') . ' = ' . $db->quoteName('t.workflow_id'), $db->quoteName('s2.id') . ' = :stage1', $db->quoteName('t.published') . ' = 1', $db->quoteName('s.published') . ' = 1', ] ) ->bind(':stage1', $workflowStage, ParameterType::INTEGER) ->order($db->quoteName('t.ordering')); $items = $db->setQuery($query)->loadObjectList(); Factory::getLanguage()->load('com_workflow', JPATH_ADMINISTRATOR); $parts = explode('.', $extension); $component = reset($parts); if (\count($items)) { $user = Factory::getUser(); $items = array_filter( $items, function ($item) use ($user, $component) { return $user->authorise('core.execute.transition', $component . '.transition.' . $item->value); } ); foreach ($items as $item) { $item->text = Text::_($item->text); } } // Get workflow stage title $query = $db->getQuery(true) ->select($db->quoteName('title')) ->from($db->quoteName('#__workflow_stages')) ->where($db->quoteName('id') . ' = :stage') ->bind(':stage', $workflowStage, ParameterType::INTEGER); $workflowName = $db->setQuery($query)->loadResult(); $default = [[HTMLHelper::_('select.option', '', Text::_($workflowName))]]; $groups = parent::getGroups(); if (\count($items)) { $groups[Text::_('COM_CONTENT_RUN_TRANSITION')] = $items; } if (\count($groups)) { $default[][] = HTMLHelper::_('select.option', '-1', '--------', ['disable' => true]); } // Merge with defaults return array_merge($default, $groups); } } Field/LastvisitdaterangeField.php 0000644 00000003171 15173135670 0013113 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Field to show a list of available date ranges to filter on last visit date. * * @since 3.6 */ class LastvisitdaterangeField extends PredefinedlistField { /** * Method to instantiate the form field object. * * @param Form $form The form to attach to the form field object. * * @since 1.7.0 */ public function __construct($form = null) { parent::__construct($form); // Set the type $this->type = 'LastvisitDateRange'; // Load the required language $lang = Factory::getLanguage(); $lang->load('com_users', JPATH_ADMINISTRATOR); // Set the pre-defined options $this->predefinedOptions = [ 'today' => 'COM_USERS_OPTION_RANGE_TODAY', 'past_week' => 'COM_USERS_OPTION_RANGE_PAST_WEEK', 'past_1month' => 'COM_USERS_OPTION_RANGE_PAST_1MONTH', 'past_3month' => 'COM_USERS_OPTION_RANGE_PAST_3MONTH', 'past_6month' => 'COM_USERS_OPTION_RANGE_PAST_6MONTH', 'past_year' => 'COM_USERS_OPTION_RANGE_PAST_YEAR', 'post_year' => 'COM_USERS_OPTION_RANGE_POST_YEAR', 'never' => 'COM_USERS_OPTION_RANGE_NEVER', ]; } } Field/TelephoneField.php 0000644 00000003527 15173135670 0011206 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Supports a text field telephone numbers. * * @link https://html.spec.whatwg.org/multipage/input.html#telephone-state-(type=tel) * @see \Joomla\CMS\Form\Rule\TelRule for telephone number validation * @see JHtmlTel for rendering of telephone numbers * @since 1.7.0 */ class TelephoneField extends TextField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Telephone'; /** * Name of the layout being used to render the field * * @var string * @since 3.7.0 */ protected $layout = 'joomla.form.field.tel'; /** * Method to get the field input markup. * * @return string The field input markup. * * @since 3.2 */ protected function getInput() { // Trim the trailing line in the layout file return rtrim($this->getRenderer($this->layout)->render($this->getLayoutData()), PHP_EOL); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.7.0 */ protected function getLayoutData() { $data = parent::getLayoutData(); // Initialize some field attributes. $maxLength = !empty($this->maxLength) ? ' maxlength="' . $this->maxLength . '"' : ''; $extraData = [ 'maxLength' => $maxLength, ]; return array_merge($data, $extraData); } } Field/IntegerField.php 0000644 00000004104 15173135670 0010650 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\HTML\HTMLHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides a select list of integers with specified first, last and step values. * * @since 1.7.0 */ class IntegerField extends ListField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Integer'; /** * Method to get the field options. * * @return object[] The field option objects. * * @since 1.7.0 */ protected function getOptions() { $options = []; // Initialize some field attributes. $first = (int) $this->element['first']; $last = (int) $this->element['last']; $step = (int) $this->element['step']; // Sanity checks. if ($step == 0) { // Step of 0 will create an endless loop. return $options; } elseif ($first < $last && $step < 0) { // A negative step will never reach the last number. return $options; } elseif ($first > $last && $step > 0) { // A position step will never reach the last number. return $options; } elseif ($step < 0) { // Build the options array backwards. for ($i = $first; $i >= $last; $i += $step) { $options[] = HTMLHelper::_('select.option', $i); } } else { // Build the options array. for ($i = $first; $i <= $last; $i += $step) { $options[] = HTMLHelper::_('select.option', $i); } } // Merge any additional options in the XML definition. $options = array_merge(parent::getOptions(), $options); return $options; } } Field/MenuitemField.php 0000644 00000016212 15173135670 0011041 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\HTML\HTMLHelper; use Joomla\Component\Menus\Administrator\Helper\MenusHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Supports an HTML grouped select list of menu item grouped by menu * * @since 1.6 */ class MenuitemField extends GroupedlistField { /** * The form field type. * * @var string * @since 1.6 */ public $type = 'MenuItem'; /** * The menu type. * * @var string * @since 3.2 */ protected $menuType; /** * The client id. * * @var int * @since 3.2 */ protected $clientId; /** * The language. * * @var string[] * @since 3.2 */ protected $language; /** * The published status. * * @var string[] * @since 3.2 */ protected $published; /** * The disabled status. * * @var string[] * @since 3.2 */ protected $disable; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'menuType': case 'clientId': case 'language': case 'published': case 'disable': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'menuType': $this->menuType = (string) $value; break; case 'clientId': $this->clientId = (int) $value; break; case 'language': case 'published': case 'disable': $value = (string) $value; $this->$name = $value ? explode(',', $value) : []; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $result = parent::setup($element, $value, $group); if ($result === true) { $this->menuType = (string) $this->element['menu_type']; $this->clientId = (int) $this->element['client_id']; $this->published = $this->element['published'] ? explode(',', (string) $this->element['published']) : []; $this->disable = $this->element['disable'] ? explode(',', (string) $this->element['disable']) : []; $this->language = $this->element['language'] ? explode(',', (string) $this->element['language']) : []; } return $result; } /** * Method to get the field option groups. * * @return array[] The field option objects as a nested array in groups. * * @since 1.6 */ protected function getGroups() { $groups = []; $menuType = $this->menuType; // Get the menu items. $items = MenusHelper::getMenuLinks($menuType, 0, 0, $this->published, $this->language, $this->clientId); // Build group for a specific menu type. if ($menuType) { // If the menutype is empty, group the items by menutype. $db = $this->getDatabase(); $query = $db->getQuery(true) ->select($db->quoteName('title')) ->from($db->quoteName('#__menu_types')) ->where($db->quoteName('menutype') . ' = :menuType') ->bind(':menuType', $menuType); $db->setQuery($query); try { $menuTitle = $db->loadResult(); } catch (\RuntimeException $e) { $menuTitle = $menuType; } // Initialize the group. $groups[$menuTitle] = []; // Build the options array. foreach ($items as $link) { $levelPrefix = str_repeat('- ', max(0, $link->level - 1)); // Displays language code if not set to All if ($link->language !== '*') { $lang = ' (' . $link->language . ')'; } else { $lang = ''; } $groups[$menuTitle][] = HTMLHelper::_( 'select.option', $link->value, $levelPrefix . $link->text . $lang, 'value', 'text', \in_array($link->type, $this->disable) ); } } else { // Build groups for all menu types. // Build the groups arrays. foreach ($items as $menu) { // Initialize the group. $groups[$menu->title] = []; // Build the options array. foreach ($menu->links as $link) { $levelPrefix = str_repeat('- ', max(0, $link->level - 1)); // Displays language code if not set to All if ($link->language !== '*') { $lang = ' (' . $link->language . ')'; } else { $lang = ''; } $groups[$menu->title][] = HTMLHelper::_( 'select.option', $link->value, $levelPrefix . $link->text . $lang, 'value', 'text', \in_array($link->type, $this->disable) ); } } } // Merge any additional groups in the XML definition. $groups = array_merge(parent::getGroups(), $groups); return $groups; } } Field/ModuleorderField.php 0000644 00000007612 15173135670 0011543 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Form\FormField; use Joomla\CMS\Session\Session; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Module Order field. * * @since 1.6 */ class ModuleorderField extends FormField { /** * The form field type. * * @var string * @since 1.6 */ protected $type = 'ModuleOrder'; /** * Name of the layout being used to render the field * * @var string * @since 3.6.3 */ protected $layout = 'joomla.form.field.moduleorder'; /** * The linked property * * @var string * @since 4.2.7 */ protected $linked; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.6.3 */ public function __get($name) { if ($name === 'linked') { return $this->linked; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.6.3 */ public function __set($name, $value) { switch ($name) { case 'linked': $this->$name = (string) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.6.3 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { $this->linked = isset($this->element['linked']) ? (int) $this->element['linked'] : 'position'; } return $return; } /** * Method to get the field input markup for the moduleorder field. * * @return string The field input markup. * * @since 1.6 */ protected function getInput() { return $this->getRenderer($this->layout)->render($this->getLayoutData()); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.6.3 */ protected function getLayoutData() { $data = parent::getLayoutData(); $extraData = [ 'ordering' => $this->form->getValue('ordering'), 'clientId' => $this->form->getValue('client_id'), 'moduleId' => $this->form->getValue('id'), 'name' => $this->name, 'token' => Session::getFormToken() . '=1', 'element' => $this->form->getName() . '_' . $this->linked, ]; return array_merge($data, $extraData); } } Field/AliastagField.php 0000644 00000004126 15173135670 0011004 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Language\Text; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Framework. * * @since 2.5.0 */ class AliastagField extends ListField { /** * The field type. * * @var string * @since 3.6 */ protected $type = 'Aliastag'; /** * Method to get a list of options for a list input. * * @return object[] An array of JHtml options. * * @since 3.6 */ protected function getOptions() { // Get list of tag type alias $db = $this->getDatabase(); $query = $db->getQuery(true) ->select( [ 'DISTINCT ' . $db->quoteName('type_alias', 'value'), $db->quoteName('type_alias', 'text'), ] ) ->from($db->quoteName('#__contentitem_tag_map')); $db->setQuery($query); $options = $db->loadObjectList(); $lang = Factory::getLanguage(); foreach ($options as $i => $item) { $parts = explode('.', $item->value); $extension = $parts[0]; $lang->load($extension . '.sys', JPATH_ADMINISTRATOR) || $lang->load($extension, Path::clean(JPATH_ADMINISTRATOR . '/components/' . $extension)); $options[$i]->text = Text::_(strtoupper($extension) . '_TAGS_' . strtoupper($parts[1])); } // Merge any additional options in the XML definition. $options = array_merge(parent::getOptions(), $options); // Sort by language value usort( $options, function ($a, $b) { return strcmp($a->text, $b->text); } ); return $options; } } Field/RadiobasicField.php 0000644 00000003006 15173135670 0011313 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2016 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides radio button inputs using default styling * * @since 4.0.0 */ class RadiobasicField extends ListField { /** * The form field type. * * @var string * @since 4.0.0 */ protected $type = 'Radiobasic'; /** * Name of the layout being used to render the field * * @var string * @since 4.0.0 */ protected $layout = 'joomla.form.field.radiobasic'; /** * Method to get the radio button field input markup. * * @return string The field input markup. * * @since 4.0.0 */ protected function getInput() { return $this->getRenderer($this->layout)->render($this->getLayoutData()); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 4.0.0 */ protected function getLayoutData() { $data = parent::getLayoutData(); $extraData = [ 'options' => $this->getOptions(), 'value' => (string) $this->value, ]; return array_merge($data, $extraData); } } Field/TextareaField.php 0000644 00000012430 15173135670 0011031 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Form\FormField; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Supports a multi line area for entry of plain text * * @link https://html.spec.whatwg.org/multipage/form-elements.html#the-textarea-element * @since 1.7.0 */ class TextareaField extends FormField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Textarea'; /** * The number of rows in textarea. * * @var mixed * @since 3.2 */ protected $rows; /** * The number of columns in textarea. * * @var mixed * @since 3.2 */ protected $columns; /** * The maximum number of characters in textarea. * * @var mixed * @since 3.4 */ protected $maxlength; /** * Does this field support a character counter? * * @var boolean * @since 4.0.0 */ protected $charcounter = false; /** * Name of the layout being used to render the field * * @var string * @since 3.7 */ protected $layout = 'joomla.form.field.textarea'; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'rows': case 'columns': case 'maxlength': case 'charcounter': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'rows': case 'columns': case 'maxlength': $this->$name = (int) $value; break; case 'charcounter': $this->charcounter = strtolower($value) === 'true'; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { $this->rows = isset($this->element['rows']) ? (int) $this->element['rows'] : false; $this->columns = isset($this->element['cols']) ? (int) $this->element['cols'] : false; $this->maxlength = isset($this->element['maxlength']) ? (int) $this->element['maxlength'] : false; $this->charcounter = isset($this->element['charcounter']) ? strtolower($this->element['charcounter']) === 'true' : false; } return $return; } /** * Method to get the textarea field input markup. * Use the rows and columns attributes to specify the dimensions of the area. * * @return string The field input markup. * * @since 1.7.0 */ protected function getInput() { // Trim the trailing line in the layout file return rtrim($this->getRenderer($this->layout)->render($this->getLayoutData()), PHP_EOL); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.7 */ protected function getLayoutData() { $data = parent::getLayoutData(); // Initialize some field attributes. $columns = $this->columns ? ' cols="' . $this->columns . '"' : ''; $rows = $this->rows ? ' rows="' . $this->rows . '"' : ''; $maxlength = $this->maxlength ? ' maxlength="' . $this->maxlength . '"' : ''; $extraData = [ 'maxlength' => $maxlength, 'rows' => $rows, 'columns' => $columns, 'charcounter' => $this->charcounter, ]; return array_merge($data, $extraData); } } Field/LimitboxField.php 0000644 00000005260 15173135670 0011046 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Language\Text; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Field to load a list of possible item count limits * * @since 3.2 */ class LimitboxField extends ListField { /** * The form field type. * * @var string * @since 3.2 */ public $type = 'Limitbox'; /** * Cached array of the category items. * * @var array[] * @since 3.2 */ protected static $options = []; /** * Default options * * @var int[] */ protected $defaultLimits = [5, 10, 15, 20, 25, 30, 50, 100, 200, 500]; /** * Method to get the options to populate to populate list * * @return object[] The field option objects. * * @since 3.2 */ protected function getOptions() { // Accepted modifiers $hash = md5($this->element->asXML()); if (!isset(static::$options[$hash])) { static::$options[$hash] = parent::getOptions(); $options = []; $limits = $this->defaultLimits; // Limits manually specified if (isset($this->element['limits'])) { $limits = explode(',', $this->element['limits']); } // User wants to add custom limits if (isset($this->element['append'])) { $limits = array_unique(array_merge($limits, explode(',', $this->element['append']))); } // User wants to remove some default limits if (isset($this->element['remove'])) { $limits = array_diff($limits, explode(',', $this->element['remove'])); } // Order the options asort($limits); // Add an option to show all? $showAll = isset($this->element['showall']) ? (string) $this->element['showall'] === 'true' : true; if ($showAll) { $limits[] = 0; } if (!empty($limits)) { foreach ($limits as $value) { $options[] = (object) [ 'value' => $value, 'text' => ($value != 0) ? Text::_('J' . $value) : Text::_('JALL'), ]; } static::$options[$hash] = array_merge(static::$options[$hash], $options); } } return static::$options[$hash]; } } Field/StatusField.php 0000644 00000001543 15173135670 0010542 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field to load a list of states * * @since 3.2 */ class StatusField extends PredefinedlistField { /** * The form field type. * * @var string * @since 3.2 */ public $type = 'Status'; /** * Available statuses * * @var string[] * @since 3.2 */ protected $predefinedOptions = [ -2 => 'JTRASHED', 0 => 'JUNPUBLISHED', 1 => 'JPUBLISHED', 2 => 'JARCHIVED', '*' => 'JALL', ]; } Field/UserField.php 0000644 00000011152 15173135670 0010172 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormField; use Joomla\CMS\Language\Text; use Joomla\CMS\User\User; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Field to select a user ID from a modal list. * * @since 1.6 */ class UserField extends FormField { /** * The form field type. * * @var string * @since 1.6 */ public $type = 'User'; /** * Filtering groups * * @var array * @since 3.5 * @deprecated 4.4 will be removed in 6.0 without replacement */ protected $groups = null; /** * Users to exclude from the list of users * * @var array * @since 3.5 * @deprecated 4.4 will be removed in 6.0 without replacement */ protected $excluded = null; /** * Layout to render * * @var string * @since 3.5 */ protected $layout = 'joomla.form.field.user'; /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @since 3.7.0 * * @see FormField::setup() */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); // If user can't access com_users the field should be readonly. if ($return && !$this->readonly) { $this->readonly = !Factory::getUser()->authorise('core.manage', 'com_users'); } return $return; } /** * Method to get the user field input markup. * * @return string The field input markup. * * @since 1.6 */ protected function getInput() { if (empty($this->layout)) { throw new \UnexpectedValueException(sprintf('%s has no layout assigned.', $this->name)); } return $this->getRenderer($this->layout)->render($this->getLayoutData()); } /** * Get the data that is going to be passed to the layout * * @return array * * @since 3.5 */ public function getLayoutData() { // Get the basic field data $data = parent::getLayoutData(); // Initialize value $name = Text::_('JLIB_FORM_SELECT_USER'); if (is_numeric($this->value)) { $name = User::getInstance($this->value)->name; } elseif (strtoupper($this->value) === 'CURRENT') { // Handle the special case for "current". // 'CURRENT' is not a reasonable value to be placed in the html $current = Factory::getUser(); $this->value = $current->id; $data['value'] = $this->value; $name = $current->name; } // User lookup went wrong, we assign the value instead. if ($name === null && $this->value) { $name = $this->value; } $extraData = [ 'userName' => $name, 'groups' => $this->getGroups(), 'excluded' => $this->getExcluded(), ]; return array_merge($data, $extraData); } /** * Method to get the filtering groups (null means no filtering) * * @return string[] Array of filtering groups or null. * * @since 1.6 */ protected function getGroups() { if (isset($this->element['groups'])) { return explode(',', $this->element['groups']); } return []; } /** * Method to get the users to exclude from the list of users * * @return string[] Array of users to exclude or null to not exclude them * * @since 1.6 */ protected function getExcluded() { if (isset($this->element['exclude'])) { return explode(',', $this->element['exclude']); } return []; } } Field/FileField.php 0000644 00000007624 15173135670 0010144 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Form\FormField; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides an input field for files * * @link https://html.spec.whatwg.org/multipage/input.html#file-upload-state-(type=file) * @since 1.7.0 */ class FileField extends FormField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'File'; /** * The accepted file type list. * * @var mixed * @since 3.2 */ protected $accept; /** * Name of the layout being used to render the field * * @var string * @since 3.6 */ protected $layout = 'joomla.form.field.file'; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { if ($name === 'accept') { return $this->accept; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'accept': $this->accept = (string) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { $this->accept = (string) $this->element['accept']; } return $return; } /** * Method to get the field input markup for the file field. * Field attributes allow specification of a maximum file size and a string * of accepted file extensions. * * @return string The field input markup. * * @note The field does not include an upload mechanism. * @see \Joomla\CMS\Form\Field\MediaField * @since 1.7.0 */ protected function getInput() { return $this->getRenderer($this->layout)->render($this->getLayoutData()); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.6 */ protected function getLayoutData() { $data = parent::getLayoutData(); $extraData = [ 'accept' => $this->accept, 'multiple' => $this->multiple, ]; return array_merge($data, $extraData); } } Field/FrontendlanguageField.php 0000644 00000004316 15173135670 0012543 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2015 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Provides a list of published content languages with home pages * * @see \Joomla\CMS\Form\Field\LanguageField for a select list of application languages. * @since 3.5 */ class FrontendlanguageField extends ListField { /** * The form field type. * * @var string * @since 3.5 */ public $type = 'Frontend_Language'; /** * Method to get the field options for frontend published content languages with homes. * * @return object[] The options the field is going to show. * * @since 3.5 */ protected function getOptions() { // Get the database object and a new query object. $db = $this->getDatabase(); $query = $db->getQuery(true); $query->select('a.lang_code AS value, a.title AS text') ->from($db->quoteName('#__languages') . ' AS a') ->where('a.published = 1') ->order('a.title'); // Select the language home pages. $query->select('l.home, l.language') ->innerJoin($db->quoteName('#__menu') . ' AS l ON l.language=a.lang_code AND l.home=1 AND l.published=1 AND l.language <> ' . $db->quote('*')) ->innerJoin($db->quoteName('#__extensions') . ' AS e ON e.element = a.lang_code') ->where('e.client_id = 0') ->where('e.enabled = 1') ->where('e.state = 0'); $db->setQuery($query); try { $languages = $db->loadObjectList(); } catch (\RuntimeException $e) { $languages = []; if (Factory::getUser()->authorise('core.admin')) { Factory::getApplication()->enqueueMessage($e->getMessage(), 'error'); } } // Merge any additional options in the XML definition. return array_merge(parent::getOptions(), $languages); } } Field/PluginsField.php 0000644 00000012266 15173135670 0010704 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\Log\Log; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Framework. * * @since 2.5.0 */ class PluginsField extends ListField { /** * The field type. * * @var string * @since 2.5.0 */ protected $type = 'Plugins'; /** * The path to folder for plugins. * * @var string * @since 3.2 */ protected $folder; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { if ($name === 'folder') { return $this->folder; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'folder': $this->folder = (string) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { $this->folder = (string) $this->element['folder']; } return $return; } /** * Method to get a list of options for a list input. * * @return object[] An array of JHtml options. * * @since 2.5.0 */ protected function getOptions() { $folder = $this->folder; $parentOptions = parent::getOptions(); if (empty($folder)) { Log::add(Text::_('JFRAMEWORK_FORM_FIELDS_PLUGINS_ERROR_FOLDER_EMPTY'), Log::WARNING, 'jerror'); return $parentOptions; } // Get list of plugins $db = $this->getDatabase(); $query = $db->getQuery(true) ->select( [ $db->quoteName('element', 'value'), $db->quoteName('name', 'text'), ] ) ->from($db->quoteName('#__extensions')) ->where( [ $db->quoteName('folder') . ' = :folder', $db->quoteName('enabled') . ' = 1', ] ) ->bind(':folder', $folder) ->order( [ $db->quoteName('ordering'), $db->quoteName('name'), ] ); if ((string) $this->element['useaccess'] === 'true') { $query->whereIn($db->quoteName('access'), Factory::getUser()->getAuthorisedViewLevels()); } $options = $db->setQuery($query)->loadObjectList(); $lang = Factory::getLanguage(); $useGlobal = $this->element['useglobal']; if ($useGlobal) { $globalValue = Factory::getApplication()->get($this->fieldname); } foreach ($options as $i => $item) { $source = JPATH_PLUGINS . '/' . $folder . '/' . $item->value; $extension = 'plg_' . $folder . '_' . $item->value; $lang->load($extension . '.sys', JPATH_ADMINISTRATOR) || $lang->load($extension . '.sys', $source); $item->text = Text::_($item->text); // If we are using useglobal update the use global value text with the plugin text. if ($useGlobal && isset($parentOptions[0]) && $item->value === $globalValue) { $text = Text::_($extension); $parentOptions[0]->text = Text::sprintf('JGLOBAL_USE_GLOBAL_VALUE', ($text === '' || $text === $extension ? $item->value : $text)); } } return array_merge($parentOptions, $options); } } Field/MenuField.php 0000644 00000007374 15173135670 0010173 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\Database\ParameterType; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Supports an HTML select list of menus * * @since 1.6 */ class MenuField extends GroupedlistField { /** * The form field type. * * @var string * @since 1.6 */ public $type = 'Menu'; /** * Method to get the field option groups. * * @return array[] The field option objects as a nested array in groups. * * @since 1.7.0 * @throws \UnexpectedValueException */ protected function getGroups() { $clientId = (string) $this->element['clientid']; $accessType = (string) $this->element['accesstype']; $showAll = (string) $this->element['showAll'] === 'true'; $db = $this->getDatabase(); $query = $db->getQuery(true) ->select( [ $db->quoteName('id'), $db->quoteName('menutype', 'value'), $db->quoteName('title', 'text'), $db->quoteName('client_id'), ] ) ->from($db->quoteName('#__menu_types')) ->order( [ $db->quoteName('client_id'), $db->quoteName('title'), ] ); if (\strlen($clientId)) { $client = (int) $clientId; $query->where($db->quoteName('client_id') . ' = :client') ->bind(':client', $client, ParameterType::INTEGER); } $menus = $db->setQuery($query)->loadObjectList(); if ($accessType) { $user = Factory::getUser(); foreach ($menus as $key => $menu) { switch ($accessType) { case 'create': case 'manage': if (!$user->authorise('core.' . $accessType, 'com_menus.menu.' . (int) $menu->id)) { unset($menus[$key]); } break; // Editing a menu item is a bit tricky, we have to check the current menutype for core.edit and all others for core.create case 'edit': $check = $this->value == $menu->value ? 'edit' : 'create'; if (!$user->authorise('core.' . $check, 'com_menus.menu.' . (int) $menu->id)) { unset($menus[$key]); } break; } } } $opts = []; // Protected menutypes can be shown if requested if ($clientId == 1 && $showAll) { $opts[] = (object) [ 'value' => 'main', 'text' => Text::_('COM_MENUS_MENU_TYPE_PROTECTED_MAIN_LABEL'), 'client_id' => 1, ]; } $options = array_merge($opts, $menus); $groups = []; if (\strlen($clientId)) { $groups[0] = $options; } else { foreach ($options as $option) { // If client id is not specified we group the items. $label = ($option->client_id == 1 ? Text::_('JADMINISTRATOR') : Text::_('JSITE')); $groups[$label][] = $option; } } // Merge any additional options in the XML definition. return array_merge(parent::getGroups(), $groups); } } Field/CalendarField.php 0000644 00000033276 15173135670 0011000 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use DateTime; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormField; use Joomla\CMS\Language\Text; use Joomla\Registry\Registry; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * * Provides a pop up date picker linked to a button. * Optionally may be filtered to use user's or server's time zone. * * @since 1.7.0 */ class CalendarField extends FormField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Calendar'; /** * The allowable maxlength of calendar field. * * @var integer * @since 3.2 */ protected $maxlength; /** * The format of date and time. * * @var string * @since 3.2 */ protected $format; /** * The format will be used to filter submitted date and time. * * @var string * @since 4.0.1 */ protected $filterFormat; /** * The filter. * * @var string * @since 3.2 */ protected $filter; /** * The minimum year number to subtract/add from the current year * * @var integer * @since 3.7.0 */ protected $minyear; /** * The maximum year number to subtract/add from the current year * * @var integer * @since 3.7.0 */ protected $maxyear; /** * The today button flag * * @var string * @since 4.3.0 */ protected $todaybutton; /** * The week numbers flag * * @var string * @since 4.3.0 */ protected $weeknumbers; /** * The show time flag * * @var string * @since 4.3.0 */ protected $showtime; /** * The fill table flag * * @var string * @since 4.3.0 */ protected $filltable; /** * The time format * * @var integer * @since 4.3.0 */ protected $timeformat; /** * The single header flag * * @var string * @since 4.3.0 */ protected $singleheader; /** * Name of the layout being used to render the field * * @var string * @since 3.7.0 */ protected $layout = 'joomla.form.field.calendar'; /** * The parent class of the field * * @var string * @since 4.0.0 */ protected $parentclass; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'maxlength': case 'format': case 'filterFormat': case 'filter': case 'timeformat': case 'todaybutton': case 'singleheader': case 'weeknumbers': case 'showtime': case 'filltable': case 'minyear': case 'maxyear': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'maxlength': case 'maxyear': case 'minyear': case 'timeformat': $this->$name = (int) $value; break; case 'todaybutton': case 'singleheader': case 'weeknumbers': case 'showtime': case 'filltable': case 'format': case 'filterFormat': case 'filter': $this->$name = (string) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { $this->maxlength = (int) $this->element['maxlength'] ? (int) $this->element['maxlength'] : 45; $this->format = (string) $this->element['format'] ? (string) $this->element['format'] : '%Y-%m-%d'; $this->filterFormat = (string) $this->element['filterformat'] ? (string) $this->element['filterformat'] : ''; $this->filter = (string) $this->element['filter'] ? (string) $this->element['filter'] : 'USER_UTC'; $this->todaybutton = (string) $this->element['todaybutton'] ? (string) $this->element['todaybutton'] : 'true'; $this->weeknumbers = (string) $this->element['weeknumbers'] ? (string) $this->element['weeknumbers'] : 'true'; $this->showtime = (string) $this->element['showtime'] ? (string) $this->element['showtime'] : 'false'; $this->filltable = (string) $this->element['filltable'] ? (string) $this->element['filltable'] : 'true'; $this->timeformat = (int) $this->element['timeformat'] ? (int) $this->element['timeformat'] : 24; $this->singleheader = (string) $this->element['singleheader'] ? (string) $this->element['singleheader'] : 'false'; $this->minyear = \strlen((string) $this->element['minyear']) ? (int) $this->element['minyear'] : null; $this->maxyear = \strlen((string) $this->element['maxyear']) ? (int) $this->element['maxyear'] : null; if ($this->maxyear < 0 || $this->minyear > 0) { $this->todaybutton = 'false'; } $translateFormat = (string) $this->element['translateformat']; if ($translateFormat && $translateFormat !== 'false') { $showTime = (string) $this->element['showtime']; $lang = Factory::getLanguage(); $debug = $lang->setDebug(false); if ($showTime && $showTime !== 'false') { $this->format = Text::_('DATE_FORMAT_CALENDAR_DATETIME'); $this->filterFormat = Text::_('DATE_FORMAT_FILTER_DATETIME'); } else { $this->format = Text::_('DATE_FORMAT_CALENDAR_DATE'); $this->filterFormat = Text::_('DATE_FORMAT_FILTER_DATE'); } $lang->setDebug($debug); } } return $return; } /** * Method to get the field input markup. * * @return string The field input markup. * * @since 1.7.0 */ protected function getInput() { $user = Factory::getApplication()->getIdentity(); // If a known filter is given use it. switch (strtoupper($this->filter)) { case 'SERVER_UTC': // Convert a date to UTC based on the server timezone. if ($this->value && $this->value != $this->getDatabase()->getNullDate()) { // Get a date object based on the correct timezone. $date = Factory::getDate($this->value, 'UTC'); $date->setTimezone(new \DateTimeZone(Factory::getApplication()->get('offset'))); // Transform the date string. $this->value = $date->format('Y-m-d H:i:s', true, false); } break; case 'USER_UTC': // Convert a date to UTC based on the user timezone. if ($this->value && $this->value != $this->getDatabase()->getNullDate()) { // Get a date object based on the correct timezone. $date = Factory::getDate($this->value, 'UTC'); $date->setTimezone($user->getTimezone()); // Transform the date string. $this->value = $date->format('Y-m-d H:i:s', true, false); } break; } // Format value when not nulldate ('0000-00-00 00:00:00'), otherwise blank it as it would result in 1970-01-01. if ($this->value && $this->value != $this->getDatabase()->getNullDate() && strtotime($this->value) !== false) { $tz = date_default_timezone_get(); date_default_timezone_set('UTC'); if ($this->filterFormat) { $date = \DateTimeImmutable::createFromFormat('U', strtotime($this->value)); $this->value = $date->format($this->filterFormat); } else { $this->value = strftime($this->format, strtotime($this->value)); } date_default_timezone_set($tz); } else { $this->value = ''; } return $this->getRenderer($this->layout)->render($this->getLayoutData()); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.7.0 */ protected function getLayoutData() { $data = parent::getLayoutData(); $lang = Factory::getApplication()->getLanguage(); $calendar = $lang->getCalendar(); $direction = strtolower(Factory::getDocument()->getDirection()); // Get the appropriate file for the current language date helper $helperPath = 'system/fields/calendar-locales/date/gregorian/date-helper.min.js'; if ($calendar && is_dir(JPATH_ROOT . '/media/system/js/fields/calendar-locales/date/' . strtolower($calendar))) { $helperPath = 'system/fields/calendar-locales/date/' . strtolower($calendar) . '/date-helper.min.js'; } $extraData = [ 'value' => $this->value, 'maxLength' => $this->maxlength, 'format' => $this->format, 'filter' => $this->filter, 'todaybutton' => ($this->todaybutton === 'true') ? 1 : 0, 'weeknumbers' => ($this->weeknumbers === 'true') ? 1 : 0, 'showtime' => ($this->showtime === 'true') ? 1 : 0, 'filltable' => ($this->filltable === 'true') ? 1 : 0, 'timeformat' => $this->timeformat, 'singleheader' => ($this->singleheader === 'true') ? 1 : 0, 'helperPath' => $helperPath, 'minYear' => $this->minyear, 'maxYear' => $this->maxyear, 'direction' => $direction, 'calendar' => $calendar, 'firstday' => $lang->getFirstDay(), 'weekend' => explode(',', $lang->getWeekEnd()), ]; return array_merge($data, $extraData); } /** * Method to filter a field value. * * @param mixed $value The optional value to use as the default for the field. * @param string $group The optional dot-separated form group path on which to find the field. * @param ?Registry $input An optional Registry object with the entire data set to filter * against the entire form. * * @return mixed The filtered value. * * @since 4.0.0 */ public function filter($value, $group = null, Registry $input = null) { // Make sure there is a valid SimpleXMLElement. if (!($this->element instanceof \SimpleXMLElement)) { throw new \UnexpectedValueException(sprintf('%s::filter `element` is not an instance of SimpleXMLElement', \get_class($this))); } if ((int) $value <= 0) { return ''; } if ($this->filterFormat) { $value = \DateTime::createFromFormat($this->filterFormat, $value)->format('Y-m-d H:i:s'); } $app = Factory::getApplication(); // Get the field filter type. $filter = (string) $this->element['filter']; $return = $value; switch (strtoupper($filter)) { // Convert a date to UTC based on the server timezone offset. case 'SERVER_UTC': // Return an SQL formatted datetime string in UTC. $return = Factory::getDate($value, $app->get('offset'))->toSql(); break; // Convert a date to UTC based on the user timezone offset. case 'USER_UTC': // Get the user timezone setting defaulting to the server timezone setting. $offset = $app->getIdentity()->getParam('timezone', $app->get('offset')); // Return an SQL formatted datetime string in UTC. $return = Factory::getDate($value, $offset)->toSql(); break; } return $return; } } Field/PluginstatusField.php 0000644 00000001416 15173135670 0011760 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2017 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Plugin Status field. * * @since 3.5 */ class PluginstatusField extends PredefinedlistField { /** * The form field type. * * @var string * @since 3.5 */ public $type = 'Plugin_Status'; /** * Available statuses * * @var string[] * @since 3.5 */ protected $predefinedOptions = [ '0' => 'JDISABLED', '1' => 'JENABLED', ]; } Field/ContenttypeField.php 0000644 00000005503 15173135670 0011573 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Content Type field. * * @since 3.1 */ class ContenttypeField extends ListField { /** * A flexible tag list that respects access controls * * @var string * @since 3.1 */ public $type = 'Contenttype'; /** * Method to get the field input for a list of content types. * * @return string The field input. * * @since 3.1 */ protected function getInput() { if (!\is_array($this->value)) { if (\is_object($this->value)) { $this->value = $this->value->tags; } if (\is_string($this->value)) { $this->value = explode(',', $this->value); } } return parent::getInput(); } /** * Method to get a list of content types * * @return object[] The field option objects. * * @since 3.1 */ protected function getOptions() { $lang = Factory::getLanguage(); $db = $this->getDatabase(); $query = $db->getQuery(true) ->select( [ $db->quoteName('a.type_id', 'value'), $db->quoteName('a.type_title', 'text'), $db->quoteName('a.type_alias', 'alias'), ] ) ->from($db->quoteName('#__content_types', 'a')) ->order($db->quoteName('a.type_title') . ' ASC'); // Get the options. $db->setQuery($query); try { $options = $db->loadObjectList(); } catch (\RuntimeException $e) { return []; } foreach ($options as $option) { // Make up the string from the component sys.ini file $parts = explode('.', $option->alias); $comp = array_shift($parts); // Make sure the component sys.ini is loaded $lang->load($comp . '.sys', JPATH_ADMINISTRATOR) || $lang->load($comp . '.sys', JPATH_ADMINISTRATOR . '/components/' . $comp); $option->string = implode('_', $parts); $option->string = $comp . '_CONTENT_TYPE_' . $option->string; if ($lang->hasKey($option->string)) { $option->text = Text::_($option->string); } } // Merge any additional options in the XML definition. $options = array_merge(parent::getOptions(), $options); return $options; } } Field/RadioField.php 0000644 00000002443 15173135670 0010315 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides radio button inputs * * @link https://html.spec.whatwg.org/multipage/input.html#radio-button-state-(type=radio) * @since 1.7.0 */ class RadioField extends ListField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Radio'; /** * Name of the layout being used to render the field * * @var string * @since 3.5 */ protected $layout = 'joomla.form.field.radio.buttons'; /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.5 */ protected function getLayoutData() { $data = parent::getLayoutData(); $extraData = [ 'options' => $this->getOptions(), 'value' => (string) $this->value, ]; return array_merge($data, $extraData); } } Field/TimezoneField.php 0000644 00000010743 15173135670 0011053 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\HTML\HTMLHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * * @since 1.7.0 */ class TimezoneField extends GroupedlistField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Timezone'; /** * The list of available timezone groups to use. * * @var string[] * @since 1.7.0 */ protected static $zones = ['Africa', 'America', 'Antarctica', 'Arctic', 'Asia', 'Atlantic', 'Australia', 'Europe', 'Indian', 'Pacific']; /** * The keyField of timezone field. * * @var integer * @since 3.2 */ protected $keyField; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { if ($name === 'keyField') { return $this->keyField; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'keyField': $this->keyField = (string) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { $this->keyField = (string) $this->element['key_field']; } return $return; } /** * Method to get the time zone field option groups. * * @return array[] The field option objects as a nested array in groups. * * @since 1.7.0 */ protected function getGroups() { $groups = []; // Get the list of time zones from the server. $zones = \DateTimeZone::listIdentifiers(); // Build the group lists. foreach ($zones as $zone) { // Time zones not in a group we will ignore. if (strpos($zone, '/') === false) { continue; } // Get the group/locale from the timezone. list($group, $locale) = explode('/', $zone, 2); // Only use known groups. if (\in_array($group, self::$zones)) { // Initialize the group if necessary. if (!isset($groups[$group])) { $groups[$group] = []; } // Only add options where a locale exists. if (!empty($locale)) { $groups[$group][$zone] = HTMLHelper::_('select.option', $zone, str_replace('_', ' ', $locale), 'value', 'text', false); } } } // Sort the group lists. ksort($groups); foreach ($groups as &$location) { sort($location); } // Merge any additional groups in the XML definition. $groups = array_merge(parent::getGroups(), $groups); return $groups; } } Field/CheckboxField.php 0000644 00000007733 15173135670 0011014 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Form\FormField; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Single checkbox field. * This is a boolean field with null for false and the specified option for true * * @link https://html.spec.whatwg.org/multipage/input.html#checkbox-state-(type=checkbox) * @see CheckboxField * @since 1.7.0 */ class CheckboxField extends FormField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Checkbox'; /** * Name of the layout being used to render the field * * @var string * @since 4.0.0 */ protected $layout = 'joomla.form.field.checkbox'; /** * The checked state of checkbox field. * * @var boolean * @since 3.2 */ protected $checked = false; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { if ($name === 'checked') { return $this->checked; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { if ($name === 'checked') { $value = (string) $value; $this->checked = ($value === 'true' || $value == $name || $value === '1'); return; } parent::__set($name, $value); } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { // Handle the default attribute $default = (string) $element['default']; if ($default) { $test = $this->form->getValue((string) $element['name'], $group); $value = ($test == $default) ? $default : null; } $return = parent::setup($element, $value, $group); if ($return) { $checked = (string) $this->element['checked']; $this->checked = ($checked === 'true' || $checked === 'checked' || $checked === '1'); empty($this->value) || $this->checked ? null : $this->checked = true; } return $return; } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 4.0.0 */ protected function getLayoutData() { $data = parent::getLayoutData(); $data['value'] = $this->default ?: '1'; $data['checked'] = $this->checked || $this->value; return $data; } } Field/SpacerField.php 0000644 00000007735 15173135670 0010505 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormField; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides spacer markup to be used in form layouts. * * @since 1.7.0 */ class SpacerField extends FormField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Spacer'; /** * Method to get the field input markup for a spacer. * The spacer does not have accept input. * * @return string The field input markup. * * @since 1.7.0 */ protected function getInput() { return ' '; } /** * Method to get the field label markup for a spacer. * Use the label text or name from the XML element as the spacer or * Use a hr="true" to automatically generate plain hr markup * * @return string The field label markup. * * @since 1.7.0 */ protected function getLabel() { $html = []; $class = !empty($this->class) ? ' class="' . $this->class . '"' : ''; $html[] = '<span class="spacer">'; $html[] = '<span class="before"></span>'; $html[] = '<span' . $class . '>'; if ((string) $this->element['hr'] === 'true') { $html[] = '<hr' . $class . '>'; } else { $label = ''; // Get the label text from the XML element, defaulting to the element name. $text = $this->element['label'] ? (string) $this->element['label'] : (string) $this->element['name']; $text = $this->translateLabel ? Text::_($text) : $text; // Build the class for the label. $class = !empty($this->description) ? 'hasPopover' : ''; $class = $this->required == true ? $class . ' required' : $class; // Add the opening label tag and main attributes attributes. $label .= '<label id="' . $this->id . '-lbl" class="' . $class . '"'; // If a description is specified, use it to build a tooltip. if (!empty($this->description)) { HTMLHelper::_('bootstrap.popover', '.hasPopover'); $label .= ' title="' . htmlspecialchars(trim($text, ':'), ENT_COMPAT, 'UTF-8') . '"'; $label .= ' data-bs-content="' . htmlspecialchars( $this->translateDescription ? Text::_($this->description) : $this->description, ENT_COMPAT, 'UTF-8' ) . '"'; if (Factory::getLanguage()->isRtl()) { $label .= ' data-bs-placement="left"'; } } // Add the label text and closing tag. $label .= '>' . $text . '</label>'; $html[] = $label; } $html[] = '</span>'; $html[] = '<span class="after"></span>'; $html[] = '</span>'; return implode('', $html); } /** * Method to get the field title. * * @return string The field title. * * @since 1.7.0 */ protected function getTitle() { return $this->getLabel(); } /** * Method to get a control group with label and input. * * @param array $options Options to be passed into the rendering of the field * * @return string A string containing the html for the control group * * @since 3.7.3 */ public function renderField($options = []) { $options['class'] = empty($options['class']) ? 'field-spacer' : $options['class'] . ' field-spacer'; return parent::renderField($options); } } Field/ModuletagField.php 0000644 00000002257 15173135670 0011203 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\HTML\HTMLHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Module Tag field. * * @since 3.0 */ class ModuletagField extends ListField { /** * The form field type. * * @var string * @since 3.0 */ protected $type = 'ModuleTag'; /** * Method to get the field options. * * @return object[] The field option objects. * * @since 3.0 */ protected function getOptions() { $options = []; $tags = ['address', 'article', 'aside', 'details', 'div', 'footer', 'header', 'main', 'nav', 'section', 'summary']; // Create one new option object for each tag foreach ($tags as $tag) { $tmp = HTMLHelper::_('select.option', $tag, $tag); $options[] = $tmp; } reset($options); return $options; } } Field/ComboField.php 0000644 00000003217 15173135670 0010316 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Implements a combo box field. * * @since 1.7.0 */ class ComboField extends ListField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Combo'; /** * Name of the layout being used to render the field * * @var string * @since 3.8.0 */ protected $layout = 'joomla.form.field.combo'; /** * Method to get the field input markup for a combo box field. * * @return string The field input markup. * * @since 1.7.0 */ protected function getInput() { if (empty($this->layout)) { throw new \UnexpectedValueException(sprintf('%s has no layout assigned.', $this->name)); } return $this->getRenderer($this->layout)->render($this->getLayoutData()); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.8.0 */ protected function getLayoutData() { $data = parent::getLayoutData(); // Get the field options. $options = $this->getOptions(); $extraData = [ 'options' => $options, ]; return array_merge($data, $extraData); } } Field/CachehandlerField.php 0000644 00000002424 15173135670 0011617 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Cache\Cache; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides a list of available cache handlers * * @see JCache * @since 1.7.0 */ class CachehandlerField extends ListField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Cachehandler'; /** * Method to get the field options. * * @return object[] The field option objects. * * @since 1.7.0 */ protected function getOptions() { $options = []; // Convert to name => name array. foreach (Cache::getStores() as $store) { $options[] = HTMLHelper::_('select.option', $store, Text::_('JLIB_FORM_VALUE_CACHE_' . $store), 'value', 'text'); } $options = array_merge(parent::getOptions(), $options); return $options; } } Field/ColorField.php 0000644 00000023352 15173135670 0010337 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormField; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Color Form Field class for the Joomla Platform. * This implementation is designed to be compatible with HTML5's `<input type="color">` * * @link https://html.spec.whatwg.org/multipage/input.html#color-state-(type=color) * @since 1.7.3 */ class ColorField extends FormField { /** * The form field type. * * @var string * @since 1.7.3 */ protected $type = 'Color'; /** * The control. * * @var mixed * @since 3.2 */ protected $control = 'hue'; /** * Default color when there is no value. * * @var string * @since 4.0.0 */ protected $default; /** * The type of value the slider should display: 'hue', 'saturation' or 'light'. * * @var string * @since 4.0.0 */ protected $display = 'hue'; /** * The format. * * @var string * @since 3.6.0 */ protected $format = 'hex'; /** * The keywords (transparent,initial,inherit). * * @var string * @since 3.6.0 */ protected $keywords = ''; /** * The position. * * @var mixed * @since 3.2 */ protected $position = 'default'; /** * The colors. * * @var mixed * @since 3.2 */ protected $colors; /** * Shows preview of the selected color * * @var boolean * @since 4.0.0 */ protected $preview = false; /** * Color format to use when value gets saved * * @var string * @since 4.0.0 */ protected $saveFormat = 'hex'; /** * The split. * * @var integer * @since 3.2 */ protected $split = 3; /** * Name of the layout being used to render the field * * @var string * @since 3.5 */ protected $layout = 'joomla.form.field.color'; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'colors': case 'control': case 'default': case 'display': case 'format': case 'keywords': case 'preview': case 'saveFormat': case 'split': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'colors': case 'control': case 'default': case 'display': case 'format': case 'keywords': case 'saveFormat': $this->$name = (string) $value; break; case 'split': $this->$name = (int) $value; break; case 'preview': $this->$name = (bool) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { $this->colors = (string) $this->element['colors']; $this->control = isset($this->element['control']) ? (string) $this->element['control'] : 'hue'; $this->default = (string) $this->element['default']; $this->display = isset($this->element['display']) ? (string) $this->element['display'] : 'hue'; $this->format = isset($this->element['format']) ? (string) $this->element['format'] : 'hex'; $this->keywords = (string) $this->element['keywords']; $this->position = isset($this->element['position']) ? (string) $this->element['position'] : 'default'; $this->preview = isset($this->element['preview']) ? (string) $this->element['preview'] : false; $this->saveFormat = isset($this->element['saveFormat']) ? (string) $this->element['saveFormat'] : 'hex'; $this->split = isset($this->element['split']) ? (int) $this->element['split'] : 3; } return $return; } /** * Method to get the field input markup. * * @return string The field input markup. * * @since 1.7.3 */ protected function getInput() { // Switch the layouts if ($this->control === 'simple' || $this->control === 'slider') { $this->layout .= '.' . $this->control; } else { $this->layout .= '.advanced'; } // Trim the trailing line in the layout file return rtrim($this->getRenderer($this->layout)->render($this->getLayoutData()), PHP_EOL); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.5 */ protected function getLayoutData() { $lang = Factory::getApplication()->getLanguage(); $data = parent::getLayoutData(); $color = strtolower($this->value); $color = !$color && $color !== '0' ? '' : $color; // Position of the panel can be: right (default), left, top or bottom (default RTL is left) $position = ' data-position="' . (($lang->isRtl() && $this->position === 'default') ? 'left' : $this->position) . '"'; if ($color === '' || \in_array($color, ['none', 'transparent'])) { $color = 'none'; } elseif ($color[0] !== '#' && $this->format === 'hex') { $color = '#' . $color; } switch ($this->control) { case 'simple': $controlModeData = $this->getSimpleModeLayoutData(); break; case 'slider': $controlModeData = $this->getSliderModeLayoutData(); break; case 'advanced': default: $controlModeData = $this->getAdvancedModeLayoutData($lang); break; } $extraData = [ 'color' => $color, 'format' => $this->format, 'keywords' => $this->keywords, 'position' => $position, 'validate' => $this->validate, ]; return array_merge($data, $extraData, $controlModeData); } /** * Method to get the data for the simple mode to be passed to the layout for rendering. * * @return array * * @since 3.5 */ protected function getSimpleModeLayoutData() { $colors = strtolower($this->colors); if (empty($colors)) { $colors = [ 'none', '#049cdb', '#46a546', '#9d261d', '#ffc40d', '#f89406', '#c3325f', '#7a43b6', '#ffffff', '#999999', '#555555', '#000000', ]; } else { $colors = explode(',', $colors); } if (!$this->split) { $count = \count($colors); if ($count % 5 == 0) { $split = 5; } else { if ($count % 4 == 0) { $split = 4; } } } $split = $this->split ?: 3; return [ 'colors' => $colors, 'split' => $split, ]; } /** * Method to get the data for the advanced mode to be passed to the layout for rendering. * * @param object $lang The language object * * @return array * * @since 3.5 */ protected function getAdvancedModeLayoutData($lang) { return [ 'colors' => $this->colors, 'control' => $this->control, 'lang' => $lang, ]; } /** * Method to get the data for the slider * * @return array * * @since 4.0.0 */ protected function getSliderModeLayoutData() { return [ 'default' => $this->default, 'display' => $this->display, 'preview' => $this->preview, 'saveFormat' => $this->saveFormat, ]; } } Field/SessionhandlerField.php 0000644 00000002574 15173135670 0012245 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Session\Session; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides a select list of session handler options. * * @since 1.7.0 */ class SessionhandlerField extends ListField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Sessionhandler'; /** * Method to get the session handler field options. * * @return object[] The field option objects. * * @since 1.7.0 */ protected function getOptions() { $options = []; // Get the options from the session object. foreach (Session::getHandlers() as $store) { $options[] = HTMLHelper::_('select.option', strtolower($store), Text::_('JLIB_FORM_VALUE_SESSION_' . $store), 'value', 'text'); } // Merge any additional options in the XML definition. $options = array_merge(parent::getOptions(), $options); return $options; } } Field/UsergrouplistField.php 0000644 00000005673 15173135670 0012156 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Access\Access; use Joomla\CMS\Helper\UserGroupsHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Field to load a dropdown list of available user groups * * @since 3.2 */ class UsergrouplistField extends ListField { /** * The form field type. * * @var string * @since 3.2 */ protected $type = 'UserGroupList'; /** * Cached array of the category items. * * @var array[] * @since 3.2 */ protected static $options = []; /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @since 1.7.0 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { if (\is_string($value) && strpos($value, ',') !== false) { $value = explode(',', $value); } return parent::setup($element, $value, $group); } /** * Method to get the options to populate list * * @return object[] The field option objects. * * @since 3.2 */ protected function getOptions() { $options = parent::getOptions(); $checkSuperUser = (int) $this->getAttribute('checksuperusergroup', 0); // Cache user groups base on checksuperusergroup attribute value if (!isset(static::$options[$checkSuperUser])) { $groups = UserGroupsHelper::getInstance()->getAll(); $cacheOptions = []; foreach ($groups as $group) { // Don't list super user groups. if ($checkSuperUser && Access::checkGroup($group->id, 'core.admin')) { continue; } $cacheOptions[] = (object) [ 'text' => str_repeat('- ', $group->level) . $group->title, 'value' => $group->id, 'level' => $group->level, ]; } static::$options[$checkSuperUser] = $cacheOptions; } return array_merge($options, static::$options[$checkSuperUser]); } } Field/RegistrationdaterangeField.php 0000644 00000003155 15173135670 0013605 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\Form\Form; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Registration Date Range field. * * @since 3.2 */ class RegistrationdaterangeField extends PredefinedlistField { /** * The form field type. * * @var string * @since 3.2 */ protected $type = 'RegistrationDateRange'; /** * Available options * * @var string[] * @since 3.2 */ protected $predefinedOptions = [ 'today' => 'COM_USERS_OPTION_RANGE_TODAY', 'past_week' => 'COM_USERS_OPTION_RANGE_PAST_WEEK', 'past_1month' => 'COM_USERS_OPTION_RANGE_PAST_1MONTH', 'past_3month' => 'COM_USERS_OPTION_RANGE_PAST_3MONTH', 'past_6month' => 'COM_USERS_OPTION_RANGE_PAST_6MONTH', 'past_year' => 'COM_USERS_OPTION_RANGE_PAST_YEAR', 'post_year' => 'COM_USERS_OPTION_RANGE_POST_YEAR', ]; /** * Method to instantiate the form field object. * * @param Form $form The form to attach to the form field object. * * @since 1.7.0 */ public function __construct($form = null) { parent::__construct($form); // Load the required language $lang = Factory::getLanguage(); $lang->load('com_users', JPATH_ADMINISTRATOR); } } Field/PredefinedlistField.php 0000644 00000006752 15173135670 0012227 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Language\Text; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field to load a list of predefined values * * @since 3.2 */ abstract class PredefinedlistField extends ListField { /** * The form field type. * * @var string * @since 3.2 */ protected $type = 'Predefinedlist'; /** * Cached array of the category items. * * @var array[] * @since 3.2 */ protected static $options = []; /** * Available predefined options * * @var string[] * @since 3.2 */ protected $predefinedOptions = []; /** * Translate options labels ? * * @var boolean * @since 3.2 */ protected $translate = true; /** * Allows to use only specific values of the predefined list * * @var string[] * @since 4.0.0 */ protected $optionsFilter = []; /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see \Joomla\CMS\Form\FormField::setup() * @since 4.0.0 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { // Note: $this->element['optionsFilter'] is not cast to string here to allow empty string value. $this->optionsFilter = $this->element['optionsFilter'] ? explode(',', (string) $this->element['optionsFilter']) : []; } return $return; } /** * Method to get the options to populate list * * @return object[] The field option objects. * * @since 3.2 */ protected function getOptions() { // Hash for caching $hash = md5($this->element); $type = strtolower($this->type); if (!isset(static::$options[$type][$hash]) && !empty($this->predefinedOptions)) { static::$options[$type][$hash] = parent::getOptions(); $options = []; foreach ($this->predefinedOptions as $value => $text) { $val = (string) $value; if (empty($this->optionsFilter) || in_array($val, $this->optionsFilter, true)) { $text = $this->translate ? Text::_($text) : $text; $options[] = (object) [ 'value' => $value, 'text' => $text, ]; } } static::$options[$type][$hash] = array_merge(static::$options[$type][$hash], $options); } return static::$options[$type][$hash]; } } Field/PasswordField.php 0000644 00000017721 15173135670 0011066 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormField; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Text field for passwords * * @link https://html.spec.whatwg.org/multipage/input.html#password-state-(type=password) * @note Two password fields may be validated as matching using \Joomla\CMS\Form\Rule\EqualsRule * @since 1.7.0 */ class PasswordField extends FormField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Password'; /** * The threshold of password field. * * @var integer * @since 3.2 */ protected $threshold = 66; /** * The allowable minimum length of password. * * @var integer * @since 4.3.0 */ protected $minLength; /** * The allowable maxlength of password. * * @var integer * @since 3.2 */ protected $maxLength; /** * The allowable minimum length of integers. * * @var integer * @since 4.3.0 */ protected $minIntegers; /** * The allowable minimum length of symbols. * * @var integer * @since 4.3.0 */ protected $minSymbols; /** * The allowable minimum length of upper case characters. * * @var integer * @since 4.3.0 */ protected $minUppercase; /** * The allowable minimum length of lower case characters. * * @var integer * @since 4.3.0 */ protected $minLowercase; /** * Whether to attach a password strength meter or not. * * @var boolean * @since 3.2 */ protected $meter = false; /** * Whether to attach a password strength meter or not. * * @var boolean * @since 4.0.0 */ protected $force = false; /** * The rules flag. * * @var bool * @since 4.3.0 */ protected $rules = false; /** * Name of the layout being used to render the field * * @var string * @since 3.7 */ protected $layout = 'joomla.form.field.password'; /** * Attach an unlock button and disable the input field, * also remove the value from the output. * * @var boolean * @since 3.9.24 */ protected $lock = false; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'lock': case 'threshold': case 'maxLength': case 'meter': case 'force': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'maxLength': case 'threshold': $this->$name = (int) $value; break; case 'lock': case 'meter': case 'force': $this->$name = ($value === 'true' || $value === $name || $value === '1'); break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { $lock = (string) $this->element['lock']; $this->lock = ($lock === 'true' || $lock === 'on' || $lock === '1'); $this->maxLength = $this->element['maxlength'] ? (int) $this->element['maxlength'] : 99; $this->threshold = $this->element['threshold'] ? (int) $this->element['threshold'] : 66; $meter = (string) $this->element['strengthmeter']; $this->meter = ($meter === 'true' || $meter === 'on' || $meter === '1'); $force = (string) $this->element['forcePassword']; $this->force = (($force === 'true' || $force === 'on' || $force === '1') && $this->meter === true); $rules = (string) $this->element['rules']; $this->rules = (($rules === 'true' || $rules === 'on' || $rules === '1') && $this->meter === true); // Set some initial values $this->minLength = 12; $this->minIntegers = 0; $this->minSymbols = 0; $this->minUppercase = 0; $this->minLowercase = 0; if (Factory::getApplication()->get('db') != '' && !Factory::getApplication()->isClient('cli_installation')) { $this->minLength = (int) ComponentHelper::getParams('com_users')->get('minimum_length', 12); $this->minIntegers = (int) ComponentHelper::getParams('com_users')->get('minimum_integers', 0); $this->minSymbols = (int) ComponentHelper::getParams('com_users')->get('minimum_symbols', 0); $this->minUppercase = (int) ComponentHelper::getParams('com_users')->get('minimum_uppercase', 0); $this->minLowercase = (int) ComponentHelper::getParams('com_users')->get('minimum_lowercase', 0); } } return $return; } /** * Method to get the field input markup for password. * * @return string The field input markup. * * @since 1.7.0 */ protected function getInput() { // Trim the trailing line in the layout file return rtrim($this->getRenderer($this->layout)->render($this->getLayoutData()), PHP_EOL); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.7 */ protected function getLayoutData() { $data = parent::getLayoutData(); // Initialize some field attributes. $extraData = [ 'lock' => $this->lock, 'maxLength' => $this->maxLength, 'meter' => $this->meter, 'threshold' => $this->threshold, 'minLength' => $this->minLength, 'minIntegers' => $this->minIntegers, 'minSymbols' => $this->minSymbols, 'minUppercase' => $this->minUppercase, 'minLowercase' => $this->minLowercase, 'forcePassword' => $this->force, 'rules' => $this->rules, ]; return array_merge($data, $extraData); } } Field/ChromestyleField.php 0000644 00000015220 15173135670 0011552 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2012 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Filesystem\Folder; use Joomla\CMS\Form\Form; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\Database\ParameterType; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Chrome Styles field. * * @since 3.0 */ class ChromestyleField extends GroupedlistField { /** * The form field type. * * @var string * @since 3.0 */ public $type = 'ChromeStyle'; /** * The client ID. * * @var integer * @since 3.2 */ protected $clientId; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { if ($name === 'clientId') { return $this->clientId; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to get the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'clientId': $this->clientId = (int) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $result = parent::setup($element, $value, $group); if ($result === true) { // Get the client id. $clientId = $this->element['client_id']; if (!isset($clientId)) { $clientName = $this->element['client']; if (isset($clientName)) { $client = ApplicationHelper::getClientInfo($clientName, true); $clientId = $client->id; } } if (!isset($clientId) && $this->form instanceof Form) { $clientId = $this->form->getValue('client_id'); } $this->clientId = (int) $clientId; } return $result; } /** * Method to get the list of template chrome style options * grouped by template. * * @return array[] The field option objects as a nested array in groups. * * @since 3.0 */ protected function getGroups() { $groups = []; // Add Module Style Field $tmp = '---' . Text::_('JLIB_FORM_VALUE_FROM_TEMPLATE') . '---'; $groups[$tmp][] = HTMLHelper::_('select.option', '0', Text::_('JLIB_FORM_VALUE_INHERITED')); $templateStyles = $this->getTemplateModuleStyles(); // Create one new option object for each available style, grouped by templates foreach ($templateStyles as $template => $styles) { $template = ucfirst($template); $groups[$template] = []; foreach ($styles as $style) { $tmp = HTMLHelper::_('select.option', $template . '-' . $style, $style); $groups[$template][] = $tmp; } } reset($groups); return $groups; } /** * Method to get the templates module styles. * * @return string[] The array of styles, grouped by templates. * * @since 3.0 */ protected function getTemplateModuleStyles() { $moduleStyles = []; // Global Layouts $layouts = Folder::files(JPATH_SITE . '/layouts/chromes', '.*\.php'); foreach ($layouts as &$layout) { $layout = basename($layout, '.php'); } $moduleStyles['system'] = $layouts; $templates = $this->getTemplates(); $path = JPATH_ADMINISTRATOR; if ($this->clientId === 0) { $path = JPATH_SITE; } foreach ($templates as $template) { $chromeLayoutPath = $path . '/templates/' . $template->element . '/html/layouts/chromes'; if (!Folder::exists($chromeLayoutPath)) { continue; } $layouts = Folder::files($chromeLayoutPath, '.*\.php'); if ($layouts) { foreach ($layouts as &$layout) { $layout = basename($layout, '.php'); } $moduleStyles[$template->element] = $layouts; } } return $moduleStyles; } /** * Return a list of templates * * @return object[] List of templates * * @since 3.2.1 */ protected function getTemplates() { $db = $this->getDatabase(); // Get the database object and a new query object. $query = $db->getQuery(true); // Build the query. $query->select( [ $db->quoteName('element'), $db->quoteName('name'), ] ) ->from($db->quoteName('#__extensions')) ->where( [ $db->quoteName('client_id') . ' = :clientId', $db->quoteName('type') . ' = ' . $db->quote('template'), $db->quoteName('enabled') . ' = 1', ] ) ->bind(':clientId', $this->clientId, ParameterType::INTEGER); // Set the query and load the templates. $db->setQuery($query); return $db->loadObjectList('element'); } } Field/FolderlistField.php 0000644 00000014736 15173135670 0011376 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\Filesystem\Folder; use Joomla\Filesystem\Path; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Supports an HTML select list of folder * * @since 1.7.0 */ class FolderlistField extends ListField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Folderlist'; /** * The folder name filter. * * @var string * @since 4.0.0 */ protected $folderFilter; /** * The exclude. * * @var string * @since 3.2 */ protected $exclude; /** * The recursive. * * @var bool * @since 3.6 */ protected $recursive; /** * The hideNone. * * @var boolean * @since 3.2 */ protected $hideNone = false; /** * The hideDefault. * * @var boolean * @since 3.2 */ protected $hideDefault = false; /** * The directory. * * @var string * @since 3.2 */ protected $directory; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'folderFilter': case 'exclude': case 'recursive': case 'hideNone': case 'hideDefault': case 'directory': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'folderFilter': case 'directory': case 'exclude': case 'recursive': $this->$name = (string) $value; break; case 'hideNone': case 'hideDefault': $value = (string) $value; $this->$name = ($value === 'true' || $value === $name || $value === '1'); break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { $this->folderFilter = (string) $this->element['folderFilter']; $this->exclude = (string) $this->element['exclude']; $recursive = (string) $this->element['recursive']; $this->recursive = ($recursive === 'true' || $recursive === 'recursive' || $recursive === '1'); $hideNone = (string) $this->element['hide_none']; $this->hideNone = ($hideNone === 'true' || $hideNone === 'hideNone' || $hideNone === '1'); $hideDefault = (string) $this->element['hide_default']; $this->hideDefault = ($hideDefault === 'true' || $hideDefault === 'hideDefault' || $hideDefault === '1'); // Get the path in which to search for file options. $this->directory = (string) $this->element['directory']; } return $return; } /** * Method to get the field options. * * @return object[] The field option objects. * * @since 1.7.0 */ protected function getOptions() { $options = []; $path = $this->directory; if (!is_dir($path)) { if (is_dir(JPATH_ROOT . '/' . $path)) { $path = JPATH_ROOT . '/' . $path; } else { return []; } } $path = Path::clean($path); // Prepend some default options based on field attributes. if (!$this->hideNone) { $options[] = HTMLHelper::_('select.option', '-1', Text::alt('JOPTION_DO_NOT_USE', preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname))); } if (!$this->hideDefault) { $options[] = HTMLHelper::_('select.option', '', Text::alt('JOPTION_USE_DEFAULT', preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname))); } // Get a list of folders in the search path with the given filter. $folders = Folder::folders($path, $this->folderFilter, $this->recursive, true); // Build the options list from the list of folders. if (\is_array($folders)) { foreach ($folders as $folder) { // Remove the root part and the leading / $folder = trim(str_replace($path, '', $folder), DIRECTORY_SEPARATOR); // Check to see if the file is in the exclude mask. if ($this->exclude) { if (preg_match(\chr(1) . $this->exclude . \chr(1), $folder)) { continue; } } $options[] = HTMLHelper::_('select.option', $folder, $folder); } } // Merge any additional options in the XML definition. $options = array_merge(parent::getOptions(), $options); return $options; } } Field/AccesslevelField.php 0000644 00000002020 15173135670 0011477 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\HTML\HTMLHelper; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides a list of access levels. Access levels control what users in specific * groups can see. * * @see JAccess * @since 1.7.0 */ class AccesslevelField extends ListField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Accesslevel'; /** * Method to get the field options. * * @return object[] The field option objects. * * @since 4.0.0 */ protected function getOptions() { return array_merge(parent::getOptions(), HTMLHelper::_('access.assetgroups')); } } Field/ComponentlayoutField.php 0000644 00000023633 15173135670 0012463 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Factory; use Joomla\CMS\Filesystem\Path; use Joomla\CMS\Form\Form; use Joomla\CMS\Form\FormField; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\Database\ParameterType; use Joomla\Filesystem\Folder; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field to display a list of the layouts for a component view from * the extension or template overrides. * * @since 1.6 */ class ComponentlayoutField extends FormField { /** * The form field type. * * @var string * @since 1.6 */ protected $type = 'ComponentLayout'; /** * Method to get the field input for a component layout field. * * @return string The field input. * * @since 1.6 */ protected function getInput() { // Get the client id. $clientId = $this->element['client_id']; if ($clientId === null && $this->form instanceof Form) { $clientId = $this->form->getValue('client_id'); } $clientId = (int) $clientId; $client = ApplicationHelper::getClientInfo($clientId); // Get the extension. $extension = (string) $this->element['extension']; if (empty($extension) && ($this->form instanceof Form)) { $extension = $this->form->getValue('extension'); } $extension = preg_replace('#\W#', '', $extension); $template = (string) $this->element['template']; $template = preg_replace('#\W#', '', $template); $template_style_id = 0; if ($this->form instanceof Form) { $template_style_id = $this->form->getValue('template_style_id', null, 0); $template_style_id = (int) preg_replace('#\W#', '', $template_style_id); } $view = (string) $this->element['view']; $view = preg_replace('#\W#', '', $view); // If a template, extension and view are present build the options. if ($extension && $view && $client) { // Load language file $lang = Factory::getLanguage(); $lang->load($extension . '.sys', JPATH_ADMINISTRATOR) || $lang->load($extension . '.sys', JPATH_ADMINISTRATOR . '/components/' . $extension); // Get the database object and a new query object. $db = $this->getDatabase(); $query = $db->getQuery(true); // Build the query. $query->select( [ $db->quoteName('e.element'), $db->quoteName('e.name'), ] ) ->from($db->quoteName('#__extensions', 'e')) ->where( [ $db->quoteName('e.client_id') . ' = :clientId', $db->quoteName('e.type') . ' = ' . $db->quote('template'), $db->quoteName('e.enabled') . ' = 1', ] ) ->bind(':clientId', $clientId, ParameterType::INTEGER); if ($template) { $query->where($db->quoteName('e.element') . ' = :template') ->bind(':template', $template); } if ($template_style_id) { $query->join('LEFT', $db->quoteName('#__template_styles', 's'), $db->quoteName('s.template') . ' = ' . $db->quoteName('e.element')) ->where($db->quoteName('s.id') . ' = :style') ->bind(':style', $template_style_id, ParameterType::INTEGER); } // Set the query and load the templates. $db->setQuery($query); $templates = $db->loadObjectList('element'); // Build the search paths for component layouts. $component_path = Path::clean($client->path . '/components/' . $extension . '/tmpl/' . $view); // Check if the new layouts folder exists, else use the old one if (!is_dir($component_path)) { $component_path = Path::clean($client->path . '/components/' . $extension . '/views/' . $view . '/tmpl'); } // Prepare array of component layouts $component_layouts = []; // Prepare the grouped list $groups = []; // Add a Use Global option if useglobal="true" in XML file if ((string) $this->element['useglobal'] === 'true') { $groups[Text::_('JOPTION_FROM_STANDARD')]['items'][] = HTMLHelper::_('select.option', '', Text::_('JGLOBAL_USE_GLOBAL')); } // Add the layout options from the component path. if (is_dir($component_path) && ($component_layouts = Folder::files($component_path, '^[^_]*\.xml$', false, true))) { // Create the group for the component $groups['_'] = []; $groups['_']['id'] = $this->id . '__'; $groups['_']['text'] = Text::sprintf('JOPTION_FROM_COMPONENT'); $groups['_']['items'] = []; foreach ($component_layouts as $i => $file) { // Attempt to load the XML file. if (!$xml = simplexml_load_file($file)) { unset($component_layouts[$i]); continue; } // Get the help data from the XML file if present. if (!$menu = $xml->xpath('layout[1]')) { unset($component_layouts[$i]); continue; } $menu = $menu[0]; // Add an option to the component group $value = basename($file, '.xml'); $component_layouts[$i] = $value; $text = isset($menu['option']) ? Text::_($menu['option']) : (isset($menu['title']) ? Text::_($menu['title']) : $value); $groups['_']['items'][] = HTMLHelper::_('select.option', '_:' . $value, $text); } } // Loop on all templates if ($templates) { foreach ($templates as $template) { // Load language file $lang->load('tpl_' . $template->element . '.sys', $client->path) || $lang->load('tpl_' . $template->element . '.sys', $client->path . '/templates/' . $template->element); $template_path = Path::clean( $client->path . '/templates/' . $template->element . '/html/' . $extension . '/' . $view ); // Add the layout options from the template path. if (is_dir($template_path) && ($files = Folder::files($template_path, '^[^_]*\.php$', false, true))) { foreach ($files as $i => $file) { // Remove layout files that exist in the component folder if (\in_array(basename($file, '.php'), $component_layouts)) { unset($files[$i]); } } if (\count($files)) { // Create the group for the template $groups[$template->name] = []; $groups[$template->name]['id'] = $this->id . '_' . $template->element; $groups[$template->name]['text'] = Text::sprintf('JOPTION_FROM_TEMPLATE', $template->name); $groups[$template->name]['items'] = []; foreach ($files as $file) { // Add an option to the template group $value = basename($file, '.php'); $text = $lang ->hasKey( $key = strtoupper( 'TPL_' . $template->name . '_' . $extension . '_' . $view . '_LAYOUT_' . $value ) ) ? Text::_($key) : $value; $groups[$template->name]['items'][] = HTMLHelper::_('select.option', $template->element . ':' . $value, $text); } } } } } // Compute attributes for the grouped list $attr = $this->element['size'] ? ' size="' . (int) $this->element['size'] . '"' : ''; $attr .= $this->element['class'] ? ' class="' . (string) $this->element['class'] . '"' : ''; // Prepare HTML code $html = []; // Compute the current selected values $selected = [$this->value]; // Add a grouped list $html[] = HTMLHelper::_( 'select.groupedlist', $groups, $this->name, ['id' => $this->id, 'group.id' => 'id', 'list.attr' => $attr, 'list.select' => $selected] ); return implode($html); } else { return ''; } } } Field/GroupedlistField.php 0000644 00000012313 15173135670 0011555 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Form\FormField; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Provides a grouped list select field. * * @since 1.7.0 */ class GroupedlistField extends FormField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Groupedlist'; /** * Name of the layout being used to render the field * * @var string * @since 4.0.0 */ protected $layout = 'joomla.form.field.groupedlist'; /** * Method to get the field option groups. * * @return array[] The field option objects as a nested array in groups. * * @since 1.7.0 * @throws \UnexpectedValueException */ protected function getGroups() { $groups = []; $label = 0; foreach ($this->element->children() as $element) { switch ($element->getName()) { // The element is an <option /> case 'option': // Initialize the group if necessary. if (!isset($groups[$label])) { $groups[$label] = []; } $disabled = (string) $element['disabled']; $disabled = ($disabled === 'true' || $disabled === 'disabled' || $disabled === '1'); // Create a new option object based on the <option /> element. $tmp = HTMLHelper::_( 'select.option', ($element['value']) ? (string) $element['value'] : trim((string) $element), Text::alt(trim((string) $element), preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname)), 'value', 'text', $disabled ); // Set some option attributes. $tmp->class = (string) $element['class']; // Set some JavaScript option attributes. $tmp->onclick = (string) $element['onclick']; // Add the option. $groups[$label][] = $tmp; break; // The element is a <group /> case 'group': // Get the group label. if ($groupLabel = (string) $element['label']) { $label = Text::_($groupLabel); } // Initialize the group if necessary. if (!isset($groups[$label])) { $groups[$label] = []; } // Iterate through the children and build an array of options. foreach ($element->children() as $option) { // Only add <option /> elements. if ($option->getName() !== 'option') { continue; } $disabled = (string) $option['disabled']; $disabled = ($disabled === 'true' || $disabled === 'disabled' || $disabled === '1'); // Create a new option object based on the <option /> element. $tmp = HTMLHelper::_( 'select.option', ($option['value']) ? (string) $option['value'] : Text::_(trim((string) $option)), Text::_(trim((string) $option)), 'value', 'text', $disabled ); // Set some option attributes. $tmp->class = (string) $option['class']; // Set some JavaScript option attributes. $tmp->onclick = (string) $option['onclick']; // Add the option. $groups[$label][] = $tmp; } if ($groupLabel) { $label = \count($groups); } break; // Unknown element type. default: throw new \UnexpectedValueException(sprintf('Unsupported element %s in GroupedlistField', $element->getName()), 500); } } reset($groups); return $groups; } /** * Method to get the field input markup for a grouped list. * Multiselect is enabled by using the multiple attribute. * * @return string The field input markup. * * @since 1.7.0 */ protected function getInput() { $data = $this->getLayoutData(); // Get the field groups. $data['groups'] = (array) $this->getGroups(); return $this->getRenderer($this->layout)->render($data); } } Field/UrlField.php 0000644 00000004041 15173135670 0010015 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2011 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Supports a URL text field * * @link https://html.spec.whatwg.org/multipage/input.html#url-state-(type=url) * @see \Joomla\CMS\Form\Rule\UrlRule for validation of full urls * @since 1.7.0 */ class UrlField extends TextField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Url'; /** * Name of the layout being used to render the field * * @var string * @since 3.7 */ protected $layout = 'joomla.form.field.url'; /** * Method to get the field input markup. * * @return string The field input markup. * * @since 3.1.2 (CMS) */ protected function getInput() { // Trim the trailing line in the layout file return rtrim($this->getRenderer($this->layout)->render($this->getLayoutData()), PHP_EOL); } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.7 */ protected function getLayoutData() { $data = parent::getLayoutData(); // Initialize some field attributes. $maxLength = !empty($this->maxLength) ? ' maxlength="' . $this->maxLength . '"' : ''; // Note that the input type "url" is suitable only for external URLs, so if internal URLs are allowed // we have to use the input type "text" instead. $inputType = $this->element['relative'] ? 'type="text"' : 'type="url"'; $extraData = [ 'maxLength' => $maxLength, 'inputType' => $inputType, ]; return array_merge($data, $extraData); } } Field/WorkflowconditionField.php 0000644 00000007433 15173135670 0013004 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Factory; use Joomla\CMS\Language\Text; use Joomla\CMS\Workflow\WorkflowServiceInterface; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Workflow States field. * * @since 4.0.0 */ class WorkflowconditionField extends ListField { /** * The form field type. * * @var string * @since 4.0.0 */ protected $type = 'Workflowcondition'; /** * The component and section separated by ".". * * @var string * @since 4.0.0 */ protected $extension = ''; /** * Determinate if the "All" value should be added * * @var boolean * @since 4.0.0 */ protected $hideAll = false; /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @since 4.0.0 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $success = parent::setup($element, $value, $group); if ($success) { if (\strlen($element['extension'])) { $this->extension = (string) $element['extension']; } else { $this->extension = Factory::getApplication()->getInput()->getCmd('extension'); } if (\strlen($element['hide_all'])) { $this->hideAll = (string) $element['hide_all'] === 'true' || (string) $element['hide_all'] === 'yes'; } } return $success; } /** * Method to get the field options. * * @return object[] The field option objects. * * @since 4.0.0 */ protected function getOptions() { $fieldname = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname); $options = []; $conditions = []; $parts = explode('.', $this->extension); $component = Factory::getApplication()->bootComponent($parts[0]); if ($component instanceof WorkflowServiceInterface) { $conditions = $component->getConditions($this->extension); } foreach ($conditions as $value => $option) { $text = trim((string) $option) != '' ? trim((string) $option) : $value; $selected = ((int) $this->value === $value); $tmp = [ 'value' => $value, 'text' => Text::alt($text, $fieldname), 'selected' => $selected, 'checked' => $selected, ]; // Add the option object to the result set. $options[] = (object) $tmp; } if (!$this->hideAll) { $options[] = (object) [ 'value' => '*', 'text' => Text::_('JALL'), 'selected' => $this->value === '*', 'checked' => $this->value === '*', ]; } // Merge any additional options in the XML definition. return array_merge(parent::getOptions(), $options); } } Field/ContenthistoryField.php 0000644 00000003773 15173135670 0012322 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2013 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Form\FormField; use Joomla\CMS\Language\Text; use Joomla\CMS\Session\Session; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Field to select Content History from a modal list. * * @since 3.2 */ class ContenthistoryField extends FormField { /** * The form field type. * * @var string * @since 3.2 */ public $type = 'ContentHistory'; /** * Layout to render the label * * @var string */ protected $layout = 'joomla.form.field.contenthistory'; /** * Get the data that is going to be passed to the layout * * @return array */ public function getLayoutData() { // Get the basic field data $data = parent::getLayoutData(); $itemId = $this->element['data-typeAlias'] . '.' . $this->form->getValue('id'); $label = Text::_('JTOOLBAR_VERSIONS'); $link = 'index.php?option=com_contenthistory&view=history&layout=modal&tmpl=component&field=' . $this->id . '&item_id=' . $itemId . '&' . Session::getFormToken() . '=1'; $extraData = [ 'item' => $itemId, 'label' => $label, 'link' => $link, ]; return array_merge($data, $extraData); } /** * Method to get the content history field input markup. * * @return string The field input markup. * * @since 3.2 */ protected function getInput() { if (empty($this->layout)) { throw new \UnexpectedValueException(sprintf('%s has no layout assigned.', $this->name)); } return $this->getRenderer($this->layout)->render($this->getLayoutData()); } } Field/FilelistField.php 0000644 00000015135 15173135670 0011034 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2010 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\Filesystem\File; use Joomla\Filesystem\Folder; use Joomla\Filesystem\Path; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Supports an HTML select list of files * * @since 1.7.0 */ class FilelistField extends ListField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Filelist'; /** * The filename filter. * * @var string * @since 4.0.0 */ protected $fileFilter; /** * The exclude. * * @var string * @since 3.2 */ protected $exclude; /** * The hideNone. * * @var boolean * @since 3.2 */ protected $hideNone = false; /** * The hideDefault. * * @var boolean * @since 3.2 */ protected $hideDefault = false; /** * The stripExt. * * @var boolean * @since 3.2 */ protected $stripExt = false; /** * The directory. * * @var string * @since 3.2 */ protected $directory; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'fileFilter': case 'exclude': case 'hideNone': case 'hideDefault': case 'stripExt': case 'directory': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'fileFilter': case 'directory': case 'exclude': $this->$name = (string) $value; break; case 'hideNone': case 'hideDefault': case 'stripExt': $value = (string) $value; $this->$name = ($value === 'true' || $value === $name || $value === '1'); break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $return = parent::setup($element, $value, $group); if ($return) { $this->fileFilter = (string) $this->element['fileFilter']; $this->exclude = (string) $this->element['exclude']; $hideNone = (string) $this->element['hide_none']; $this->hideNone = ($hideNone === 'true' || $hideNone === 'hideNone' || $hideNone === '1'); $hideDefault = (string) $this->element['hide_default']; $this->hideDefault = ($hideDefault === 'true' || $hideDefault === 'hideDefault' || $hideDefault === '1'); $stripExt = (string) $this->element['stripext']; $this->stripExt = ($stripExt === 'true' || $stripExt === 'stripExt' || $stripExt === '1'); // Get the path in which to search for file options. $this->directory = (string) $this->element['directory']; } return $return; } /** * Method to get the list of files for the field options. * Specify the target directory with a directory attribute * Attributes allow an exclude mask and stripping of extensions from file name. * Default attribute may optionally be set to null (no file) or -1 (use a default). * * @return object[] The field option objects. * * @since 1.7.0 */ protected function getOptions() { $options = []; $path = $this->directory; if (!is_dir($path)) { $path = JPATH_ROOT . '/' . $path; } $path = Path::clean($path); // Prepend some default options based on field attributes. if (!$this->hideNone) { $options[] = HTMLHelper::_('select.option', '-1', Text::alt('JOPTION_DO_NOT_USE', preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname))); } if (!$this->hideDefault) { $options[] = HTMLHelper::_('select.option', '', Text::alt('JOPTION_USE_DEFAULT', preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname))); } // Get a list of files in the search path with the given filter. $files = Folder::files($path, $this->fileFilter); // Build the options list from the list of files. if (\is_array($files)) { foreach ($files as $file) { // Check to see if the file is in the exclude mask. if ($this->exclude) { if (preg_match(\chr(1) . $this->exclude . \chr(1), $file)) { continue; } } // If the extension is to be stripped, do it. if ($this->stripExt) { $file = File::stripExt($file); } $options[] = HTMLHelper::_('select.option', $file, $file); } } // Merge any additional options in the XML definition. $options = array_merge(parent::getOptions(), $options); return $options; } } Field/ListField.php 0000644 00000016204 15173135670 0010172 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormField; use Joomla\CMS\Form\FormHelper; use Joomla\CMS\Helper\ModuleHelper; use Joomla\CMS\Language\Associations; use Joomla\CMS\Language\Multilanguage; use Joomla\CMS\Language\Text; use Joomla\CMS\Plugin\PluginHelper; use Joomla\CMS\Uri\Uri; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Supports a generic list of options. * * @since 1.7.0 */ class ListField extends FormField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'List'; /** * Name of the layout being used to render the field * * @var string * @since 4.0.0 */ protected $layout = 'joomla.form.field.list'; /** * Method to get the field input markup for a generic list. * Use the multiple attribute to enable multiselect. * * @return string The field input markup. * * @since 3.7.0 */ protected function getInput() { $data = $this->getLayoutData(); $data['options'] = (array) $this->getOptions(); return $this->getRenderer($this->layout)->render($data); } /** * Method to get the field options. * * @return object[] The field option objects. * * @since 3.7.0 */ protected function getOptions() { $fieldname = preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname); $options = []; foreach ($this->element->xpath('option') as $option) { // Filter requirements $requires = explode(',', (string) $option['requires']); // Requires multilanguage if (\in_array('multilanguage', $requires) && !Multilanguage::isEnabled()) { continue; } // Requires associations if (\in_array('associations', $requires) && !Associations::isEnabled()) { continue; } // Requires adminlanguage if (\in_array('adminlanguage', $requires) && !ModuleHelper::isAdminMultilang()) { continue; } // Requires vote plugin if (\in_array('vote', $requires) && !PluginHelper::isEnabled('content', 'vote')) { continue; } // Requires record hits if (\in_array('hits', $requires) && !ComponentHelper::getParams('com_content')->get('record_hits', 1)) { continue; } $value = (string) $option['value']; $text = trim((string) $option) != '' ? trim((string) $option) : $value; $disabled = (string) $option['disabled']; $disabled = ($disabled === 'true' || $disabled === 'disabled' || $disabled === '1'); $disabled = $disabled || ($this->readonly && $value != $this->value); $checked = (string) $option['checked']; $checked = ($checked === 'true' || $checked === 'checked' || $checked === '1'); $selected = (string) $option['selected']; $selected = ($selected === 'true' || $selected === 'selected' || $selected === '1'); $tmp = [ 'value' => $value, 'text' => Text::alt($text, $fieldname), 'disable' => $disabled, 'class' => (string) $option['class'], 'selected' => ($checked || $selected), 'checked' => ($checked || $selected), ]; // Set some event handler attributes. But really, should be using unobtrusive js. $tmp['onclick'] = (string) $option['onclick']; $tmp['onchange'] = (string) $option['onchange']; if ((string) $option['showon']) { $encodedConditions = json_encode( FormHelper::parseShowOnConditions((string) $option['showon'], $this->formControl, $this->group) ); $tmp['optionattr'] = " data-showon='" . $encodedConditions . "'"; } // Add the option object to the result set. $options[] = (object) $tmp; } if ($this->element['useglobal']) { $tmp = new \stdClass(); $tmp->value = ''; $tmp->text = Text::_('JGLOBAL_USE_GLOBAL'); $component = Factory::getApplication()->getInput()->getCmd('option'); // Get correct component for menu items if ($component === 'com_menus') { $link = $this->form->getData()->get('link'); $uri = new Uri($link); $component = $uri->getVar('option', 'com_menus'); } $params = ComponentHelper::getParams($component); $value = $params->get($this->fieldname); // Try with global configuration if (\is_null($value)) { $value = Factory::getApplication()->get($this->fieldname); } // Try with menu configuration if (\is_null($value) && Factory::getApplication()->getInput()->getCmd('option') === 'com_menus') { $value = ComponentHelper::getParams('com_menus')->get($this->fieldname); } if (!\is_null($value)) { $value = (string) $value; foreach ($options as $option) { if ($option->value === $value) { $value = $option->text; break; } } $tmp->text = Text::sprintf('JGLOBAL_USE_GLOBAL_VALUE', $value); } array_unshift($options, $tmp); } reset($options); return $options; } /** * Method to add an option to the list field. * * @param string $text Text/Language variable of the option. * @param string[] $attributes Array of attributes ('name' => 'value') format * * @return ListField For chaining. * * @since 3.7.0 */ public function addOption($text, $attributes = []) { if ($text && $this->element instanceof \SimpleXMLElement) { $child = $this->element->addChild('option', $text); foreach ($attributes as $name => $value) { $child->addAttribute($name, $value); } } return $this; } /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.7.0 */ public function __get($name) { if ($name === 'options') { return $this->getOptions(); } return parent::__get($name); } } Field/TextField.php 0000644 00000021772 15173135670 0010211 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Component\ComponentHelper; use Joomla\CMS\Factory; use Joomla\CMS\Form\FormField; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\CMS\Uri\Uri; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Form Field class for the Joomla Platform. * Supports a one line text field. * * @link https://html.spec.whatwg.org/multipage/input.html#text-(type=text)-state-and-search-state-(type=search) * @since 1.7.0 */ class TextField extends FormField { /** * The form field type. * * @var string * @since 1.7.0 */ protected $type = 'Text'; /** * The allowable maxlength of the field. * * @var integer * @since 3.2 */ protected $maxLength; /** * Does this field support a character counter? * * @var boolean * @since 4.3.0 */ protected $charcounter = false; /** * The mode of input associated with the field. * * @var mixed * @since 3.2 */ protected $inputmode; /** * The name of the form field direction (ltr or rtl). * * @var string * @since 3.2 */ protected $dirname; /** * Input addon before * * @var string * @since 4.0.0 */ protected $addonBefore; /** * Input addon after * * @var string * @since 4.0.0 */ protected $addonAfter; /** * Name of the layout being used to render the field * * @var string * @since 3.7 */ protected $layout = 'joomla.form.field.text'; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'maxLength': case 'dirname': case 'addonBefore': case 'addonAfter': case 'inputmode': case 'charcounter': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'maxLength': $this->maxLength = (int) $value; break; case 'dirname': $value = (string) $value; $this->dirname = ($value == $name || $value === 'true' || $value === '1'); break; case 'inputmode': $this->inputmode = (string) $value; break; case 'addonBefore': $this->addonBefore = (string) $value; break; case 'addonAfter': $this->addonAfter = (string) $value; break; case 'charcounter': $this->charcounter = strtolower($value) === 'true'; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $result = parent::setup($element, $value, $group); if ($result == true) { $inputmode = (string) $this->element['inputmode']; $dirname = (string) $this->element['dirname']; $this->inputmode = ''; $inputmode = preg_replace('/\s+/', ' ', trim($inputmode)); $inputmode = explode(' ', $inputmode); $defaultInputmode = \in_array('default', $inputmode) ? Text::_('JLIB_FORM_INPUTMODE') . ' ' : ''; foreach (array_keys($inputmode, 'default') as $key) { unset($inputmode[$key]); } $this->inputmode = $defaultInputmode . implode(' ', $inputmode); // Set the dirname. $dirname = ($dirname === 'dirname' || $dirname === 'true' || $dirname === '1'); $this->dirname = $dirname ? $this->getName($this->fieldname . '_dir') : false; $this->maxLength = (int) $this->element['maxlength']; $this->charcounter = isset($this->element['charcounter']) ? strtolower($this->element['charcounter']) === 'true' : false; $this->addonBefore = (string) $this->element['addonBefore']; $this->addonAfter = (string) $this->element['addonAfter']; } return $result; } /** * Method to get the field input markup. * * @return string The field input markup. * * @since 1.7.0 */ protected function getInput() { if ($this->element['useglobal']) { $component = Factory::getApplication()->getInput()->getCmd('option'); // Get correct component for menu items if ($component === 'com_menus') { $link = $this->form->getData()->get('link'); $uri = new Uri($link); $component = $uri->getVar('option', 'com_menus'); } $params = ComponentHelper::getParams($component); $value = $params->get($this->fieldname); // Try with global configuration if (\is_null($value)) { $value = Factory::getApplication()->get($this->fieldname); } // Try with menu configuration if (\is_null($value) && Factory::getApplication()->getInput()->getCmd('option') === 'com_menus') { $value = ComponentHelper::getParams('com_menus')->get($this->fieldname); } if (!\is_null($value)) { $value = (string) $value; $this->hint = Text::sprintf('JGLOBAL_USE_GLOBAL_VALUE', $value); } } return $this->getRenderer($this->layout)->render($this->getLayoutData()); } /** * Method to get the field options. * * @return object[] The field option objects. * * @since 3.4 */ protected function getOptions() { $options = []; foreach ($this->element->children() as $option) { // Only add <option /> elements. if ($option->getName() !== 'option') { continue; } // Create a new option object based on the <option /> element. $options[] = HTMLHelper::_( 'select.option', (string) $option['value'], Text::alt(trim((string) $option), preg_replace('/[^a-zA-Z0-9_\-]/', '_', $this->fieldname)), 'value', 'text' ); } return $options; } /** * Method to get the data to be passed to the layout for rendering. * * @return array * * @since 3.7 */ protected function getLayoutData() { $data = parent::getLayoutData(); // Initialize some field attributes. $maxLength = !empty($this->maxLength) ? ' maxlength="' . $this->maxLength . '"' : ''; $inputmode = !empty($this->inputmode) ? ' inputmode="' . $this->inputmode . '"' : ''; $dirname = !empty($this->dirname) ? ' dirname="' . $this->dirname . '"' : ''; // Get the field options for the datalist. $options = (array) $this->getOptions(); $extraData = [ 'maxLength' => $maxLength, 'pattern' => $this->pattern, 'inputmode' => $inputmode, 'dirname' => $dirname, 'addonBefore' => $this->addonBefore, 'addonAfter' => $this->addonAfter, 'options' => $options, 'charcounter' => $this->charcounter, ]; return array_merge($data, $extraData); } } Field/TemplatestyleField.php 0000644 00000013405 15173135671 0012114 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2009 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form\Field; use Joomla\CMS\Application\ApplicationHelper; use Joomla\CMS\Factory; use Joomla\CMS\HTML\HTMLHelper; use Joomla\CMS\Language\Text; use Joomla\Database\ParameterType; // phpcs:disable PSR1.Files.SideEffects \defined('JPATH_PLATFORM') or die; // phpcs:enable PSR1.Files.SideEffects /** * Supports a select grouped list of template styles * * @since 1.6 */ class TemplatestyleField extends GroupedlistField { /** * The form field type. * * @var string * @since 1.6 */ public $type = 'TemplateStyle'; /** * The client name. * * @var mixed * @since 3.2 */ protected $clientName; /** * The template. * * @var mixed * @since 3.2 */ protected $template; /** * Method to get certain otherwise inaccessible properties from the form field object. * * @param string $name The property name for which to get the value. * * @return mixed The property value or null. * * @since 3.2 */ public function __get($name) { switch ($name) { case 'clientName': case 'template': return $this->$name; } return parent::__get($name); } /** * Method to set certain otherwise inaccessible properties of the form field object. * * @param string $name The property name for which to set the value. * @param mixed $value The value of the property. * * @return void * * @since 3.2 */ public function __set($name, $value) { switch ($name) { case 'clientName': case 'template': $this->$name = (string) $value; break; default: parent::__set($name, $value); } } /** * Method to attach a Form object to the field. * * @param \SimpleXMLElement $element The SimpleXMLElement object representing the `<field>` tag for the form field object. * @param mixed $value The form field value to validate. * @param string $group The field name group control value. This acts as an array container for the field. * For example if the field has name="foo" and the group value is set to "bar" then the * full field name would end up being "bar[foo]". * * @return boolean True on success. * * @see FormField::setup() * @since 3.2 */ public function setup(\SimpleXMLElement $element, $value, $group = null) { $result = parent::setup($element, $value, $group); if ($result === true) { // Get the clientName template. $this->clientName = $this->element['client'] ? (string) $this->element['client'] : 'site'; $this->template = (string) $this->element['template']; } return $result; } /** * Method to get the list of template style options grouped by template. * Use the client attribute to specify a specific client. * Use the template attribute to specify a specific template * * @return array[] The field option objects as a nested array in groups. * * @since 1.6 */ protected function getGroups() { $groups = []; $lang = Factory::getLanguage(); // Get the client and client_id. $client = ApplicationHelper::getClientInfo($this->clientName, true); // Get the template. $template = $this->template; // Get the database object and a new query object. $db = $this->getDatabase(); $query = $db->getQuery(true); // Build the query. $query->select( [ $db->quoteName('s.id'), $db->quoteName('s.title'), $db->quoteName('e.name'), $db->quoteName('s.template'), ] ) ->from($db->quoteName('#__template_styles', 's')) ->where($db->quoteName('s.client_id') . ' = :clientId') ->bind(':clientId', $client->id, ParameterType::INTEGER) ->order( [ $db->quoteName('template'), $db->quoteName('title'), ] ); if ($template) { $query->where('s.template = ' . $db->quote($template)); } $query->join('LEFT', '#__extensions as e on e.element=s.template') ->where('e.enabled = 1') ->where($db->quoteName('e.type') . ' = ' . $db->quote('template')); // Set the query and load the styles. $db->setQuery($query); $styles = $db->loadObjectList(); // Build the grouped list array. if ($styles) { foreach ($styles as $style) { $template = $style->template; $lang->load('tpl_' . $template . '.sys', $client->path) || $lang->load('tpl_' . $template . '.sys', $client->path . '/templates/' . $template); $name = Text::_($style->name); // Initialize the group if necessary. if (!isset($groups[$name])) { $groups[$name] = []; } $groups[$name][] = HTMLHelper::_('select.option', $style->id, $style->title); } } // Merge any additional groups in the XML definition. $groups = array_merge(parent::getGroups(), $groups); return $groups; } } FormFactoryAwareTrait.php 0000644 00000002601 15173135671 0011504 0 ustar 00 <?php /** * Joomla! Content Management System * * @copyright (C) 2018 Open Source Matters, Inc. <https://www.joomla.org> * @license GNU General Public License version 2 or later; see LICENSE.txt */ namespace Joomla\CMS\Form; // phpcs:disable PSR1.Files.SideEffects \defined('_JEXEC') or die; // phpcs:enable PSR1.Files.SideEffects /** * Defines the trait for a FormFactoryInterface Aware Class. * * @since 4.0.0 */ trait FormFactoryAwareTrait { /** * FormFactoryInterface * * @var FormFactoryInterface * @since 4.0.0 */ private $formFactory; /** * Get the FormFactoryInterface. * * @return FormFactoryInterface * * @since 4.0.0 * @throws \UnexpectedValueException May be thrown if the FormFactory has not been set. */ public function getFormFactory(): FormFactoryInterface { if ($this->formFactory) { return $this->formFactory; } throw new \UnexpectedValueException('FormFactory not set in ' . __CLASS__); } /** * Set the form factory to use. * * @param ?FormFactoryInterface $formFactory The form factory to use. * * @return $this * * @since 4.0.0 */ public function setFormFactory(FormFactoryInterface $formFactory = null) { $this->formFactory = $formFactory; return $this; } }
| ver. 1.4 |
Github
|
.
| PHP 8.3.23 | Generation time: 0.01 |
proxy
|
phpinfo
|
Settings