<?php /* Copyright (C) 2004-2014 Laurent Destailleur <eldy@users.sourceforge.net> * Copyright (C) 2005-2011 Regis Houssin <regis.houssin@inodbox.com> * Copyright (C) 2007 Patrick Raguin <patrick.raguin@gmail.com> * Copyright (C) 2024 Frédéric France <frederic.france@free.fr> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <https://www.gnu.org/licenses/>. */ /** * \file htdocs/core/class/html.formadmin.class.php * \ingroup core * \brief File of class for html functions for admin pages */ /** * Class to generate html code for admin pages */ class FormAdmin { /** * @var DoliDB Database handler. */ public $db; /** * @var string error message */ public $error; /** * Constructor * * @param DoliDB|null $db Database handler */ public function __construct($db) { $this->db = $db; } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Return html select list with available languages (key='en_US', value='United States' for example) * * @param string|array $selected Language pre-selected. Can be an array if $multiselect is 1. * @param string $htmlname Name of HTML select * @param int $showauto Show 'auto' choice * @param array $filter Array of keys to exclude in list (opposite of $onlykeys) * @param int|string $showempty '1'=Add empty value or 'string to show' * @param int $showwarning Show a warning if language is not complete * @param int $disabled Disable edit of select * @param string $morecss Add more css styles * @param int $showcode 1=Add language code into label at beginning, 2=Add language code into label at end * @param int $forcecombo Force to use combo box (so no ajax beautify effect) * @param int $multiselect Make the combo a multiselect * @param array $onlykeys Array of language keys to restrict list with the following keys (opposite of $filter). Example array('fr', 'es', ...) * @param int $mainlangonly 1=Show only main languages ('fr_FR' no' fr_BE', 'es_ES' not 'es_MX', ...) * @return string Return HTML select string with list of languages */ public function select_language($selected = '', $htmlname = 'lang_id', $showauto = 0, $filter = array(), $showempty = '', $showwarning = 0, $disabled = 0, $morecss = '', $showcode = 0, $forcecombo = 0, $multiselect = 0, $onlykeys = array(), $mainlangonly = 0) { // phpcs:enable global $langs; if (getDolGlobalString('MAIN_DEFAULT_LANGUAGE_FILTER')) { if (!is_array($filter)) { $filter = array(); } $filter[getDolGlobalString('MAIN_DEFAULT_LANGUAGE_FILTER')] = 1; } $langs_available = $langs->get_available_languages(DOL_DOCUMENT_ROOT, 12, 0, $mainlangonly); // If empty value is not allowed and the language to select is not inside the list of available language and we must find // an alternative of the language code to pre-select (to avoid to have first element in list pre-selected). if ($selected && empty($showempty)) { if (!is_array($selected) && !array_key_exists($selected, $langs_available)) { $tmparray = explode('_', $selected); if (!empty($tmparray[1])) { $selected = getLanguageCodeFromCountryCode($tmparray[1]); } if (empty($selected)) { $selected = $langs->defaultlang; } } else { // If the preselected value is an array, we do not try to find alternative to preselect } } $out = ''; $out .= '<select '.($multiselect ? 'multiple="multiple" ' : '').'class="flat'.($morecss ? ' '.$morecss : '').'" id="'.$htmlname.'" name="'.$htmlname.($multiselect ? '[]' : '').'"'.($disabled ? ' disabled' : '').'>'; if ($showempty && !$multiselect) { if (is_numeric($showempty)) { $out .= '<option value="0"'; } else { $out .= '<option value="-1"'; } if ($selected === '') { $out .= ' selected'; } $out .= '>'; if ($showempty != '1') { $out .= $showempty; } else { $out .= ' '; } $out .= '</option>'; } if ($showauto) { $out .= '<option value="auto"'; if ($selected === 'auto') { $out .= ' selected'; } $out .= '>'.$langs->trans("AutoDetectLang").'</option>'; } asort($langs_available); // array('XX' => 'Language (Country)', ...) foreach ($langs_available as $key => $value) { $valuetoshow = $value; if ($showcode == 1) { if ($mainlangonly) { $valuetoshow = '<span class="opacitymedium">'.preg_replace('/[_-].*$/', '', $key).'</span> - '.$value; } else { $valuetoshow = '<span class="opacitymedium">'.$key.'</span> - '.$value; } } if ($showcode == 2) { if ($mainlangonly) { $valuetoshow = $value.' <span class="opacitymedium">('.preg_replace('/[_-].*$/', '', $key).')</span>'; } else { $valuetoshow = $value.' <span class="opacitymedium">('.$key.')</span>'; } } $keytouse = $key; if ($mainlangonly) { $keytouse = preg_replace('/[_-].*$/', '', $key); } if ($filter && is_array($filter) && array_key_exists($keytouse, $filter)) { continue; } if ($onlykeys && is_array($onlykeys) && !array_key_exists($keytouse, $onlykeys)) { continue; } $valuetoshow = picto_from_langcode($key, 'class="saturatemedium"').' '.$valuetoshow; if ((is_string($selected) && (string) $selected == (string) $keytouse) || (is_array($selected) && in_array($keytouse, $selected))) { $out .= '<option value="'.$keytouse.'" selected data-html="'.dol_escape_htmltag($valuetoshow).'">'.$valuetoshow.'</option>'; } else { $out .= '<option value="'.$keytouse.'" data-html="'.dol_escape_htmltag($valuetoshow).'">'.$valuetoshow.'</option>'; } } $out .= '</select>'; // Make select dynamic if (!$forcecombo) { include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; $out .= ajax_combobox($htmlname); } return $out; } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Return list of available menus (eldy_backoffice, ...) * * @param string $selected Preselected menu value * @param string $htmlname Name of html select * @param array $dirmenuarray Array of directories to scan * @param string $moreattrib More attributes on html select tag * @return integer|void */ public function select_menu($selected, $htmlname, $dirmenuarray, $moreattrib = '') { // phpcs:enable global $langs, $conf; // Clean parameters // Check parameters if (!is_array($dirmenuarray)) { return -1; } $menuarray = array(); foreach ($conf->file->dol_document_root as $dirroot) { foreach ($dirmenuarray as $dirtoscan) { $dir = $dirroot.$dirtoscan; //print $dir.'<br>'; if (is_dir($dir)) { $handle = opendir($dir); if (is_resource($handle)) { while (($file = readdir($handle)) !== false) { if (is_file($dir."/".$file) && substr($file, 0, 1) != '.' && substr($file, 0, 3) != 'CVS' && substr($file, 0, 5) != 'index') { if (preg_match('/lib\.php$/i', $file)) { continue; // We exclude library files } if (preg_match('/eldy_(backoffice|frontoffice)\.php$/i', $file)) { continue; // We exclude all menu manager files } if (preg_match('/auguria_(backoffice|frontoffice)\.php$/i', $file)) { continue; // We exclude all menu manager files } if (preg_match('/smartphone_(backoffice|frontoffice)\.php$/i', $file)) { continue; // We exclude all menu manager files } $filelib = preg_replace('/\.php$/i', '', $file); $prefix = ''; // 0=Recommended, 1=Experimental, 2=Development, 3=Other if (preg_match('/^eldy/i', $file)) { $prefix = '0'; } elseif (preg_match('/^smartphone/i', $file)) { $prefix = '2'; } else { $prefix = '3'; } $morelabel = ''; if (preg_match('/^auguria/i', $file)) { $morelabel .= ' <span class="opacitymedium">('.$langs->trans("Unstable").')</span>'; } if ($file == $selected) { $menuarray[$prefix.'_'.$file] = '<option value="'.$file.'" selected data-html="'.dol_escape_htmltag($filelib.$morelabel).'">'.$filelib.$morelabel; $menuarray[$prefix.'_'.$file] .= '</option>'; } else { $menuarray[$prefix.'_'.$file] = '<option value="'.$file.'" data-html="'.dol_escape_htmltag($filelib.$morelabel).'">'.$filelib.$morelabel; $menuarray[$prefix.'_'.$file] .= '</option>'; } } } closedir($handle); } } } } ksort($menuarray); // Output combo list of menus print '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'"'.($moreattrib ? ' '.$moreattrib : '').'>'; $oldprefix = ''; foreach ($menuarray as $key => $val) { $tab = explode('_', $key); $newprefix = $tab[0]; if ($newprefix == '1' && (getDolGlobalInt('MAIN_FEATURES_LEVEL') < 1)) { continue; } if ($newprefix == '2' && (getDolGlobalInt('MAIN_FEATURES_LEVEL') < 2)) { continue; } if ($newprefix != $oldprefix) { // Add separators // Affiche titre print '<option value="-2" disabled>'; if ($newprefix == '0') { print '-- '.$langs->trans("VersionRecommanded").' --'; } if ($newprefix == '1') { print '-- '.$langs->trans("VersionExperimental").' --'; } if ($newprefix == '2') { print '-- '.$langs->trans("VersionDevelopment").' --'; } if ($newprefix == '3') { print '-- '.$langs->trans("Other").' --'; } print '</option>'; $oldprefix = $newprefix; } print $val."\n"; // Show menu entry ($val contains the <option> tags } print '</select>'; print ajax_combobox($htmlname); return; } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Return combo list of available menu families * * @param string $selected Menu pre-selected * @param string $htmlname Name of html select * @param string[] $dirmenuarray Directories to scan * @return void */ public function select_menu_families($selected, $htmlname, $dirmenuarray) { // phpcs:enable global $langs, $conf; //$expdevmenu=array('smartphone_backoffice.php','smartphone_frontoffice.php'); // Menu to disable if $conf->global->MAIN_FEATURES_LEVEL is not set $expdevmenu = array(); $menuarray = array(); foreach ($dirmenuarray as $dirmenu) { foreach ($conf->file->dol_document_root as $dirroot) { $dir = $dirroot.$dirmenu; if (is_dir($dir)) { $handle = opendir($dir); if (is_resource($handle)) { while (($file = readdir($handle)) !== false) { if (is_file($dir."/".$file) && substr($file, 0, 1) != '.' && substr($file, 0, 3) != 'CVS') { $filelib = preg_replace('/(_backoffice|_frontoffice)?\.php$/i', '', $file); if (preg_match('/^index/i', $filelib)) { continue; } if (preg_match('/^default/i', $filelib)) { continue; } if (preg_match('/^empty/i', $filelib)) { continue; } if (preg_match('/\.lib/i', $filelib)) { continue; } if (getDolGlobalInt('MAIN_FEATURES_LEVEL') == 0 && in_array($file, $expdevmenu)) { continue; } $menuarray[$filelib] = 1; } $menuarray['all'] = 1; } closedir($handle); } } } } ksort($menuarray); // Show combo list of menu handlers print '<select class="flat maxwidth150" id="'.$htmlname.'" name="'.$htmlname.'">'; foreach ($menuarray as $key => $val) { $tab = explode('_', $key); print '<option value="'.$key.'"'; if ($key == $selected) { print ' selected'; } print '>'; if ($key == 'all') { print $langs->trans("AllMenus"); } else { print $key; } print '</option>'."\n"; } print '</select>'; print ajax_combobox($htmlname); } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Return a HTML select list of timezones * * @param string $selected Menu pre-selectionnee * @param string $htmlname Nom de la zone select * @return void */ public function select_timezone($selected, $htmlname) { // phpcs:enable print '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">'; print '<option value="-1"> </option>'; $arraytz = array( "Pacific/Midway" => "GMT-11:00", "Pacific/Fakaofo" => "GMT-10:00", "America/Anchorage" => "GMT-09:00", "America/Los_Angeles" => "GMT-08:00", "America/Dawson_Creek" => "GMT-07:00", "America/Chicago" => "GMT-06:00", "America/Bogota" => "GMT-05:00", "America/Anguilla" => "GMT-04:00", "America/Araguaina" => "GMT-03:00", "America/Noronha" => "GMT-02:00", "Atlantic/Azores" => "GMT-01:00", "Africa/Abidjan" => "GMT+00:00", "Europe/Paris" => "GMT+01:00", "Europe/Helsinki" => "GMT+02:00", "Europe/Moscow" => "GMT+03:00", "Asia/Dubai" => "GMT+04:00", "Asia/Karachi" => "GMT+05:00", "Indian/Chagos" => "GMT+06:00", "Asia/Jakarta" => "GMT+07:00", "Asia/Hong_Kong" => "GMT+08:00", "Asia/Tokyo" => "GMT+09:00", "Australia/Sydney" => "GMT+10:00", "Pacific/Noumea" => "GMT+11:00", "Pacific/Auckland" => "GMT+12:00", "Pacific/Enderbury" => "GMT+13:00" ); foreach ($arraytz as $lib => $gmt) { print '<option value="'.$lib.'"'; if ($selected == $lib || $selected == $gmt) { print ' selected'; } print '>'.$gmt.'</option>'."\n"; } print '</select>'; } // phpcs:disable PEAR.NamingConventions.ValidFunctionName.ScopeNotCamelCaps /** * Return html select list with available languages (key='en_US', value='United States' for example) * * @param string $selected Paper format pre-selected * @param string $htmlname Name of HTML select field * @param string $filter Value to filter on code * @param int $showempty Add empty value * @param int $forcecombo Force to load all values and output a standard combobox (with no beautification) * @return string Return HTML output */ public function select_paper_format($selected = '', $htmlname = 'paperformat_id', $filter = '', $showempty = 0, $forcecombo = 0) { // phpcs:enable global $langs; $langs->load("dict"); $sql = "SELECT code, label, width, height, unit"; $sql .= " FROM ".$this->db->prefix()."c_paper_format"; $sql .= " WHERE active=1"; if ($filter) { $sql .= " AND code LIKE '%".$this->db->escape($filter)."%'"; } $paperformat = array(); $resql = $this->db->query($sql); if ($resql) { $num = $this->db->num_rows($resql); $i = 0; while ($i < $num) { $obj = $this->db->fetch_object($resql); $unitKey = $langs->trans('SizeUnit'.$obj->unit); $paperformat[$obj->code] = $langs->trans('PaperFormat'.strtoupper($obj->code)).' - '.round($obj->width).'x'.round($obj->height).' '.($unitKey == 'SizeUnit'.$obj->unit ? $obj->unit : $unitKey); $i++; } } else { dol_print_error($this->db); return ''; } $out = ''; $out .= '<select class="flat" id="'.$htmlname.'" name="'.$htmlname.'">'; if ($showempty) { $out .= '<option value=""'; if ($selected == '') { $out .= ' selected'; } $out .= '> </option>'; } foreach ($paperformat as $key => $value) { if ($selected == $key) { $out .= '<option value="'.$key.'" selected>'.$value.'</option>'; } else { $out .= '<option value="'.$key.'">'.$value.'</option>'; } } $out .= '</select>'; if (!$forcecombo) { include_once DOL_DOCUMENT_ROOT.'/core/lib/ajax.lib.php'; $out .= ajax_combobox($htmlname); } return $out; } /** * Function to show the combo select to chose a type of field (varchar, int, email, ...) * * @param string $htmlname Name of HTML select component * @param string $type Type preselected * @param array $typewecanchangeinto Array of possible switch combination from 1 type to another one. This will grey not possible combinations. * @return string The combo HTML select component */ public function selectTypeOfFields($htmlname, $type, $typewecanchangeinto = array()) { global $type2label; // TODO Remove this $out = ''; $out .= '<select class="flat type" id="'.$htmlname.'" name="'.$htmlname.'">'; foreach ($type2label as $key => $val) { $selected = ''; if ($key == $type) { $selected = ' selected="selected"'; } // Set $valhtml with the picto for the type $valhtml = ($key ? getPictoForType($key) : '').$val; if (empty($typewecanchangeinto) || in_array($key, $typewecanchangeinto[$type])) { $out .= '<option value="'.$key.'"'.$selected.' data-html="'.dol_escape_htmltag($valhtml).'">'.($val ? $val : ' ').'</option>'; } else { $out .= '<option value="'.$key.'" disabled="disabled"'.$selected.' data-html="'.dol_escape_htmltag($valhtml).'">'.($val ? $val : ' ').'</option>'; } } $out .= '</select>'; $out .= ajax_combobox('type'); return $out; } }