├── .gitignore ├── uninstall.sql ├── .php-cs-fixer.dist.php ├── lib ├── rex_global_settings_list.php ├── input │ ├── text.php │ ├── colorpicker.php │ ├── textarea.php │ ├── rgbacolorpicker.php │ ├── linkbutton.php │ ├── linklistbutton.php │ ├── select.php │ ├── mediabutton.php │ ├── medialistbutton.php │ ├── datetime.php │ ├── time.php │ └── date.php ├── rex_var_global_var.php ├── utils │ └── global_settings_helper.php ├── table_manager.php ├── handler │ ├── global_settings_handler.php │ └── handler.php ├── input.php ├── rex_global_settings.php └── table_expander.php ├── .tools └── bootstrap.php ├── pages ├── help.readme.php ├── help.license.php ├── help.changelog.php ├── index.php ├── settings.php └── field.php ├── composer.json ├── phpunit.xml.dist ├── .github └── workflows │ ├── publish-to-redaxo.yml │ ├── default.config.yml.github-action.diff │ ├── code-style.yml │ └── phppest.yml ├── package.yml ├── LICENSE.md ├── _install.sql ├── update.php ├── tests └── global_settings_test.php ├── assets ├── js │ └── global_settings.js └── css │ ├── global_settings.css │ └── spectrum.css ├── install.php ├── boot.php ├── README.md ├── CHANGELOG.md ├── lang ├── en_gb.lang ├── sv_se.lang ├── de_de.lang └── es_es.lang └── functions └── function_global_settings.php /.gitignore: -------------------------------------------------------------------------------- 1 | /.phpunit.result.cache 2 | /vendor 3 | /.idea/ 4 | /.php-cs-fixer.cache -------------------------------------------------------------------------------- /uninstall.sql: -------------------------------------------------------------------------------- 1 | DROP TABLE IF EXISTS `%TABLE_PREFIX%global_settings_field`; 2 | DROP TABLE IF EXISTS `%TABLE_PREFIX%global_settings_type`; 3 | DROP TABLE IF EXISTS `%TABLE_PREFIX%global_settings`; 4 | -------------------------------------------------------------------------------- /.php-cs-fixer.dist.php: -------------------------------------------------------------------------------- 1 | in(__DIR__) 7 | ->exclude('tests') 8 | ; 9 | 10 | return (new Redaxo\PhpCsFixerConfig\Config()) 11 | ->setFinder($finder) 12 | ; 13 | -------------------------------------------------------------------------------- /lib/rex_global_settings_list.php: -------------------------------------------------------------------------------- 1 | setAttribute('class', 'form-control'); 9 | $this->setAttribute('type', 'text'); 10 | } 11 | 12 | public function getHtml() 13 | { 14 | $value = htmlspecialchars((string) $this->value); 15 | return 'getAttributeString() . ' value="' . $value . '" />'; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pages/help.readme.php: -------------------------------------------------------------------------------- 1 | getPath('README.md')); 4 | [$toc, $content] = rex_markdown::factory()->parseWithToc($data); 5 | $fragment = new rex_fragment(); 6 | $fragment->setVar('content', $content, false); 7 | $fragment->setVar('toc', $toc, false); 8 | $content = $fragment->parse('core/page/docs.php'); 9 | 10 | $fragment = new rex_fragment(); 11 | $fragment->setVar('title', $this->i18n('help_readme'), false); 12 | $fragment->setVar('body', $content, false); 13 | echo $fragment->parse('core/page/section.php'); 14 | -------------------------------------------------------------------------------- /pages/help.license.php: -------------------------------------------------------------------------------- 1 | parseWithToc(rex_file::require($this->getPath('LICENSE.md')), 2, 3, false); 4 | 5 | $fragment = new rex_fragment(); 6 | $fragment->setVar('content', $Content, false); 7 | $fragment->setVar('toc', $Toc, false); 8 | $content = $fragment->parse('core/page/docs.php'); 9 | 10 | $fragment = new rex_fragment(); 11 | $fragment->setVar('title', $this->i18n('help_license')); 12 | $fragment->setVar('body', $content, false); 13 | 14 | echo $fragment->parse('core/page/section.php'); 15 | -------------------------------------------------------------------------------- /pages/help.changelog.php: -------------------------------------------------------------------------------- 1 | parseWithToc(rex_file::require($this->getPath('CHANGELOG.md')), 2, 3, false); 4 | 5 | $fragment = new rex_fragment(); 6 | $fragment->setVar('content', $Content, false); 7 | $fragment->setVar('toc', $Toc, false); 8 | $content = $fragment->parse('core/page/docs.php'); 9 | 10 | $fragment = new rex_fragment(); 11 | $fragment->setVar('title', $this->i18n('help_changelog')); 12 | $fragment->setVar('body', $content, false); 13 | 14 | echo $fragment->parse('core/page/section.php'); 15 | -------------------------------------------------------------------------------- /lib/input/colorpicker.php: -------------------------------------------------------------------------------- 1 | setAttribute('class', 'form-control rex-global-settings-color-picker'); 9 | $this->setAttribute('type', 'text'); 10 | } 11 | 12 | public function getHtml() 13 | { 14 | $value = htmlspecialchars($this->value); 15 | return 'getAttributeString() . ' value="' . $value . '" />'; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "license": "MIT", 3 | "scripts": { 4 | "test": "./vendor/bin/pest --testdox", 5 | "cs-dry": "php-cs-fixer fix -v --ansi --dry-run --config=.php-cs-fixer.dist.php", 6 | "cs-fix": "php-cs-fixer fix -v --ansi --config=.php-cs-fixer.dist.php" 7 | }, 8 | "require-dev": { 9 | "pestphp/pest": "^1.22", 10 | "psr/log": "1.1.4", 11 | "redaxo/php-cs-fixer-config": "^2.0", 12 | "friendsofphp/php-cs-fixer": "^3.14" 13 | }, 14 | "config": { 15 | "allow-plugins": { 16 | "pestphp/pest-plugin": true 17 | } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /lib/input/textarea.php: -------------------------------------------------------------------------------- 1 | setAttribute('class', 'form-control'); 9 | $this->setAttribute('cols', '50'); 10 | $this->setAttribute('rows', '6'); 11 | } 12 | 13 | public function getHtml() 14 | { 15 | $value = htmlspecialchars($this->value); 16 | return 'getAttributeString() . '>' . $value . ''; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /lib/input/rgbacolorpicker.php: -------------------------------------------------------------------------------- 1 | setAttribute('class', 'form-control rex-global-settings-rgba-color-picker'); 9 | $this->setAttribute('data-preferred-format', 'rgb'); 10 | $this->setAttribute('data-show-alpha', 'true'); 11 | $this->setAttribute('type', 'text'); 12 | } 13 | 14 | public function getHtml() 15 | { 16 | $value = htmlspecialchars($this->value); 17 | return 'getAttributeString() . ' value="' . $value . '" />'; 18 | } 19 | } 20 | 21 | -------------------------------------------------------------------------------- /pages/index.php: -------------------------------------------------------------------------------- 1 | 8 | * 9 | * For the full copyright and license information, please view the LICENSE 10 | * file that was distributed with this source code. 11 | */ 12 | class rex_var_global_var extends rex_var 13 | { 14 | protected function getOutput() 15 | { 16 | $var = $this->getParsedArg('var', null, true); 17 | if (null === $var) { 18 | return false; 19 | } 20 | 21 | if ('1' == $this->getArg('empty')) { 22 | $method = 'getDefaultValue'; 23 | } else { 24 | $method = 'getString'; 25 | } 26 | 27 | return "rex_global_settings::$method($var)"; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /phpunit.xml.dist: -------------------------------------------------------------------------------- 1 | 2 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | tests 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /.github/workflows/publish-to-redaxo.yml: -------------------------------------------------------------------------------- 1 | # Instructions: https://github.com/FriendsOfREDAXO/installer-action/ 2 | 3 | name: Publish to REDAXO.org 4 | on: 5 | release: 6 | types: 7 | - published 8 | 9 | jobs: 10 | redaxo_publish: 11 | runs-on: ubuntu-latest 12 | steps: 13 | - uses: actions/checkout@v3 14 | - if: hashFiles('composer.json') != '' 15 | uses: shivammathur/setup-php@v2 16 | with: 17 | php-version: "8.2" 18 | - if: hashFiles('composer.json') != '' 19 | uses: ramsey/composer-install@v2 20 | with: 21 | composer-options: "--no-dev" 22 | - uses: FriendsOfREDAXO/installer-action@v1 23 | with: 24 | myredaxo-username: ${{ secrets.MYREDAXO_USERNAME }} 25 | myredaxo-api-key: ${{ secrets.MYREDAXO_API_KEY }} 26 | description: ${{ github.event.release.body }} 27 | version: ${{ github.event.release.tag_name }} 28 | -------------------------------------------------------------------------------- /lib/input/linkbutton.php: -------------------------------------------------------------------------------- 1 | buttonId = ''; 12 | $this->categoryId = ''; 13 | } 14 | 15 | public function setButtonId($buttonId) 16 | { 17 | $this->buttonId = $buttonId; 18 | $this->setAttribute('id', 'LINK_' . $buttonId); 19 | } 20 | 21 | public function setCategoryId($categoryId) 22 | { 23 | $this->categoryId = $categoryId; 24 | } 25 | 26 | public function getHtml() 27 | { 28 | $buttonId = $this->buttonId; 29 | $categoryId = $this->categoryId; 30 | $value = htmlspecialchars($this->value); 31 | $name = $this->attributes['name']; 32 | 33 | $field = rex_var_link::getWidget($buttonId, $name, $value, ['category' => $categoryId]); 34 | 35 | return $field; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /lib/input/linklistbutton.php: -------------------------------------------------------------------------------- 1 | buttonId = ''; 12 | $this->categoryId = ''; 13 | } 14 | 15 | public function setButtonId($buttonId) 16 | { 17 | $this->buttonId = $buttonId; 18 | $this->setAttribute('id', 'REX_LINKLIST_' . $buttonId); 19 | } 20 | 21 | public function setCategoryId($categoryId) 22 | { 23 | $this->categoryId = $categoryId; 24 | } 25 | 26 | public function getHtml() 27 | { 28 | $buttonId = $this->buttonId; 29 | $category = $this->categoryId; 30 | $value = htmlspecialchars($this->value); 31 | $name = $this->attributes['name']; 32 | 33 | $field = rex_var_linklist::getWidget($buttonId, $name, $value, ['category' => $category]); 34 | 35 | return $field; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /.github/workflows/default.config.yml.github-action.diff: -------------------------------------------------------------------------------- 1 | diff --git a/redaxo_cms/redaxo/src/core/default.config.yml b/redaxo_cms/redaxo/src/core/default.config.yml 2 | index 2880a09e9..3485d830a 100644 3 | --- a/redaxo_cms/redaxo/src/core/default.config.yml 4 | +++ b/redaxo_cms/redaxo/src/core/default.config.yml 5 | @@ -1,8 +1,8 @@ 6 | setup: true 7 | debug: 8 | - enabled: false 9 | - throw_always_exception: false # `true` for all error levels, `[E_WARNING, E_NOTICE]` for subset 10 | -instname: null 11 | + enabled: true 12 | + throw_always_exception: true # `true` for all error levels, `[E_WARNING, E_NOTICE]` for subset 13 | +instname: 57d0619b2d578f108506a917826ea8b62c1c3eea 14 | server: https://www.redaxo.org/ 15 | servername: REDAXO 16 | error_email: null 17 | @@ -64,9 +64,9 @@ table_prefix: rex_ 18 | temp_prefix: tmp_ 19 | db: 20 | 1: 21 | - host: localhost 22 | + host: 127.0.0.1 23 | login: root 24 | - password: '' 25 | + password: root 26 | name: redaxo5 27 | persistent: false 28 | ssl_key: null 29 | -------------------------------------------------------------------------------- /package.yml: -------------------------------------------------------------------------------- 1 | package: global_settings 2 | version: '2.8.8' 3 | author: Friends Of REDAXO 4 | supportpage: https://github.com/FriendsOfREDAXO/global_settings 5 | page: 6 | title: translate:title 7 | perm: global_settings[settings] 8 | pjax: true 9 | icon: rex-icon fa-wrench 10 | subpages: 11 | settings: { title: 'translate:settings', perm: 'global_settings[settings]' } 12 | fields: { title: 'translate:fields', perm: 'admin[]' } 13 | help: 14 | title: 'translate:help' 15 | perm: admin[] 16 | subpages: 17 | readme: { title: 'translate:help_readme' } 18 | changelog: { title: 'translate:help_changelog' } 19 | license: { title: 'translate:help_license' } 20 | requires: 21 | redaxo: '^5.13' 22 | php: 23 | version: '>=8.0' 24 | 25 | installer_ignore: 26 | - .git 27 | - .gitignore 28 | - composer.json 29 | - composer.lock 30 | - phpunit.xml.dist 31 | - tests 32 | - .tools 33 | - .php-cs-fixer.dist.php 34 | - .php-cs-fixer.cache 35 | -------------------------------------------------------------------------------- /lib/input/select.php: -------------------------------------------------------------------------------- 1 | select = new rex_select(); 12 | $this->setAttribute('class', 'form-control'); 13 | } 14 | 15 | public function setValue($value) 16 | { 17 | $this->select->setSelected($value); 18 | parent::setValue($value); 19 | } 20 | 21 | public function setAttribute($name, $value) 22 | { 23 | if ('name' == $name) { 24 | $this->select->setName($value); 25 | } elseif ('id' == $name) { 26 | $this->select->setId($value); 27 | } else { 28 | $this->select->setAttribute($name, $value); 29 | } 30 | 31 | parent::setAttribute($name, $value); 32 | } 33 | 34 | public function getSelect() 35 | { 36 | return $this->select; 37 | } 38 | 39 | public function getHtml() 40 | { 41 | return $this->select->get(); 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Friends Of REDAXO 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.github/workflows/code-style.yml: -------------------------------------------------------------------------------- 1 | name: PHP-CS-Fixer 2 | 3 | on: 4 | push: 5 | branches: [ master, main ] 6 | pull_request: 7 | branches: [ master, main ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | code-style: 14 | 15 | runs-on: ubuntu-latest 16 | permissions: 17 | contents: write # for Git to git apply 18 | 19 | steps: 20 | - uses: actions/checkout@v3 21 | 22 | - name: Setup PHP 23 | uses: shivammathur/setup-php@v2 24 | with: 25 | php-version: '8.1' 26 | extensions: gd, intl, pdo_mysql 27 | coverage: none # disable xdebug, pcov 28 | 29 | # install dependencies from composer.json 30 | - name: Install test dependencies 31 | env: 32 | COMPOSER: composer.json 33 | run: composer install --prefer-dist --no-progress 34 | 35 | # run php-cs-fixer, fix code styles 36 | - name: Run PHP CS Fixer 37 | run: composer cs-dry 38 | 39 | # # commit and push fixed files 40 | # - uses: stefanzweifel/git-auto-commit-action@v4 41 | # with: 42 | # commit_message: Apply php-cs-fixer changes 43 | -------------------------------------------------------------------------------- /lib/input/mediabutton.php: -------------------------------------------------------------------------------- 1 | buttonId = ''; 12 | } 13 | 14 | public function setButtonId($buttonId) 15 | { 16 | $this->buttonId = $buttonId; 17 | $this->setAttribute('id', 'REX_MEDIA_' . $buttonId); 18 | } 19 | 20 | public function setCategoryId($categoryId) 21 | { 22 | $this->args['category'] = $categoryId; 23 | } 24 | 25 | public function setTypes($types) 26 | { 27 | $this->args['types'] = $types; 28 | } 29 | 30 | public function setPreview($preview = true) 31 | { 32 | $this->args['preview'] = $preview; 33 | } 34 | 35 | public function getHtml() 36 | { 37 | $buttonId = $this->buttonId; 38 | $value = htmlspecialchars($this->value); 39 | $name = $this->attributes['name']; 40 | $args = $this->args; 41 | 42 | $field = rex_var_media::getWidget($buttonId, $name, $value, $args); 43 | 44 | return $field; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /lib/input/medialistbutton.php: -------------------------------------------------------------------------------- 1 | buttonId = ''; 12 | } 13 | 14 | public function setButtonId($buttonId) 15 | { 16 | $this->buttonId = $buttonId; 17 | $this->setAttribute('id', 'REX_MEDIALIST_' . $buttonId); 18 | } 19 | 20 | public function setCategoryId($categoryId) 21 | { 22 | $this->args['category'] = $categoryId; 23 | } 24 | 25 | public function setTypes($types) 26 | { 27 | $this->args['types'] = $types; 28 | } 29 | 30 | public function setPreview($preview = true) 31 | { 32 | $this->args['preview'] = $preview; 33 | } 34 | 35 | public function getHtml() 36 | { 37 | $buttonId = $this->buttonId; 38 | $value = htmlspecialchars($this->value); 39 | $name = $this->attributes['name']; 40 | $args = $this->args; 41 | 42 | $field = rex_var_medialist::getWidget($buttonId, $name, $value, $args); 43 | 44 | return $field; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /_install.sql: -------------------------------------------------------------------------------- 1 | CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%global_settings_type` ( 2 | `id` int(10) unsigned NOT NULL auto_increment, 3 | `label` varchar(255) default NULL, 4 | `dbtype` varchar(255) NOT NULL, 5 | `dblength` int(11) NOT NULL, 6 | PRIMARY KEY (`id`) 7 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; 8 | 9 | INSERT INTO %TABLE_PREFIX%global_settings_type VALUES 10 | (1, 'text', 'text', 0), 11 | (2, 'textarea', 'mediumtext', 0), 12 | (3, 'select', 'varchar', 255), 13 | (4, 'radio', 'varchar', 255), 14 | (5, 'checkbox', 'varchar', 255), 15 | (10, 'date', 'text', 0), 16 | (13, 'time', 'text', 0), 17 | (11, 'datetime', 'text', 0), 18 | (12, 'legend', 'text', 0), 19 | (6, 'REX_MEDIA_WIDGET', 'varchar', 255), 20 | (7, 'REX_MEDIALIST_WIDGET', 'text', 0), 21 | (8, 'REX_LINK_WIDGET', 'varchar', 255), 22 | (9, 'REX_LINKLIST_WIDGET', 'text', 0), 23 | (14, 'tab', 'text', 0), 24 | (15, 'colorpicker', 'text', 0), 25 | (16, 'rgbacolorpicker', 'text', 0) 26 | ON DUPLICATE KEY UPDATE `label` = VALUES(`label`), `dbtype` = VALUES(`dbtype`), `dblength` = VALUES(`dblength`); 27 | 28 | CREATE TABLE IF NOT EXISTS `%TABLE_PREFIX%global_settings` ( 29 | `clang` int(10) unsigned NOT NULL, 30 | PRIMARY KEY (`clang`) 31 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ; 32 | -------------------------------------------------------------------------------- /pages/settings.php: -------------------------------------------------------------------------------- 1 | '; 12 | 13 | $clangId = filter_var(rex_be_controller::getCurrentPagePart(3), FILTER_SANITIZE_NUMBER_INT); 14 | 15 | if ($clangId < 1) { 16 | $clangId = 1; 17 | } 18 | 19 | if (rex_clang::exists($clangId)) { 20 | rex_clang::setCurrentId($clangId); 21 | } 22 | 23 | $global_settingsHandler = new rex_global_settings_global_settings_handler(); 24 | $form = $global_settingsHandler->getForm([ 25 | 'clang' => $clangId, 26 | ]); 27 | 28 | $panel .= $form; 29 | 30 | $formElements = []; 31 | 32 | $n = []; 33 | $n['field'] = ''; 34 | $formElements[] = $n; 35 | 36 | $fragment = new rex_fragment(); 37 | $fragment->setVar('elements', $formElements, false); 38 | $buttons = $fragment->parse('core/form/submit.php'); 39 | 40 | $fragment = new rex_fragment(); 41 | $fragment->setVar('class', 'edit', false); 42 | $fragment->setVar('title', rex_i18n::msg('global_settings_settings'), false); 43 | $fragment->setVar('body', $panel, false); 44 | $fragment->setVar('buttons', $buttons, false); 45 | $content .= $fragment->parse('core/page/section.php'); 46 | 47 | $action = 'index.php?page=global_settings/settings'; 48 | 49 | if (count(rex_clang::getAll()) > 1) { 50 | $action .= '/clang' . $clangId; 51 | } 52 | 53 | echo ' 54 |
55 | ' . $content . ' 56 |
'; 57 | -------------------------------------------------------------------------------- /lib/utils/global_settings_helper.php: -------------------------------------------------------------------------------- 1 | getParams(); 8 | $warning = $ep->getSubject(); 9 | $fileName = rex_string::sanitizeHtml($params['filename']); 10 | 11 | $sql = rex_sql::factory(); 12 | $sql->setQuery('SELECT `name` FROM `' . rex::getTablePrefix() . 'global_settings_field` WHERE `type_id` IN(6,7)'); 13 | $rows = $sql->getRows(); 14 | 15 | /** 16 | * get column names. 17 | */ 18 | $in = []; 19 | for ($i = 0; $i < $rows; ++$i) { 20 | $name = $sql->getValue('name'); 21 | $in[] = $name; 22 | $sql->next(); 23 | } 24 | 25 | if (!empty($in)) { 26 | $sql = rex_sql::factory(); 27 | $sql->setQuery('SELECT * FROM `' . rex::getTablePrefix() . 'global_settings` WHERE "' . $fileName . '" IN(' . implode(',', $in) . ')'); 28 | $rows = $sql->getRows(); 29 | $columns = $sql->getArray(); 30 | } 31 | 32 | /** 33 | * if filename does not exist. 34 | */ 35 | if (0 == $rows) { 36 | return $warning; 37 | } 38 | 39 | /** 40 | * get warnings. 41 | */ 42 | $messages = ''; 43 | foreach ($columns[0] as $key => $val) { 44 | if (str_contains($val, $fileName)) { 45 | $sql = rex_sql::factory(); 46 | $sql->setQuery('SELECT * FROM `' . rex::getTablePrefix() . 'global_settings_field` WHERE `name` = "' . $key . '"'); 47 | 48 | $messages .= '
  • ' . rex_i18n::msg('global_settings_title') . ': ' . $sql->getValue('title') . '
  • '; 49 | } 50 | } 51 | 52 | if ('' !== $messages) { 53 | $warning[] = '
      ' . $messages . '
    '; 54 | } 55 | 56 | return $warning; 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /lib/input/datetime.php: -------------------------------------------------------------------------------- 1 | dateInput = rex_global_settings_input::factory('date'); 13 | $this->timeInput = rex_global_settings_input::factory('time'); 14 | } 15 | 16 | public function setValue($value) 17 | { 18 | if (!is_array($value)) { 19 | throw new InvalidArgumentException('Expecting $value to be an array!'); 20 | } 21 | 22 | $this->dateInput->setValue($value); 23 | $this->timeInput->setValue($value); 24 | 25 | parent::setValue($value); 26 | } 27 | 28 | public function getValue() 29 | { 30 | return array_merge($this->dateInput->getValue(), $this->timeInput->getValue()); 31 | } 32 | 33 | public function setAttribute($name, $value) 34 | { 35 | $this->dateInput->setAttribute($name, $value); 36 | $this->timeInput->setAttribute($name, $value); 37 | 38 | parent::setAttribute($name, $value); 39 | } 40 | 41 | public function getDaySelect() 42 | { 43 | return $this->dateInput->daySelect; 44 | } 45 | 46 | public function getMonthSelect() 47 | { 48 | return $this->dateInput->monthSelect; 49 | } 50 | 51 | public function getYearSelect() 52 | { 53 | return $this->dateInput->yearSelect; 54 | } 55 | 56 | public function getHourSelect() 57 | { 58 | return $this->hourSelect; 59 | } 60 | 61 | public function getMinuteSelect() 62 | { 63 | return $this->minuteSelect; 64 | } 65 | 66 | public function getHtml() 67 | { 68 | $html = '
    ' . $this->dateInput->getHtml() . '
    '; 69 | $html .= '-'; 70 | $html .= '
    ' . $this->timeInput->getHtml() . '
    '; 71 | return $html; 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /lib/input/time.php: -------------------------------------------------------------------------------- 1 | hourSelect = new rex_select(); 13 | $this->hourSelect->addOptions(range(0, 23), true); 14 | $this->hourSelect->setSize(1); 15 | $this->hourSelect->setAttribute('class', 'rex-form-select-date'); 16 | 17 | $this->minuteSelect = new rex_select(); 18 | $this->minuteSelect->addOptions(range(0, 59), true); 19 | $this->minuteSelect->setSize(1); 20 | $this->minuteSelect->setAttribute('class', 'rex-form-select-date'); 21 | } 22 | 23 | public function setValue($value) 24 | { 25 | if (!is_array($value)) { 26 | throw new InvalidArgumentException('Expecting $value to be an array!'); 27 | } 28 | 29 | foreach (['hour', 'minute'] as $reqIndex) { 30 | if (!isset($value[$reqIndex])) { 31 | throw new rex_exception('Missing index "' . $reqIndex . '" in $value!'); 32 | } 33 | } 34 | 35 | $this->hourSelect->setSelected($value['hour']); 36 | $this->minuteSelect->setSelected($value['minute']); 37 | 38 | parent::setValue($value); 39 | } 40 | 41 | public function setAttribute($name, $value) 42 | { 43 | if ('name' == $name) { 44 | $this->hourSelect->setName($value . '[hour]'); 45 | $this->minuteSelect->setName($value . '[minute]'); 46 | } elseif ('id' == $name) { 47 | $this->hourSelect->setId($value . '_hour'); 48 | $this->minuteSelect->setId($value . '_minute'); 49 | } else { 50 | $this->hourSelect->setAttribute($name, $value); 51 | $this->minuteSelect->setAttribute($name, $value); 52 | } 53 | parent::setAttribute($name, $value); 54 | } 55 | 56 | public function getHourSelect() 57 | { 58 | return $this->hourSelect; 59 | } 60 | 61 | public function getMinuteSelect() 62 | { 63 | return $this->minuteSelect; 64 | } 65 | 66 | public function getHtml() 67 | { 68 | return $this->hourSelect->get() . $this->minuteSelect->get(); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /update.php: -------------------------------------------------------------------------------- 1 | ensurePrimaryIdColumn() 7 | ->ensureColumn(new rex_sql_column('title', 'varchar(255)', true, null)) 8 | ->ensureColumn(new rex_sql_column('name', 'varchar(255)', true, null)) 9 | ->ensureColumn(new rex_sql_column('notice', 'text', true, null)) 10 | ->ensureColumn(new rex_sql_column('priority', 'int(10) unsigned')) 11 | ->ensureColumn(new rex_sql_column('attributes', 'text')) 12 | ->ensureColumn(new rex_sql_column('type_id', 'int(10) unsigned', true, null)) 13 | ->ensureColumn(new rex_sql_column('default', 'varchar(255)')) 14 | ->ensureColumn(new rex_sql_column('params', 'text', true, null)) 15 | ->ensureColumn(new rex_sql_column('validate', 'text', true, null)) 16 | ->ensureColumn(new rex_sql_column('callback', 'text', true, null)) 17 | ->ensureColumn(new rex_sql_column('restrictions', 'text', true, null)) 18 | ->ensureColumn(new rex_sql_column('createuser', 'varchar(255)')) 19 | ->ensureColumn(new rex_sql_column('createdate', 'datetime')) 20 | ->ensureColumn(new rex_sql_column('updateuser', 'varchar(255)')) 21 | ->ensureColumn(new rex_sql_column('updatedate', 'datetime')) 22 | ->ensureIndex(new rex_sql_index('name', ['name'], rex_sql_index::UNIQUE)) 23 | ->ensure(); 24 | 25 | // update existing textarea fields from text to mediumtext 26 | if (rex_string::versionCompare($addon->getVersion(), '2.7.1', '<=')) { 27 | $sql = rex_sql::factory(); 28 | $sql->prepareQuery('SELECT name FROM ' . rex::getTable('global_settings_field') . ' WHERE type_id =:type_id'); 29 | $sql->execute(['type_id' => '2']); 30 | $results = $sql->getArray(); 31 | if ($results) { 32 | foreach ($results as $result) { 33 | rex_sql_table::get(rex::getTable('global_settings'))->ensureColumn(new rex_sql_column($result['name'], 'mediumtext', true, null))->ensure(); 34 | } 35 | } 36 | } 37 | 38 | // add rgbacolorpicker field type 39 | $sql = rex_sql::factory(); 40 | $sql->setQuery('INSERT INTO ' . rex::getTable('global_settings_type') . ' (id, label, dbtype, dblength) 41 | VALUES (16, "rgbacolorpicker", "text", 0) 42 | ON DUPLICATE KEY UPDATE label = VALUES(label), dbtype = VALUES(dbtype), dblength = VALUES(dblength)'); 43 | 44 | -------------------------------------------------------------------------------- /tests/global_settings_test.php: -------------------------------------------------------------------------------- 1 | setTable(rex::getTable('global_settings_type')); 12 | $sql->setWhere(['label' => 'text']); 13 | $sql->select('id'); 14 | 15 | if ($sql->getRows() > 0) { 16 | return (int)$sql->getValue('id'); 17 | } 18 | 19 | return null; 20 | } 21 | 22 | test('expect the field to be created', function () 23 | { 24 | $returnValue = rex_global_settings_add_field('test_title', getName('test_name'), 0, '', getFieldID('text'), ''); 25 | expect($returnValue)->toBeTrue(); 26 | }); 27 | 28 | test('expect the field already exists', function () 29 | { 30 | $returnValue = rex_global_settings_add_field('test_title', getName('test_name'), 0, '', getFieldID('text'), ''); 31 | expect($returnValue)->toBeString(); 32 | expect($returnValue)->toEqual(rex_i18n::msg('global_settings_field_error_unique_name')); 33 | }); 34 | 35 | test('expect the field type to be invalid', function () 36 | { 37 | $returnValue = rex_global_settings_add_field('test_invalid_title', getName('test_invalid_name'), 0, '', 99999, ''); 38 | expect($returnValue)->toBeString(); 39 | expect($returnValue)->toEqual(rex_i18n::msg('global_settings_field_error_invalid_type')); 40 | }); 41 | 42 | test('expect the cache to be cleared', function () 43 | { 44 | $returnValue = rex_global_settings::deleteCache(); 45 | expect($returnValue)->toBeTrue(); 46 | }); 47 | 48 | test('expect the value to be set', function () 49 | { 50 | $sql = rex_sql::factory(); 51 | $sql->setTable(rex::getTable('global_settings')); 52 | $sql->setWhere(['clang' => 1]); 53 | $sql->setValue('glob_test_name', ''); 54 | $sql->update(); 55 | 56 | rex_global_settings::deleteCache(); 57 | rex_global_settings::init(); 58 | $returnValue = rex_global_settings::setValue(getName('test_name'), null, 'Hallo'); 59 | expect($returnValue)->toBeTrue(); 60 | }); 61 | 62 | test('expect to get the value', function () 63 | { 64 | rex_global_settings::deleteCache(); 65 | rex_global_settings::init(); 66 | $returnValue = rex_global_settings::getValue(getName('test_name'), null); 67 | expect($returnValue)->toEqual('Hallo'); 68 | }); 69 | 70 | test('expect the field to be deleted', function () { 71 | $returnValue = rex_global_settings_delete_field(getName('test_name')); 72 | expect($returnValue)->toBeTrue(); 73 | }); 74 | 75 | test('expect the field does not exist', function () { 76 | $returnValue = rex_global_settings_delete_field(getName('test_name')); 77 | expect($returnValue)->toBeString(); 78 | expect($returnValue)->toEqual(rex_i18n::msg('global_settings_field_error_invalid_name')); 79 | }); 80 | -------------------------------------------------------------------------------- /assets/js/global_settings.js: -------------------------------------------------------------------------------- 1 | var gs_visibleNotice; 2 | 3 | function gs_checkConditionalFields(selectEl, activeIds, textIds) { 4 | var toggle = false; 5 | 6 | for (var i = 0; i < activeIds.length; i++) { 7 | if (selectEl.value == activeIds[i]) { 8 | toggle = activeIds[i]; 9 | break; 10 | } 11 | } 12 | 13 | if (toggle) { 14 | if (gs_visibleNotice) { 15 | toggleElement(gs_visibleNotice, 'none'); 16 | } 17 | 18 | needle = new getObj('global-settings-field-params-notice-' + toggle); 19 | if (needle.obj) { 20 | toggleElement(needle.obj, ''); 21 | gs_visibleNotice = needle.obj; 22 | } 23 | } else { 24 | if (gs_visibleNotice) { 25 | toggleElement(gs_visibleNotice, 'none'); 26 | } 27 | } 28 | 29 | var show = 1; 30 | for (var i = 0; i < textIds.length; i++) { 31 | if (selectEl.value == textIds[i]) { 32 | show = 0; 33 | break; 34 | } 35 | } 36 | 37 | jQuery(function ($) { 38 | if (show == 1) { 39 | $("#rex-global-settings-field-feld-bearbeiten-erstellen-default").parent().parent().show(); 40 | } else { 41 | $("#rex-global-settings-field-feld-bearbeiten-erstellen-default").parent().parent().hide(); 42 | } 43 | }); 44 | 45 | }; 46 | 47 | $(document).on('rex:ready', function (event, container) { 48 | var disableSelect = function (chkbox) { 49 | var sibling = chkbox; 50 | while (sibling != null) { 51 | if (sibling.nodeType == 1 && sibling.tagName.toLowerCase() == "select") { 52 | $(sibling).prop('disabled', !chkbox.checked); 53 | } 54 | sibling = sibling.previousSibling; 55 | } 56 | }; 57 | 58 | container.find("input[type=checkbox].rex-global-settings-checkbox").click(function () { 59 | disableSelect(this); 60 | }).each(function () { 61 | disableSelect(this); 62 | }) 63 | 64 | $(".rex-global-settings-color-picker,.rex-color-picker").spectrum({ 65 | preferredFormat: 'hex', 66 | showInput: true, 67 | allowEmpty: true 68 | }); 69 | 70 | // codemirror fix as otherwise in combination with tabs codemirror is broken 71 | $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { 72 | $('.CodeMirror').each(function (i, el) { 73 | el.CodeMirror.refresh(); 74 | }); 75 | }); 76 | 77 | // _glob prefix check 78 | $('#rex-page-global-settings-fields form#rex-addon-editmode').submit(function (e) { 79 | if ($('#global-settings-name-field').val().substring(0, 5) == "glob_") { 80 | alert('Don\' use glob_ as prefix!'); 81 | e.preventDefault(); 82 | } 83 | }); 84 | 85 | // set focus on first input 86 | $('#global-settings-name-field').focus(); 87 | }); 88 | -------------------------------------------------------------------------------- /install.php: -------------------------------------------------------------------------------- 1 | ensurePrimaryIdColumn() 5 | ->ensureColumn(new rex_sql_column('title', 'varchar(255)', true, null)) 6 | ->ensureColumn(new rex_sql_column('name', 'varchar(255)', true, null)) 7 | ->ensureColumn(new rex_sql_column('notice', 'text', true, null)) 8 | ->ensureColumn(new rex_sql_column('priority', 'int(10) unsigned')) 9 | ->ensureColumn(new rex_sql_column('attributes', 'text')) 10 | ->ensureColumn(new rex_sql_column('type_id', 'int(10) unsigned', true, null)) 11 | ->ensureColumn(new rex_sql_column('default', 'varchar(255)')) 12 | ->ensureColumn(new rex_sql_column('params', 'text', true, null)) 13 | ->ensureColumn(new rex_sql_column('validate', 'text', true, null)) 14 | ->ensureColumn(new rex_sql_column('callback', 'text', true, null)) 15 | ->ensureColumn(new rex_sql_column('restrictions', 'text', true, null)) 16 | ->ensureColumn(new rex_sql_column('createuser', 'varchar(255)')) 17 | ->ensureColumn(new rex_sql_column('createdate', 'datetime')) 18 | ->ensureColumn(new rex_sql_column('updateuser', 'varchar(255)')) 19 | ->ensureColumn(new rex_sql_column('updatedate', 'datetime')) 20 | ->ensureIndex(new rex_sql_index('name', ['name'], rex_sql_index::UNIQUE)) 21 | ->ensure(); 22 | 23 | rex_sql_util::importDump($this->getPath('_install.sql')); 24 | 25 | $tablePrefixes = ['global_settings' => ['glob_']]; 26 | $columns = ['global_settings' => []]; 27 | foreach ($tablePrefixes as $table => $prefixes) { 28 | foreach (rex_sql::showColumns(rex::getTable($table)) as $column) { 29 | $column = $column['name']; 30 | $prefix = substr($column, 0, 4); 31 | if (in_array(substr($column, 0, 4), $prefixes)) { 32 | $columns[$table][$column] = true; 33 | } 34 | } 35 | } 36 | 37 | $sql = rex_sql::factory(); 38 | $sql->setQuery('SELECT p.name, p.default, t.dbtype, t.dblength FROM ' . rex::getTable('global_settings_field') . ' p, ' . rex::getTable('global_settings_type') . ' t WHERE p.type_id = t.id'); 39 | $rows = $sql->getRows(); 40 | $managers = [ 41 | 'global_settings' => new rex_global_settings_table_manager(rex::getTable('global_settings')), 42 | ]; 43 | for ($i = 0; $i < $sql->getRows(); ++$i) { 44 | $column = $sql->getValue('name'); 45 | if ('glob_' == substr($column, 0, 5)) { 46 | $table = 'global_settings'; 47 | } else { 48 | $table = 'error'; 49 | } 50 | 51 | if (isset($columns[$table][$column])) { 52 | $managers[$table]->editColumn($column, $column, $sql->getValue('dbtype'), $sql->getValue('dblength'), $sql->getValue('default')); 53 | } else { 54 | $managers[$table]->addColumn($column, $sql->getValue('dbtype'), $sql->getValue('dblength'), $sql->getValue('default')); 55 | } 56 | 57 | unset($columns[$table][$column]); 58 | $sql->next(); 59 | } 60 | 61 | rex_global_settings::deleteCache(); 62 | -------------------------------------------------------------------------------- /lib/table_manager.php: -------------------------------------------------------------------------------- 1 | tableName = $tableName; 11 | $this->DBID = $DBID; 12 | } 13 | 14 | public function getTableName() 15 | { 16 | return $this->tableName; 17 | } 18 | 19 | public function addColumn($name, $type, $length, $default = null, $nullable = true) 20 | { 21 | $qry = 'ALTER TABLE `' . $this->getTableName() . '` ADD '; 22 | $qry .= '`' . $name . '` ' . $type; 23 | 24 | if (0 != $length) { 25 | $qry .= '(' . $length . ')'; 26 | } 27 | 28 | if (null !== $default) { 29 | $qry .= ' DEFAULT \'' . str_replace("'", "\\'", $default) . '\''; 30 | } 31 | 32 | if (true !== $nullable) { 33 | $qry .= ' NOT NULL'; 34 | } 35 | 36 | try { 37 | $this->setQuery($qry); 38 | return true; 39 | } catch (rex_sql_exception $e) { 40 | return false; 41 | } 42 | } 43 | 44 | public function editColumn($oldname, $name, $type, $length, $default = null, $nullable = true) 45 | { 46 | $qry = 'ALTER TABLE `' . $this->getTableName() . '` CHANGE '; 47 | $qry .= '`' . $oldname . '` `' . $name . '` ' . $type; 48 | 49 | if (0 != $length) { 50 | $qry .= '(' . $length . ')'; 51 | } 52 | 53 | if (null !== $default) { 54 | $qry .= ' DEFAULT \'' . str_replace("'", "\\'", $default) . '\''; 55 | } 56 | 57 | if (true !== $nullable) { 58 | $qry .= ' NOT NULL'; 59 | } 60 | 61 | try { 62 | $this->setQuery($qry); 63 | return true; 64 | } catch (rex_sql_exception $e) { 65 | return false; 66 | } 67 | } 68 | 69 | public function deleteColumn($name) 70 | { 71 | $qry = 'ALTER TABLE `' . $this->getTableName() . '` DROP '; 72 | $qry .= '`' . $name . '`'; 73 | 74 | try { 75 | $this->setQuery($qry); 76 | return true; 77 | } catch (rex_sql_exception $e) { 78 | return false; 79 | } 80 | } 81 | 82 | public function hasColumn($name) 83 | { 84 | $columns = rex_sql::showColumns($this->getTableName(), $this->DBID); 85 | 86 | foreach ($columns as $column) { 87 | if ($column['name'] == $name) { 88 | return true; 89 | } 90 | } 91 | return false; 92 | } 93 | 94 | protected function setQuery($qry) 95 | { 96 | try { 97 | $sql = rex_sql::factory($this->DBID); 98 | $sql->setQuery($qry); 99 | return true; 100 | } catch (rex_sql_exception $e) { 101 | return false; 102 | } 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /lib/handler/global_settings_handler.php: -------------------------------------------------------------------------------- 1 | setDebug(); 17 | $article->setTable(rex::getTablePrefix() . 'global_settings'); 18 | $article->setWhere('clang=:clang', ['clang' => $params['clang']]); 19 | // $article->setValue('name', rex_post('meta_article_name', 'string')); 20 | 21 | parent::fetchRequestValues($params, $article, $sqlFields); 22 | 23 | // do the save only when metafields are defined 24 | if ($article->hasValues()) { 25 | $article->update(); 26 | } 27 | 28 | // rex_article_cache::deleteMeta($params['id'], $params['clang']); 29 | 30 | rex_extension::registerPoint(new rex_extension_point('GLOB_META_UPDATED', '', $params)); 31 | 32 | return $params; 33 | } 34 | 35 | protected function buildFilterCondition(array $params) 36 | { 37 | $restrictionsCondition = ''; 38 | 39 | if (!empty($params['id'])) { 40 | $s = ''; 41 | $OOArt = rex_article::get($params['id'], $params['clang']); 42 | 43 | // Alle Metafelder des Pfades sind erlaubt 44 | foreach ($OOArt->getPathAsArray() as $pathElement) { 45 | if ('' != $pathElement) { 46 | $s .= ' OR `p`.`restrictions` LIKE "%|' . $pathElement . '|%"'; 47 | } 48 | } 49 | 50 | $restrictionsCondition = 'AND (`p`.`restrictions` = "" OR `p`.`restrictions` IS NULL ' . $s . ')'; 51 | } 52 | 53 | return $restrictionsCondition; 54 | } 55 | 56 | protected function renderFormItem($field, $tag, $tag_attr, $id, $label, $labelIt, $typeLabel) 57 | { 58 | return $field; 59 | } 60 | 61 | public function getForm(array $params) 62 | { 63 | // $OOArt = rex_article::get($params['id'], $params['clang']); 64 | 65 | // $params['activeItem'] = $params['article']; 66 | // Hier die category_id setzen, damit beim klick auf den REX_LINK_BUTTON der Medienpool in der aktuellen Kategorie startet 67 | // $params['activeItem']->setValue('category_id', $OOArt->getCategoryId()); 68 | 69 | $sql = rex_sql::factory(); 70 | // $sql->setDebug(); 71 | $sql->setTable(rex::getTablePrefix() . 'global_settings'); 72 | $sql->setWhere('clang=:clang', ['clang' => $params['clang']]); 73 | $sql->select('*'); 74 | $params['activeItem'] = $sql; 75 | $params['activeItem']->setValue('category_id', 0); // othewise notice 76 | 77 | return parent::renderFormAndSave(self::PREFIX, $params); 78 | } 79 | 80 | public function extendForm(rex_extension_point $ep) 81 | { 82 | // noop 83 | } 84 | } 85 | -------------------------------------------------------------------------------- /boot.php: -------------------------------------------------------------------------------- 1 | setProperty('prefixes', ['glob_']); 27 | $this->setProperty('metaTables', [ 28 | 'glob_' => rex::getTablePrefix() . 'global_settings', 29 | ]); 30 | 31 | rex_extension::register('PACKAGES_INCLUDED', 'rex_global_settings::init'); 32 | 33 | if (rex::isBackend()) { 34 | // rex_perm::register('global_settings[settings]', null, rex_perm::OPTIONS); 35 | 36 | $curDir = __DIR__; 37 | require_once $curDir . '/functions/function_global_settings.php'; 38 | 39 | rex_global_settings_check_langs(); 40 | 41 | rex_extension::register('PAGE_CHECKED', 'rex_global_settings_extensions_handler'); 42 | 43 | rex_extension::register('CLANG_ADDED', 'rex_global_settings_clang_added'); 44 | rex_extension::register('CLANG_DELETED', 'rex_global_settings_clang_deleted'); 45 | 46 | rex_extension::register('PAGES_PREPARED', static function () { 47 | if (rex::getUser() instanceof rex_user) { // important, otherwise oops error (also never use is_object()...otherwise you will regret it ;)) 48 | if (rex::getUser()->isAdmin() || rex::getUser()->hasPerm('global_settings[settings]')) { 49 | $page = rex_be_controller::getPageObject('global_settings/settings'); 50 | 51 | if (count(rex_clang::getAll(false)) > 1) { 52 | $clang_id = str_replace('clang', '', (string) rex_be_controller::getCurrentPagePart(3)); 53 | $clangAll = \rex_clang::getAll(); 54 | 55 | foreach ($clangAll as $id => $clang) { 56 | if (rex::getUser()->getComplexPerm('clang')->hasPerm($id)) { 57 | $page->addSubpage((new rex_be_page('clang' . $id, $clang->getName()))->setIsActive($id == $clang_id)); 58 | } 59 | } 60 | } 61 | } 62 | } 63 | }); 64 | 65 | rex_extension::register('CACHE_DELETED', static function () { 66 | rex_global_settings::deleteCache(); 67 | }); 68 | 69 | rex_extension::register('BACKUP_AFTER_DB_IMPORT', static function () { 70 | rex_global_settings::deleteCache(); 71 | }); 72 | 73 | rex_extension::register('GLOBAL_SETTINGS_CHANGED', static function () { 74 | rex_global_settings::deleteCache(); 75 | }); 76 | 77 | rex_extension::register('MEDIA_IS_IN_USE', 'rex_global_settings_helper::isMediaInUse'); 78 | } 79 | -------------------------------------------------------------------------------- /.github/workflows/phppest.yml: -------------------------------------------------------------------------------- 1 | name: PestPHP 2 | 3 | on: 4 | push: 5 | branches: [ master, main ] 6 | pull_request: 7 | branches: [ master, main ] 8 | 9 | permissions: 10 | contents: read 11 | 12 | jobs: 13 | pestphp: 14 | 15 | runs-on: ubuntu-latest 16 | permissions: 17 | contents: write # for Git to git apply 18 | 19 | steps: 20 | - uses: actions/checkout@v3 21 | 22 | # setup PHP v8, install some extensions 23 | - name: Setup PHP 24 | uses: shivammathur/setup-php@v2 25 | with: 26 | php-version: '8.1' 27 | extensions: gd, intl, pdo_mysql 28 | coverage: none # disable xdebug, pcov 29 | 30 | # download the latest REDAXO release and unzip it 31 | # credits https://blog.markvincze.com/download-artifacts-from-a-latest-github-release-in-sh-and-powershell/ 32 | - name: Download latest REDAXO release 33 | run: | 34 | LATEST_RELEASE=$(curl -L -s -H 'Accept: application/json' https://github.com/redaxo/redaxo/releases/latest) 35 | REDAXO_VERSION=$(echo $LATEST_RELEASE | sed -e 's/.*"tag_name":"\([^"]*\)".*/\1/') 36 | echo "Downloaded REDAXO $REDAXO_VERSION" 37 | curl -Ls -o redaxo.zip https://github.com/redaxo/redaxo/releases/download/$REDAXO_VERSION/redaxo_$REDAXO_VERSION.zip 38 | unzip -oq redaxo.zip -d redaxo_cms 39 | rm redaxo.zip 40 | 41 | # start mysql service, create a database called redaxo5, apply config patch 42 | - name: Init database 43 | run: | 44 | sudo /etc/init.d/mysql start 45 | mysql -uroot -h127.0.0.1 -proot -e 'create database redaxo5;' 46 | git apply .github/workflows/default.config.yml.github-action.diff 47 | 48 | # run REDAXO setup with the following parameters 49 | # Language: de 50 | # DB password: root 51 | # Create DB: no 52 | # Admin username: admin 53 | # Admin password: adminpassword 54 | # Error E-mail: test@redaxo.invalid 55 | - name: Setup REDAXO 56 | run: | 57 | php redaxo_cms/redaxo/bin/console setup:run -n --lang=de_de --agree-license --db-password=root --db-createdb=no --db-setup=normal --admin-username=admin --admin-password=adminpassword --error-email=test@redaxo.invalid --ansi 58 | 59 | # copy Addon files, ignore some directories... 60 | # install the addon 61 | # if the addon name does not match the repository name, ${{ github.event.repository.name }} must be replaced with the addon name 62 | # if additional addons are needed, they can be installed via the console commands 63 | # see: https://www.redaxo.org/doku/main/basis-addons#console 64 | - name: Copy and install Addons 65 | run: | 66 | rsync -av --exclude='./vendor' --exclude='.github' --exclude='.git' --exclude='redaxo_cms' './' 'redaxo_cms/redaxo/src/addons/${{ github.event.repository.name }}' 67 | redaxo_cms/redaxo/bin/console package:install '${{ github.event.repository.name }}' 68 | 69 | # install dependencies from composer.json 70 | - name: Install test dependencies 71 | working-directory: redaxo_cms/redaxo/src/addons/${{ github.event.repository.name }} 72 | env: 73 | COMPOSER: composer.json 74 | run: composer install --prefer-dist --no-progress 75 | 76 | # run unit tests, see composer.json 77 | - name: Run pest 78 | working-directory: redaxo_cms/redaxo/src/addons/${{ github.event.repository.name }} 79 | run: composer test 80 | -------------------------------------------------------------------------------- /lib/input/date.php: -------------------------------------------------------------------------------- 1 | yearSelect = new rex_select(); 14 | $this->yearSelect->addOptions(range(2005, date('Y') + 10), true); 15 | $this->yearSelect->setAttribute('class', 'rex-form-select-year'); 16 | $this->yearSelect->setSize(1); 17 | 18 | $this->monthSelect = new rex_select(); 19 | $this->monthSelect->addOptions(range(1, 12), true); 20 | $this->monthSelect->setAttribute('class', 'rex-form-select-date'); 21 | $this->monthSelect->setSize(1); 22 | 23 | $this->daySelect = new rex_select(); 24 | $this->daySelect->addOptions(range(1, 31), true); 25 | $this->daySelect->setAttribute('class', 'rex-form-select-date'); 26 | $this->daySelect->setSize(1); 27 | } 28 | 29 | public function setValue($value) 30 | { 31 | if (!is_array($value)) { 32 | throw new InvalidArgumentException('Expecting $value to be an array!'); 33 | } 34 | 35 | foreach (['year', 'month', 'day'] as $reqIndex) { 36 | if (!isset($value[$reqIndex])) { 37 | throw new rex_exception('Missing index "' . $reqIndex . '" in $value!'); 38 | } 39 | } 40 | 41 | $this->yearSelect->setSelected($value['year']); 42 | $this->monthSelect->setSelected($value['month']); 43 | $this->daySelect->setSelected($value['day']); 44 | 45 | parent::setValue($value); 46 | } 47 | 48 | public function setAttribute($name, $value) 49 | { 50 | if ('name' == $name) { 51 | $this->yearSelect->setName($value . '[year]'); 52 | $this->monthSelect->setName($value . '[month]'); 53 | $this->daySelect->setName($value . '[day]'); 54 | } elseif ('id' == $name) { 55 | $this->yearSelect->setId($value . '_year'); 56 | $this->monthSelect->setId($value . '_month'); 57 | $this->daySelect->setId($value); 58 | } else { 59 | $this->yearSelect->setAttribute($name, $value); 60 | $this->monthSelect->setAttribute($name, $value); 61 | $this->daySelect->setAttribute($name, $value); 62 | } 63 | 64 | parent::setAttribute($name, $value); 65 | } 66 | 67 | public function getDaySelect() 68 | { 69 | return $this->daySelect; 70 | } 71 | 72 | public function getMonthSelect() 73 | { 74 | return $this->monthSelect; 75 | } 76 | 77 | public function getYearSelect() 78 | { 79 | return $this->yearSelect; 80 | } 81 | 82 | public function getHtml() 83 | { 84 | $name = $this->getAttribute('name'); 85 | $html = ''; 86 | 87 | if ($name === 'glob_datetime') { 88 | $html .= $this->daySelect->get(); 89 | $html .= $this->monthSelect->get(); 90 | $html .= $this->yearSelect->get(); 91 | } else { 92 | $html .= '
    '; 93 | $html .= $this->daySelect->get(); 94 | $html .= $this->monthSelect->get(); 95 | $html .= $this->yearSelect->get(); 96 | $html .= '
    '; 97 | } 98 | 99 | return $html; 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /assets/css/global_settings.css: -------------------------------------------------------------------------------- 1 | .global-settings.nav-tabs { 2 | margin-bottom: 20px; 3 | border-bottom: 1px solid #bfe0d8; 4 | } 5 | 6 | .global-settings.nav-tabs > li.active > a, 7 | .global-settings.nav-tabs.nav-tabs > li.active > a:hover, 8 | .global-settings.nav-tabs.nav-tabs > li.active > a:focus { 9 | background-color: #e9f5ef; 10 | border: 1px solid #bfe0d8; 11 | border-bottom: 1px solid #e9f5ef; 12 | border-top: 2px solid #3bb594; 13 | border-radius: 4px 4px 0 0; 14 | color: #333333; 15 | } 16 | 17 | .global-settings.nav-tabs > li > a { 18 | color: #333333; 19 | background-color: #e6eaf0; 20 | border-color: #e6eaf0; 21 | border-radius: 4px 4px 0 0; 22 | } 23 | 24 | .global-settings.nav-tabs > li > a:hover { 25 | color: #ffffff; 26 | background-color: #3bb594; 27 | border-color: #3bb594; 28 | } 29 | 30 | .global-settings.nav-tabs li label { 31 | font-weight: normal; 32 | cursor: pointer; 33 | margin-bottom: 0; 34 | } 35 | 36 | .sp-replacer, 37 | .sp-replacer:hover, 38 | .sp-replacer.sp-active, 39 | .sp-container { 40 | border-color: #c1c9d4; 41 | } 42 | 43 | dl.rex-form-group.global-settings-datetime dd { 44 | display: grid; 45 | grid-template-columns: 2fr auto 1fr; 46 | gap: 0.5rem; 47 | align-items: center; 48 | } 49 | 50 | dl.rex-form-group.global-settings-date dd .global-settings-date-wrapper { 51 | display: grid; 52 | grid-template-columns: 1fr 1fr 2fr; 53 | gap: 0.5rem; 54 | } 55 | 56 | dl.rex-form-group.global-settings-date dd .global-settings-time-wrapper { 57 | display: grid; 58 | grid-template-columns: 1fr 1fr; 59 | gap: 0.5rem; 60 | } 61 | 62 | body.rex-theme-dark .global-settings.nav-tabs { 63 | border-bottom: 1px solid #1a3332; 64 | } 65 | 66 | body.rex-theme-dark .global-settings.nav-tabs > li.active > a, 67 | body.rex-theme-dark .global-settings.nav-tabs > li.active > a:hover, 68 | body.rex-theme-dark .global-settings.nav-tabs > li.active > a:focus { 69 | background-color: #1f3d3c; 70 | border: 1px solid #1a3332; 71 | border-bottom: 1px solid #1f3d3c; 72 | border-top: 2px solid #3bb594; 73 | color: #c5cbcb; 74 | } 75 | 76 | body.rex-theme-dark .global-settings.nav-tabs > li > a { 77 | color: #8d8d8d; 78 | background-color: #1a3332; 79 | border-color: transparent; 80 | } 81 | 82 | body.rex-theme-dark .global-settings.nav-tabs > li > a:hover { 83 | color: #c5cbcb; 84 | } 85 | 86 | @media (prefers-color-scheme: dark) { 87 | body.rex-has-theme:not(.rex-theme-light) .global-settings.nav-tabs { 88 | border-bottom: 1px solid #1a3332; 89 | } 90 | 91 | body.rex-has-theme:not(.rex-theme-light) .global-settings.nav-tabs > li.active > a, 92 | body.rex-has-theme:not(.rex-theme-light) .global-settings.nav-tabs > li.active > a:hover, 93 | body.rex-has-theme:not(.rex-theme-light) .global-settings.nav-tabs > li.active > a:focus { 94 | background-color: #1f3d3c; 95 | border: 1px solid #1a3332; 96 | border-bottom: 1px solid #1f3d3c; 97 | border-top: 2px solid #3bb594; 98 | color: #c5cbcb; 99 | } 100 | 101 | body.rex-has-theme:not(.rex-theme-light) .global-settings.nav-tabs > li > a { 102 | color: #8d8d8d; 103 | background-color: #1a3332; 104 | border-color: transparent; 105 | } 106 | 107 | body.rex-has-theme:not(.rex-theme-light) .global-settings.nav-tabs > li > a:hover { 108 | color: #c5cbcb; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Globale Einstellungen, AddOn für REDAXO 5 2 | 3 | Mit diesem Addon kann man globale MetaInfos setzen, die für die gesamte Website gültig sind. Admins können Felder anlegen und bearbeiten, Nicht-Admins können diese nur bearbeiten 4 | 5 | ![Screenshot](https://github.com/FriendsOfREDAXO/global_settings/raw/assets/screenshot.png) 6 | (Beispiel) 7 | 8 | ## Features 9 | 10 | * MetaInfos für die gesamte Website 11 | * API für den Zugriff auf die Felder 12 | * Nicht-Admins dürfen Felder nur bearbeiten 13 | * Mehrsprachigkeit 14 | * Neue Feldertypen: Tab, Colorpicker 15 | 16 | ## Tabs 17 | 18 | Das AddOn kann Felder in Tabs gruppieren. Hier ein Beispiel für eine mögliche Gruppierung in 3 Tabs: 19 | 20 | * Allgemein (mit allgemeinen Feldern) 21 | * Tracking Code (Textarea mit class="codemirror", wenn installiert) 22 | * Übersetzungen (mit Text-Felder wie bei Sprog oder beim String Table Addon für R4). 23 | 24 | ## Colorpicker 25 | 26 | * Der eingsetzte Colorpicker ist dieser hier: https://bgrins.github.io/spectrum/ 27 | * Alle Optionen lassen sich auch per data-Attribut festlegen (einzugeben in Globale Einstellungen > Felder > Feldattribute), siehe den Tip hier https://bgrins.github.io/spectrum/#options 28 | * Beispiel: `data-preferred-format="rgb" data-show-alpha="true"` zeigt rgba Werte an inkl. Alpha-Transparenzen. 29 | 30 | ## API 31 | 32 | ```php 33 | // Ausgabe eines Feldes der aktuellen Sprache 34 | echo rex_global_settings::getValue('my_field'); 35 | 36 | // Ausgabe eines Feldes der Sprache mit der ID = 2 37 | echo rex_global_settings::getValue('my_field', 2); 38 | 39 | // Ausgabe eines Feldes der Haupt-Sprache 40 | echo rex_global_settings::getDefaultValue('my_field'); 41 | 42 | // Ausgabe eines Feldes der aktuellen Sprache, wenn leer kommt Ausgabe {{ my_field }} 43 | echo rex_global_settings::getString('my_field'); 44 | 45 | // Ausgabe eines Feldes der Sprache mit der ID = 2, wenn leer kommt Ausgabe {{ my_field }} 46 | echo rex_global_settings::getString('my_field', 2); 47 | 48 | // Ausgabe eines Feldes der Haupt-Sprache, wenn leer kommt Ausgabe {{ my_field }} 49 | echo rex_global_settings::getDefaultString('my_field'); 50 | 51 | // Ausgabe der Felddefinition als Array 52 | dump(rex_global_settings::getFieldDefinition('my_field')); 53 | 54 | // Überschreiben eines Feldwertes der aktuellen Sprache mit dem Wert "Hallo" 55 | rex_global_settings::setValue('my_field', null, "Hallo"); 56 | 57 | // Überschreiben eines Feldwertes der Sprache mit der ID = 2 mit dem Wert "Hallo" 58 | rex_global_settings::setValue('my_field', 2, "Hallo"); 59 | ``` 60 | 61 | ## REDAXO-Variable 62 | 63 | Die REDAXO-Variable `REX_GLOBAL_VAR` kann in Modulen und Templates verwendet werden um Werte auszulesen. 64 | Sie entspricht der Ausgabe von: `rex_global_settings::getString('my_field')`. 65 | 66 | Verwendung: 67 | 68 | ``` 69 | REX_GLOBAL_VAR[my_field] 70 | ``` 71 | 72 | ``` 73 | REX_GLOBAL_VAR[var=my_field] 74 | ``` 75 | 76 | Benötigt man einen leeren Rückgabewert für Prüfungen 77 | 78 | ``` 79 | REX_GLOBAL_VAR[var=my_field empty=1] 80 | ``` 81 | 82 | ## Hinweise 83 | 84 | * Addon kann als String Table / Sprog Ersatz genutzt werden durch Einsatz der Tabs. Die Feldbezeichnung können auch leer gelassen werden, dann wird direkt der Feldname (Spaltenname) dem Enduser angezeigt. 85 | 86 | ## Changelog 87 | 88 | siehe `CHANGELOG.md` des AddOns 89 | 90 | ## Lizenz 91 | 92 | MIT-Lizenz, siehe `LICENSE.md` des AddOns und Release notes 93 | 94 | ## Credits 95 | 96 | * REXDude 97 | * Spectrum Color Picker 98 | * Global Settings ist ein Fork des Meta Info Addons 99 | * @eaCe 100 | * @Sysix 101 | * @polarpixel 102 | * @skerbis 103 | * @alxndr-w 104 | 105 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Globale Einstellungen - Changelog 2 | 3 | ## Version 2.8.7 4 | - RGBA-Colorpicker mit Alpha-Kanal-Unterstützung als Direktwahl hinzugefügt 5 | 6 | ## Version 2.8.6 7 | - Datumsfelder werden nun nebeneinander angezeigt, die Checkbox um das Datum zu aktivieren bzw. deaktivieren wurde entfernt. Das Datum wird nun immer gespeichert. 8 | 9 | ## Version 2.8.0 10 | - update: Textfelder werden jetzt als "mediumtext" angelegt 11 | - update: Kopiervorlage - Ausgaben werden direkt in der Feldübersicht anzeigen 12 | 13 | ## Version 2.6.2 14 | - fixed: Notice-Spalte bei Update hinzufügen #36 15 | 16 | ## Version 2.6.1 17 | - fixed: Datei im Medienpool kann nicht gelöscht werden #35 18 | 19 | ## Version 2.6.0 20 | - Rechte der Tabs werden an Felder vererbt 21 | - Felder und Tabs können Notizen hinzugefügt werden 22 | - Verwendete Medien werden vor dem löschen geschützt 23 | 24 | ## Version 2.5.1 25 | - Replaced data-path by cache @alexplus.de 26 | - Spanish translation @nandes2062 27 | 28 | ## Version 2.5.0 29 | 30 | Einstellungen können nun auch mit rex_global_settings::setValue() gesetzt werden, Danke @alexplusde 31 | 32 | ## Version 2.4.1 33 | 34 | REX_GLOBAL_VAR rex_escape entfernt, damit HTML-Ausgaben möglich werden. 35 | 36 | ## Version 2.4.0 37 | 38 | Var= ist nun optional 39 | 40 | Es kann nun auch folgende Schreibweise verwendet werden: 41 | 42 | REX_GLOBAL_VAR[key] 43 | 44 | ## Version 2.3.1 45 | 46 | Bugfix Release 47 | 48 | 49 | ## Version 2.3.0 - 08.08.2019 50 | 51 | Neu: `REX_GLOBAL_VAR[var=my_field empty=1]` 52 | 53 | um leere Felder prüfen zu können. 54 | 55 | 56 | ## Version 2.2.0 - 25.07.2019 57 | 58 | Ab jetzt ein FriendsOfREDAXO-Projekt 59 | 60 | * Neu: Readme mit AutoToc 61 | * Neu `REX_GLOBAL_VAR` liefert das Value des Feldes als String der aktuellen Sprache 62 | * Neu: `rex_global_settings::getFieldDefinition('my_field')` liefert die Felddefinition als Array 63 | * Screenshot hinzugefügt 64 | 65 | ## Version 2.1.0 - 09. Juni 2018 66 | 67 | * Extension Point `GLOBAL_SETTINGS_CHANGED` hinzugefügt. Wird getriggert wenn die Felder oder die Settings aktualisiert wurden 68 | * Focus wird auf erstes Textfeld gelegt beim anlegen/bearbeiten eines Feldes 69 | * Tab Cursor korrigiert, thx@fietstouring 70 | * Addon-Menüeintrag wird nur noch angezeigt wenn der Benutzer das Recht für die Einstellungen-Seite hat, thx@Gort 71 | * File-Cache für die Einstellungen hinzugefügt, benötigt keine DB Abfragen mehr wenn einmal gecachet 72 | * Ausgabe der Codebeispiele für REDAXO 5.6 wiederhergestellt 73 | 74 | ## Version 2.0.0 - 15. März 2017 75 | 76 | * Portierung zu REDAXO 5 77 | * Neuer Feldtyp: Tab, dadurch kann man das AddOn auch als String Table oder Sprog ersatz benutzen. Die Feldbezeichnung können auch leer gelassen werden, dann wird direkt der Feldname (Spaltenname) dem Enduser angezeigt. 78 | * Neuer Feldtyp: Colorpicker (siehe Readme für Hinweise) 79 | * Der `glob_` Prefix ist jetzt optional. Aufruf sollte so erfolgen: `rex_global_settings::getValue('my_field');`. Beim Feldanlegen sollte ebenfalls kein `glob_` benutzt werden. 80 | * Hinzugefügt: `rex_global_settings::getString()` und `rex_global_settings::getDefaultString()`. Wie `getValue()` nur dass standardmäßig ein Platzhalter angezeigt wird wenn Ausgabe leer ist. 81 | * Ein dritter Parameter `$allowEmpty` für `getValue()` und `getString()` wurde hinzugefügt der steuert ob ein Platzhalter angezeigt wird wenn Feld leer oder nicht da. `getValue()` Standard: nicht anzeigen, `getString()` Standard: anzeigen 82 | 83 | ## Version 1.1.0 - 01. März 2016 84 | 85 | * Fixed #10: Checkboxen gingen nicht, specialthx@Sysix 86 | * Fixed #11: Wenn Feld nicht vorhanden war gab es eine Fehlermeldung, specialthx@Sysix 87 | * Kategorie-Checkbox entfernt, da keine Funktion 88 | * Fixed: Database down Problem wenn REDAXO Setup gestartet wurde 89 | * Fixed #8: Felder wurden nicht korrekt ausgelesen unter PHP 5.3 90 | 91 | ## Version 1.0.1 - 20. August 2015 92 | 93 | * Englische Backend Übersetzung hinzugefügt 94 | 95 | ## Version 1.0.0 - 11. August 2015 96 | 97 | -------------------------------------------------------------------------------- /lib/input.php: -------------------------------------------------------------------------------- 1 | value = ''; 11 | $this->attributes = []; 12 | } 13 | 14 | /** 15 | * Setzt den Value des Input-Feldes. 16 | */ 17 | public function setValue($value) 18 | { 19 | $this->value = $value; 20 | } 21 | 22 | /** 23 | * Gibt den Wert des Input-Feldes zurueck. 24 | */ 25 | public function getValue() 26 | { 27 | return $this->value; 28 | } 29 | 30 | /** 31 | * Setzt ein HTML-Attribut des Input-Feldes. 32 | */ 33 | public function setAttribute($name, $value) 34 | { 35 | if ('value' == $name) { 36 | $this->value = $value; 37 | } else { 38 | $this->attributes[$name] = $value; 39 | } 40 | } 41 | 42 | /** 43 | * Gibt den Wert des Attributes $name zurueck falls vorhanden, sonst $default. 44 | */ 45 | public function getAttribute($name, $default = null) 46 | { 47 | if ('value' == $name) { 48 | return $this->getValue(); 49 | } 50 | if (isset($this->attributes[$name])) { 51 | return $this->attributes[$name]; 52 | } 53 | 54 | return $default; 55 | } 56 | 57 | /** 58 | * Prueft ob das Input-Feld ein Attribute $name besitzt. 59 | */ 60 | public function hasAttribute($name) 61 | { 62 | return isset($this->attributes[$name]); 63 | } 64 | 65 | /** 66 | * Fuegt dem Input-Feld die Attribute $attributes hinzu. 67 | */ 68 | public function addAttributes($attributes) 69 | { 70 | foreach ($attributes as $name => $value) { 71 | $this->setAttribute($name, $value); 72 | } 73 | } 74 | 75 | /** 76 | * Setzt die Attribute des Input-Feldes auf $attributes. 77 | * Alle vorher vorhanden Attribute werden geloescht/ueberschrieben. 78 | */ 79 | public function setAttributes($attributes) 80 | { 81 | $this->attributes = []; 82 | 83 | foreach ($attributes as $name => $value) { 84 | $this->setAttribute($name, $value); 85 | } 86 | } 87 | 88 | /** 89 | * Gibt alle Attribute in Form eines Array zurueck. 90 | */ 91 | public function getAttributes() 92 | { 93 | return $this->attributes; 94 | } 95 | 96 | /** 97 | * Gibt alle Attribute in String-Form zurueck. 98 | */ 99 | public function getAttributeString() 100 | { 101 | $attr = ''; 102 | foreach ($this->attributes as $attributeName => $attributeValue) { 103 | $attr .= ' ' . $attributeName . '="' . $attributeValue . '"'; 104 | } 105 | return $attr; 106 | } 107 | 108 | /** 109 | * Gibt die HTML-Representation des Input-Feldes zurueck. 110 | * Diese beeinhaltet alle Attribute und den Wert des Feldes. 111 | */ 112 | abstract public function getHtml(); 113 | 114 | /** 115 | * Factory-Methode um rex_global_settings_input_*-Elemente anhand des Types $inputType zu erstellen. 116 | * 117 | * @param string $inputType 118 | * 119 | * @return self 120 | */ 121 | public static function factory($inputType) 122 | { 123 | switch ($inputType) { 124 | case 'text': 125 | case 'colorpicker': 126 | case 'rgbacolorpicker': 127 | case 'textarea': 128 | case 'select': 129 | case 'categoryselect': 130 | case 'mediacategoryselect': 131 | case 'radio': 132 | case 'checkbox': 133 | case 'date': 134 | case 'time': 135 | case 'datetime': 136 | case 'mediabutton': 137 | case 'medialistbutton': 138 | case 'linkbutton': 139 | case 'linklistbutton': 140 | $class = 'rex_global_settings_input_' . $inputType; 141 | return new $class(); 142 | } 143 | return null; 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /lang/en_gb.lang: -------------------------------------------------------------------------------- 1 | global_settings_settings = Settings 2 | global_settings_fields = Fields 3 | global_settings_help = Help 4 | global_settings_help_readme = Readme 5 | global_settings_help_changelog = Changelog 6 | global_settings_help_license = Licence 7 | 8 | global_settings_title = Global Settings 9 | global_settings_global_settings_not_found = No fields were found 10 | 11 | global_settings_field_list_caption = Fields 12 | 13 | global_settings_field_fieldset = Create and edit fields 14 | global_settings_field_label_prefix = Prefix 15 | global_settings_field_label_title = Field title 16 | global_settings_field_label_output = Output 17 | global_settings_field_label_name = Field name 18 | global_settings_field_label_function = Function 19 | global_settings_field_label_functions = Functions 20 | global_settings_field_label_id = Id 21 | global_settings_field_label_type = Type 22 | global_settings_field_label_note = Notice 23 | global_settings_field_label_attributes = Attributes 24 | global_settings_field_label_callback = Callback 25 | global_settings_field_label_callback_templates = Callback templates 26 | global_settings_field_label_default = Default value 27 | global_settings_field_label_nullable = Mandatory field 28 | global_settings_field_label_params = Parameter 29 | global_settings_field_label_priority = Position 30 | global_settings_field_label_restrictions = Only available in following categories 31 | global_settings_field_label_no_restrictions = Available in all categories 32 | 33 | global_settings_field_notice_title = Prepend "translate:" for I18N translation 34 | 35 | global_settings_field_first_priority = At the beginning 36 | global_settings_field_after_priority = After field "{0}" 37 | 38 | global_settings_field_params_notice_3 = Examples:
    a) all|user|admin
    b) 1:all|2:user|3:admin
    c) SELECT label,id FROM my_table WHERE a=4
    d) (DB2) SELECT label,id FROM my_table WHERE a=4 39 | global_settings_field_params_notice_4 = Examples:
    a) all|user|admin
    b) 1:all|2:user|3:admin
    c) SELECT label,id FROM my_table WHERE a=4
    d) (DB2) SELECT label,id FROM my_table WHERE a=4 40 | global_settings_field_params_notice_5 = Examples:
    a) all|user|admin
    b) 1:all|2:user|3:admin
    c) SELECT label,id FROM my_table WHERE a=4
    d) (DB2) SELECT label,id FROM my_table WHERE a=4 41 | global_settings_field_params_notice_6 = Example:
    category="1" types="gif,jpg" preview="1" 42 | global_settings_field_params_notice_7 = Example:
    category="1" types="gif,jpg" preview="1" 43 | global_settings_field_params_notice_8 = Example:
    category="1" 44 | global_settings_field_params_notice_9 = Example:
    category="1" 45 | 46 | global_settings_field_attributes_notice = Example:
    style="color:red;" multiple="multiple" class="my_css_class" perm="admin[]" 47 | global_settings_field_label_notice = Code run on field edit
    Readable Variables: string $fieldName, string $fieldValue, rex_sql $field 48 | 49 | global_settings_field_error_name = Please fill in the field name! 50 | global_settings_field_error_unique_name = A field with this name already exists! 51 | global_settings_field_error_unique_type = A type with this name already exists! 52 | global_settings_field_error_chars_name = The field name contains invalid symbols (use A-Z, 0-9 and _)! 53 | global_settings_field_error_invalid_prefix = Invalid Prefix! 54 | global_settings_field_error_invalid_type = Invalid Type! 55 | global_settings_field_error_invalid_length = Invalid field length! 56 | global_settings_field_error_invalid_name = Invalid field name! 57 | global_settings_field_error_invalid_fieldid = Invalid field id! 58 | global_settings_field_error_invalid_typeid = Invalid type id! 59 | global_settings_field_error_deleted = Couldn't delete the field! 60 | global_settings_field_successfull_deleted = Field deleted successfully! 61 | global_settings_field_successfull_saved = Data successfully saved! 62 | 63 | global_settings_default_fields_create = Create default fields 64 | global_settings_default_fields_created = Default fields created successfully! 65 | 66 | global_settings_edit_global_settings = Edit global settings 67 | global_settings_metadata_saved = Global settings saved 68 | 69 | global_settings_media_in_use_glob = Global Settings (Metadata) 70 | 71 | global_settings_callback_lang_indep_field = Field independent of language 72 | 73 | global_settings_save_settings = Save settings 74 | -------------------------------------------------------------------------------- /lang/sv_se.lang: -------------------------------------------------------------------------------- 1 | global_settings_settings = Inställningar 2 | global_settings_fields = Fält 3 | global_settings_help = Hjälp 4 | global_settings_help_readme = Readme 5 | global_settings_help_changelog = Changelog 6 | global_settings_help_license = Licens 7 | 8 | global_settings_title = Globala inställnigar 9 | global_settings_global_settings_not_found = Inga fält hittades 10 | 11 | global_settings_field_list_caption = Fält 12 | 13 | global_settings_field_fieldset = Redigera/skapa fält 14 | global_settings_field_label_prefix = Prefix 15 | global_settings_field_label_title = Fältnamn 16 | global_settings_field_label_name = Spaltnamn 17 | global_settings_field_label_function = Funktion 18 | global_settings_field_label_functions = Funktioner 19 | global_settings_field_label_id = Id 20 | global_settings_field_label_type = Fälttyp 21 | global_settings_field_label_note = Notis 22 | global_settings_field_label_attributes = Fältattribut 23 | global_settings_field_label_callback = Callback 24 | global_settings_field_label_callback_templates = Callback mallar 25 | global_settings_field_label_default = Standard värde 26 | global_settings_field_label_nullable = Obligatoriskt fält 27 | global_settings_field_label_params = Parameter 28 | global_settings_field_label_priority = Fältpostition 29 | global_settings_field_label_restrictions = Endast tillgängligt i följande kategorier 30 | global_settings_field_label_no_restrictions = Finns i alla kategorier 31 | 32 | global_settings_field_notice_title = Prefixet "translate:" översätter värdet via I18N 33 | 34 | global_settings_field_first_priority = Vid början 35 | global_settings_field_after_priority = Efter fält "{0}" 36 | 37 | global_settings_field_params_notice_3 = Exempel:
    a) all|user|admin
    b) 1: all|2:user|3:admin
    c) SELECT labelt,id FROM my_table WHERE a=4
    d) (DB2) SELECT label,id FROM my_table WHERE a=4 38 | global_settings_field_params_notice_4 = Exempel:
    a) all|user|admin
    b) 1: all|2:user|3:admin
    c) SELECT labelt,id FROM my_table WHERE a=4
    d) (DB2) SELECT label,id FROM my_table WHERE a=4 39 | global_settings_field_params_notice_5 = Exempel:
    a) all|user|admin
    b) 1: all|2:user|3:admin
    c) SELECT labelt,id FROM my_table WHERE a=4
    d) (DB2) SELECT label,id FROM my_table WHERE a=4 40 | global_settings_field_params_notice_6 = Exempel:
    category = "1" types = "gif, jpg" preview = "1" 41 | global_settings_field_params_notice_7 = Exempel:
    category = "1" types = "gif, jpg" preview = "1" 42 | global_settings_field_params_notice_8 = Exempel:
    category = "1" 43 | global_settings_field_params_notice_9 = Exempel:
    category = "1" 44 | 45 | global_settings_field_attributes_notice = Exempel:
    style = "color: red;" multiple = "multiple" class= "my_css_class" perm = "admin []" 46 | global_settings_field_label_notice = Code som körs när värdet på fältet ändras.
    Läsbara variabler: string $fieldName, string $fieldValue, rex_sql $field 47 | 48 | global_settings_field_error_name = Ange kolumnnamn! 49 | global_settings_field_error_unique_name = Det angivna kolumnnamnet finns redan! 50 | global_settings_field_error_unique_type = Det angivna typnamnet finns redan! 51 | global_settings_field_error_chars_name = Kolumnnamnet innehåller ogiltiga tecken (tillåtna är A-Z, 0-9 och _)! 52 | global_settings_field_error_invalid_prefix = Det angivna prefixet är ogiltigt! 53 | global_settings_field_error_invalid_type = Den angivna typen är ogiltig! 54 | global_settings_field_error_invalid_length = Den angivna fältlängden är ogiltig! 55 | global_settings_field_error_invalid_name = Det angivna kolumnnamnet är ogiltig! 56 | global_settings_field_error_invalid_fieldid = Den angivna fält-id är ogiltig! 57 | global_settings_field_error_invalid_typeid = Den angivna typ-id är ogiltig! 58 | global_settings_field_error_deleted = Fältet raderades inte! 59 | global_settings_field_successfull_deleted = Fältet raderas framgångsrikt! 60 | global_settings_field_successfull_saved = Data sparas framgångsrikt! 61 | 62 | global_settings_default_fields_create = Skapa standardfält 63 | global_settings_default_fields_created = Standardfält skapade framgångsrikt! 64 | 65 | global_settings_edit_global_settings = Redigera globala inställningar 66 | global_settings_metadata_saved = Globala inställningarna sparades 67 | 68 | global_settings_media_in_use_glob = Globala inställningar (Metadata) 69 | 70 | global_settings_callback_lang_indep_field = Språkoberoende fält 71 | 72 | global_settings_save_settings = Spara inställningarna 73 | 74 | 75 | -------------------------------------------------------------------------------- /lang/de_de.lang: -------------------------------------------------------------------------------- 1 | global_settings_settings = Einstellungen 2 | global_settings_fields = Felder 3 | global_settings_help = Hilfe 4 | global_settings_help_readme = Readme 5 | global_settings_help_changelog = Changelog 6 | global_settings_help_license = Lizenz 7 | 8 | global_settings_title = Globale Einstellungen 9 | global_settings_global_settings_not_found = Es wurden keine Felder gefunden 10 | 11 | global_settings_field_list_caption = Felder 12 | 13 | global_settings_field_fieldset = Feld bearbeiten/erstellen 14 | global_settings_field_label_prefix = Prefix 15 | global_settings_field_label_title = Feldbezeichnung 16 | global_settings_field_label_output = Ausgabe 17 | global_settings_field_label_name = Spaltenname 18 | global_settings_field_label_function = Funktion 19 | global_settings_field_label_functions = Funktionen 20 | global_settings_field_label_id = Id 21 | global_settings_field_label_type = Feldtyp 22 | global_settings_field_label_note = Notiz 23 | global_settings_field_label_attributes = HTML-Attribute 24 | global_settings_field_label_callback = Callback 25 | global_settings_field_label_callback_templates = Callback-Vorlagen 26 | global_settings_field_label_default = Standardwert 27 | global_settings_field_label_nullable = Pflichtfeld 28 | global_settings_field_label_params = Parameter 29 | global_settings_field_label_priority = Feldposition 30 | global_settings_field_label_restrictions = Nur in folgenden Kategorien verfügbar 31 | global_settings_field_label_no_restrictions = In allen Kategorien verfügbar 32 | 33 | global_settings_field_notice_title = Prefix "translate:" übersetzt den Wert via I18N 34 | 35 | global_settings_field_first_priority = Am Anfang 36 | global_settings_field_after_priority = Nach dem Feld "{0}" 37 | 38 | global_settings_field_params_notice_3 = Beispiele:
    a) all|user|admin
    b) 1:all|2:user|3:admin
    c) SELECT label,id FROM my_table WHERE a=4
    d) (DB2) SELECT label,id FROM my_table WHERE a=4 39 | global_settings_field_params_notice_4 = Beispiele:
    a) all|user|admin
    b) 1:all|2:user|3:admin
    c) SELECT label,id FROM my_table WHERE a=4
    d) (DB2) SELECT label,id FROM my_table WHERE a=4 40 | global_settings_field_params_notice_5 = Beispiele:
    a) all|user|admin
    b) 1:all|2:user|3:admin
    c) SELECT label,id FROM my_table WHERE a=4
    d) (DB2) SELECT label,id FROM my_table WHERE a=4 41 | global_settings_field_params_notice_6 = Beispiel:
    category="1" types="gif,jpg" preview="1" 42 | global_settings_field_params_notice_7 = Beispiel:
    category="1" types="gif,jpg" preview="1" 43 | global_settings_field_params_notice_8 = Beispiel:
    category="1" 44 | global_settings_field_params_notice_9 = Beispiel:
    category="1" 45 | 46 | global_settings_field_attributes_notice = Beispiel:
    style="color:red;" multiple="multiple" class="my_css_class" perm="admin[]" 47 | global_settings_field_label_notice = Code der ausgeführt wird, wenn der Wert des Feldes geändert wird.
    Lesbare Variablen: string $fieldName, string $fieldValue, rex_sql $field 48 | 49 | global_settings_field_error_name = Bitte Spaltennamen eingeben! 50 | global_settings_field_error_unique_name = Der angegebene Spaltenname existiert schon! 51 | global_settings_field_error_unique_type = Der angegebene Typename existiert schon! 52 | global_settings_field_error_chars_name = Der Spaltennamen enthält ungültige Zeichen (Erlaubt sind A-Z, 0-9 und _)! 53 | global_settings_field_error_invalid_prefix = Der angegebene Prefix ist ungültig! 54 | global_settings_field_error_invalid_type = Der angegebene Type ist ungültig! 55 | global_settings_field_error_invalid_length = Die angegebene Feldlänge ist ungültig! 56 | global_settings_field_error_invalid_name = Der angegebene Spaltenname ist ungültig! 57 | global_settings_field_error_invalid_fieldid = Die angegebene Feld-Id ist ungültig! 58 | global_settings_field_error_invalid_typeid = Die angegebene Type-Id ist ungültig! 59 | global_settings_field_error_deleted = Feld wurde nicht gelöscht! 60 | global_settings_field_successfull_deleted = Feld erfolgreich gelöscht! 61 | global_settings_field_successfull_saved = Daten erfolgreich gespeichert! 62 | 63 | global_settings_default_fields_create = Standardfelder erstellen 64 | global_settings_default_fields_created = Standardfelder erfolgreich erstellt! 65 | 66 | global_settings_edit_global_settings = Globale Einstellungen bearbeiten 67 | global_settings_metadata_saved = Die Globalen Einstellungen wurden gespeichert. 68 | 69 | global_settings_media_in_use_glob = Globale Einstellungen (Metadaten) 70 | 71 | global_settings_callback_lang_indep_field = Sprachunabhängiges Feld 72 | 73 | global_settings_save_settings = Einstellungen speichern 74 | 75 | 76 | -------------------------------------------------------------------------------- /lang/es_es.lang: -------------------------------------------------------------------------------- 1 | global_settings_settings = Ajustes 2 | global_settings_fields = Campos 3 | global_settings_help = Ayuda 4 | global_settings_help_readme = Léame 5 | global_settings_help_changelog = Cambios 6 | global_settings_help_license = Licencia 7 | 8 | global_settings_title = Configuraciones globales 9 | global_settings_global_settings_not_found = No se encontraron campos 10 | 11 | global_settings_field_list_caption = campos 12 | 13 | global_settings_field_fieldset = Editar / crear campo 14 | global_settings_field_label_prefix = prefijo 15 | global_settings_field_label_title = Nombre del campo 16 | global_settings_field_label_name = nombre de la columna 17 | global_settings_field_label_function = función 18 | global_settings_field_label_functions = características 19 | global_settings_field_label_id = identificación 20 | global_settings_field_label_type = tipo de campo 21 | global_settings_field_label_note = Nota 22 | global_settings_field_label_attributes = atributos de campo 23 | global_settings_field_label_callback = devolución de llamada 24 | global_settings_field_label_callback_templates = Plantillas de devolución de llamada 25 | global_settings_field_label_default = defecto 26 | global_settings_field_label_nullable = campo obligatorio 27 | global_settings_field_label_params = parámetro 28 | global_settings_field_label_priority = posición en el campo 29 | global_settings_field_label_restrictions = Solo disponible en las siguientes categorías 30 | global_settings_field_label_no_restrictions = Disponible en todas las categorias 31 | 32 | global_settings_field_notice_title = El prefijo "traducir:" traduce el valor a través de I18N 33 | 34 | global_settings_field_first_priority = Al principio 35 | global_settings_field_after_priority = Después del campo "{0}" 36 | 37 | global_settings_field_params_notice_3 = Ejemplos:
    a) todos | usuario | admin
    b) 1: todos | 2: usuario | 3: admin
    c) etiqueta SELECT, id FROM my_table WHERE a = 4
    d) (DB2) SELECT label, id FROM my_table WHERE a = 4 38 | global_settings_field_params_notice_4 = Ejemplos:
    a) todos | usuario | admin
    b) 1: todos | 2: usuario | 3: admin
    c) etiqueta SELECT, id FROM my_table WHERE a = 4
    d) (DB2) SELECT label, id FROM my_table WHERE a = 4 39 | global_settings_field_params_notice_5 = Ejemplos:
    a) todos | usuario | admin
    b) 1: todos | 2: usuario | 3: admin
    c) etiqueta SELECT, id FROM my_table WHERE a = 4
    d) (DB2) SELECT label, id FROM my_table WHERE a = 4 40 | global_settings_field_params_notice_6 = Ejemplo:
    category = "1" types = "gif, jpg" preview = "1" 41 | global_settings_field_params_notice_7 = Ejemplo:
    category = "1" types = "gif, jpg" preview = "1" 42 | global_settings_field_params_notice_8 = Ejemplo:
    category = "1" 43 | global_settings_field_params_notice_9 = Ejemplo:
    category = "1" 44 | 45 | global_settings_field_attributes_notice = Ejemplo:
    style = "color: red;" multiple = "multiple" class = "my_css_class" perm = "admin []" 46 | global_settings_field_label_notice = Código ejecutado cuando se cambia el valor del campo.
    Variables legibles: string $ fieldName, string $ fieldValue, rex_sql $ field 47 | 48 | global_settings_field_error_name = Por favor ingrese el nombre de la columna! 49 | global_settings_field_error_unique_name = ¡El nombre de columna especificado ya existe! 50 | global_settings_field_error_unique_type = ¡El nombre de tipo especificado ya existe! 51 | global_settings_field_error_chars_name = ¡El nombre de la columna contiene caracteres no válidos (los permitidos son A-Z, 0-9 y _)! 52 | global_settings_field_error_invalid_prefix = ¡El prefijo especificado no es válido! 53 | global_settings_field_error_invalid_type = ¡El tipo especificado no es válido! 54 | global_settings_field_error_invalid_length = ¡La longitud del campo especificado no es válida! 55 | global_settings_field_error_invalid_name = ¡El nombre de columna especificado no es válido! 56 | global_settings_field_error_invalid_fieldid = ¡La ID de campo especificada no es válida! 57 | global_settings_field_error_invalid_typeid = ¡El Id. De tipo especificado no es válido! 58 | global_settings_field_error_deleted = ¡El campo no fue eliminado! 59 | global_settings_field_successfull_deleted = ¡Campo eliminado con éxito! 60 | global_settings_field_successfull_saved = ¡Datos guardados con éxito! 61 | 62 | global_settings_default_fields_create = Crear campos estándar 63 | global_settings_default_fields_created = ¡Campos estándar creados con éxito! 64 | 65 | global_settings_edit_global_settings = Editar configuración global 66 | global_settings_metadata_saved = La configuración global se ha guardado. 67 | 68 | global_settings_media_in_use_glob = Configuración global (metadatos) 69 | 70 | global_settings_callback_lang_indep_field = Campo independiente del idioma 71 | 72 | global_settings_save_settings = Guardar configuración 73 | -------------------------------------------------------------------------------- /lib/rex_global_settings.php: -------------------------------------------------------------------------------- 1 | getArray('SELECT * FROM ' . rex::getTablePrefix() . 'global_settings'); 25 | 26 | if (is_array($result)) { 27 | // build globalValues array based on clang then key/value 28 | for ($i = 0; $i < count($result); ++$i) { 29 | $clangId = $result[$i]['clang']; 30 | unset($result[$i]['clang']); 31 | 32 | self::$globalValues[$clangId] = $result[$i]; 33 | } 34 | 35 | // create cache dir if necessary 36 | $dataCache = rex_path::addonCache('global_settings'); 37 | 38 | if (!file_exists($dataCache)) { 39 | if (!mkdir($dataCache, rex::getDirPerm(), true)) { 40 | throw new Exception('Dir "' . $dataCache . '" could not be created! Check if server permissions are set correctly.'); 41 | } 42 | } 43 | 44 | // store in cachefile for next time 45 | if (!file_put_contents(self::$cacheFile, 'setDebug(0)->setQuery('UPDATE ' . rex::getTablePrefix() . 'global_settings SET ' . $field . ' = :value WHERE clang = :clang', [':value' => $value, ':clang' => $clangId]); 91 | self::deleteCache(); 92 | return true; 93 | } 94 | return false; 95 | 96 | } 97 | 98 | public static function getDefaultString($field, $allowEmpty = false) 99 | { 100 | return self::getDefaultValue($field, $allowEmpty); 101 | } 102 | 103 | public static function getString($field, $clangId = null, $allowEmpty = false) 104 | { 105 | return self::getValue($field, $clangId, $allowEmpty); 106 | } 107 | 108 | protected static function getEmptyFieldOutput($field, $value, $allowEmpty) 109 | { 110 | if (!$allowEmpty && '' == $value) { 111 | return '{{ ' . self::getStrippedField($field) . ' }}'; 112 | } 113 | return $value; 114 | 115 | } 116 | 117 | public static function getStrippedField($field) 118 | { 119 | if (str_starts_with($field, self::FIELD_PREFIX)) { 120 | $field = substr($field, strlen(self::FIELD_PREFIX)); 121 | } 122 | 123 | return $field; 124 | } 125 | 126 | public static function getFieldDefinition($field) 127 | { 128 | $field = self::FIELD_PREFIX . self::getStrippedField($field); 129 | $sql = rex_sql::factory(); 130 | $result = $sql->getArray('SELECT * FROM ' . rex::getTablePrefix() . 'global_settings_field WHERE name = :name', ['name' => $field]); 131 | return $result[0]; 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /pages/field.php: -------------------------------------------------------------------------------- 1 | Parameter 19 | if (empty($prefix)) { 20 | throw new rex_exception('Fehler: Prefix nicht definiert!'); 21 | } 22 | 23 | if (empty($metaTable)) { 24 | throw new rex_exception('Fehler: metaTable nicht definiert!'); 25 | } 26 | 27 | $Basedir = __DIR__; 28 | $field_id = rex_request('field_id', 'int'); 29 | 30 | // ------------------------------> Feld loeschen 31 | if ('delete' == $func) { 32 | $field_id = rex_request('field_id', 'int', 0); 33 | if (0 != $field_id) { 34 | if (rex_global_settings_delete_field($field_id)) { 35 | rex_extension::registerPoint(new rex_extension_point('GLOBAL_SETTINGS_CHANGED')); 36 | 37 | echo rex_view::success(rex_i18n::msg('global_settings_field_successfull_deleted')); 38 | } else { 39 | echo rex_view::error(rex_i18n::msg('global_settings_field_error_deleted')); 40 | } 41 | } 42 | $func = ''; 43 | } 44 | 45 | // ------------------------------> Eintragsliste 46 | if ('' == $func) { 47 | echo rex_api_function::getMessage(); 48 | 49 | $title = rex_i18n::msg('global_settings_field_list_caption'); 50 | 51 | // replace LIKE wildcards 52 | $likePrefix = str_replace(['_', '%'], ['\_', '\%'], $prefix); 53 | 54 | $list = rex_global_settings_list::factory('SELECT id, name, title FROM ' . rex::getTablePrefix() . 'global_settings_field WHERE `name` LIKE "' . $likePrefix . '%" ORDER BY priority'); 55 | $list->addTableAttribute('class', 'table-striped'); 56 | 57 | $tdIcon = ''; 58 | $thIcon = ''; 59 | $list->addColumn($thIcon, $tdIcon, 0, ['###VALUE###', '###VALUE###']); 60 | $list->setColumnParams($thIcon, ['func' => 'edit', 'field_id' => '###id###']); 61 | 62 | $list->removeColumn('id'); 63 | 64 | $list->setColumnLabel('id', rex_i18n::msg('global_settings_field_label_id')); 65 | $list->setColumnLayout('id', ['###VALUE###', '###VALUE###']); 66 | 67 | $list->setColumnLabel('name', rex_i18n::msg('global_settings_field_label_name')); 68 | $list->setColumnLayout('name', ['###VALUE###', '###VALUE###']); 69 | $list->setColumnParams('name', ['func' => 'edit', 'field_id' => '###id###']); 70 | 71 | $list->setColumnLabel('title', rex_i18n::msg('global_settings_field_label_title')); 72 | $list->setColumnLayout('title', ['###VALUE###', '###VALUE###']); 73 | 74 | $list->addColumn('output', ''); 75 | $list->setColumnLayout('output', ['' . rex_i18n::msg('global_settings_field_label_output') . '', '<?= rex_global_settings::getValue(\'###name###\'); ?>']); 76 | 77 | $list->addColumn(rex_i18n::msg('global_settings_field_label_functions'), ' ' . rex_i18n::msg('edit')); 78 | $list->setColumnLayout(rex_i18n::msg('global_settings_field_label_functions'), ['###VALUE###', '###VALUE###']); 79 | $list->setColumnParams(rex_i18n::msg('global_settings_field_label_functions'), ['func' => 'edit', 'field_id' => '###id###']); 80 | $list->addLinkAttribute(rex_i18n::msg('global_settings_field_label_functions'), 'class', 'rex-edit'); 81 | 82 | $list->addColumn('delete', ' ' . rex_i18n::msg('delete')); 83 | $list->setColumnLayout('delete', ['', '###VALUE###']); 84 | $list->setColumnParams('delete', ['func' => 'delete', 'field_id' => '###id###']); 85 | $list->addLinkAttribute('delete', 'data-confirm', rex_i18n::msg('delete') . ' ?'); 86 | $list->addLinkAttribute('delete', 'class', 'rex-delete'); 87 | 88 | $list->setNoRowsMessage(rex_i18n::msg('global_settings_global_settings_not_found')); 89 | 90 | $content .= $list->get(); 91 | 92 | $fragment = new rex_fragment(); 93 | $fragment->setVar('title', $title); 94 | 95 | if (in_array($prefix, ['art_', 'med_'])) { 96 | $defaultFields = sprintf( 97 | '', 98 | rex_url::currentBackendPage(['rex-api-call' => 'global_settings_default_fields_create', 'type' => $subpage]), 99 | rex_i18n::msg('global_settings_default_fields_create'), 100 | ); 101 | $fragment->setVar('options', $defaultFields, false); 102 | } 103 | 104 | $fragment->setVar('content', $content, false); 105 | $content = $fragment->parse('core/page/section.php'); 106 | } // ------------------------------> Formular 107 | elseif ('edit' == $func || 'add' == $func) { 108 | $title = rex_i18n::msg('global_settings_field_fieldset'); 109 | $form = new rex_global_settings_table_expander($prefix, $metaTable, rex::getTablePrefix() . 'global_settings_field', 'id=' . $field_id); 110 | 111 | if ('edit' == $func) { 112 | $form->addParam('field_id', $field_id); 113 | } 114 | 115 | $content .= $form->get(); 116 | 117 | $fragment = new rex_fragment(); 118 | $fragment->setVar('class', 'edit', false); 119 | $fragment->setVar('title', $title); 120 | $fragment->setVar('body', $content, false); 121 | $content = $fragment->parse('core/page/section.php'); 122 | } 123 | 124 | echo $content; 125 | -------------------------------------------------------------------------------- /functions/function_global_settings.php: -------------------------------------------------------------------------------- 1 | getParams(); 6 | $newClangId = $params['clang']->getId(); 7 | 8 | $sql = rex_sql::factory(); 9 | $sql->setQuery('INSERT INTO `' . rex::getTablePrefix() . 'global_settings` (`clang`) VALUES (' . $newClangId . ')'); 10 | } 11 | 12 | function rex_global_settings_clang_deleted($ep) 13 | { 14 | $params = $ep->getParams(); 15 | $id = $params['id']; 16 | 17 | $sql = rex_sql::factory(); 18 | $sql->setQuery('DELETE FROM `' . rex::getTablePrefix() . 'global_settings` WHERE `clang` = ' . $id); 19 | } 20 | 21 | function rex_global_settings_check_langs() 22 | { 23 | foreach (rex_clang::getAll() as $clang) { 24 | $sql = rex_sql::factory(); 25 | $sql->setQuery('SELECT `clang` FROM ' . rex::getTablePrefix() . 'global_settings WHERE `clang` = ' . $clang->getId()); 26 | 27 | switch ($sql->getRows()) { 28 | case 0: 29 | $sql = rex_sql::factory(); 30 | $sql->setQuery('INSERT INTO `' . rex::getTablePrefix() . 'global_settings` (`clang`) VALUES (' . $clang->getId() . ')'); 31 | break; 32 | case 1: 33 | // clang is in the database 34 | break; 35 | default: 36 | throw new Exception('global_settings: clang #' . $clang->getId() . ' is ' . $sql->getRows() . 'x in the database, only once allowed.'); 37 | } 38 | } 39 | } 40 | 41 | /** 42 | * Fügt einen neuen Feldtyp ein. 43 | * 44 | * Gibt beim Erfolg die Id des Feldes zurück, bei Fehler die Fehlermeldung 45 | */ 46 | function rex_global_settings_add_field_type($label, $dbtype, $dblength) 47 | { 48 | if (!is_string($label) || empty($label)) { 49 | return rex_i18n::msg('global_settings_field_error_invalid_name'); 50 | } 51 | 52 | if (!is_string($dbtype) || empty($dbtype)) { 53 | return rex_i18n::msg('global_settings_field_error_invalid_type'); 54 | } 55 | 56 | if (!is_int($dblength) || empty($dblength)) { 57 | return rex_i18n::msg('global_settings_field_error_invalid_length'); 58 | } 59 | 60 | $qry = 'SELECT * FROM ' . rex::getTablePrefix() . 'global_settings_type WHERE label=:label LIMIT 1'; 61 | $sql = rex_sql::factory(); 62 | $sql->setQuery($qry, [':label' => $label]); 63 | if (0 != $sql->getRows()) { 64 | return rex_i18n::msg('global_settings_field_error_unique_type'); 65 | } 66 | 67 | $sql->setTable(rex::getTablePrefix() . 'global_settings_type'); 68 | $sql->setValue('label', $label); 69 | $sql->setValue('dbtype', $dbtype); 70 | $sql->setValue('dblength', $dblength); 71 | 72 | $sql->insert(); 73 | return $sql->getLastId(); 74 | } 75 | 76 | /** 77 | * Löscht einen Feldtyp. 78 | * 79 | * Gibt beim Erfolg true zurück, sonst eine Fehlermeldung 80 | */ 81 | function rex_global_settings_delete_field_type($field_type_id) 82 | { 83 | if (!is_int($field_type_id) || empty($field_type_id)) { 84 | return rex_i18n::msg('global_settings_field_error_invalid_typeid'); 85 | } 86 | 87 | $sql = rex_sql::factory(); 88 | $sql->setTable(rex::getTablePrefix() . 'global_settings_type'); 89 | $sql->setWhere(['id' => $field_type_id]); 90 | 91 | $sql->delete(); 92 | return 1 == $sql->getRows(); 93 | } 94 | 95 | /** 96 | * Fügt ein MetaFeld hinzu und legt dafür eine Spalte in der MetaTable an. 97 | */ 98 | function rex_global_settings_add_field($title, $name, $priority, $attributes, $type, $default, $params = null, $validate = null, $restrictions = '') 99 | { 100 | $prefix = rex_global_settings_meta_prefix($name); 101 | $metaTable = rex_global_settings_meta_table($prefix); 102 | 103 | // Prefix korrekt? 104 | if (!$metaTable) { 105 | return rex_i18n::msg('global_settings_field_error_invalid_prefix'); 106 | } 107 | 108 | // TypeId korrekt? 109 | $qry = 'SELECT * FROM ' . rex::getTablePrefix() . 'global_settings_type WHERE id=' . $type . ' LIMIT 2'; 110 | $sql = rex_sql::factory(); 111 | $typeInfos = $sql->getArray($qry); 112 | 113 | if (1 != $sql->getRows()) { 114 | return rex_i18n::msg('global_settings_field_error_invalid_type'); 115 | } 116 | 117 | $fieldDbType = $typeInfos[0]['dbtype']; 118 | $fieldDbLength = $typeInfos[0]['dblength']; 119 | 120 | // Spalte existiert schon? 121 | $sql->setQuery('SELECT * FROM ' . $metaTable . ' LIMIT 1'); 122 | if (in_array($name, $sql->getFieldnames())) { 123 | return rex_i18n::msg('global_settings_field_error_unique_name'); 124 | } 125 | 126 | // Spalte extiert laut global_settings_field? 127 | $qry = 'SELECT * FROM ' . rex::getTablePrefix() . 'global_settings_field WHERE name=:name LIMIT 1'; 128 | $sql = rex_sql::factory(); 129 | $sql->setQuery($qry, [':name' => $name]); 130 | if (0 != $sql->getRows()) { 131 | return rex_i18n::msg('global_settings_field_error_unique_name'); 132 | } 133 | 134 | $sql->setTable(rex::getTablePrefix() . 'global_settings_field'); 135 | $sql->setValue('title', $title); 136 | $sql->setValue('name', $name); 137 | $sql->setValue('priority', $priority); 138 | $sql->setValue('attributes', $attributes); 139 | $sql->setValue('type_id', $type); 140 | $sql->setValue('default', $default); 141 | $sql->setValue('params', $params); 142 | $sql->setValue('validate', $validate); 143 | $sql->setValue('restrictions', $restrictions); 144 | $sql->addGlobalUpdateFields(); 145 | $sql->addGlobalCreateFields(); 146 | 147 | $sql->insert(); 148 | 149 | // replace LIKE wildcards 150 | $prefix = str_replace(['_', '%'], ['\_', '\%'], $prefix); 151 | 152 | rex_sql_util::organizePriorities(rex::getTablePrefix() . 'global_settings_field', 'priority', 'name LIKE "' . $prefix . '%"', 'priority, updatedate'); 153 | 154 | $tableManager = new rex_global_settings_table_manager($metaTable); 155 | return $tableManager->addColumn($name, $fieldDbType, $fieldDbLength, $default); 156 | } 157 | 158 | function rex_global_settings_delete_field($fieldIdOrName) 159 | { 160 | // Löschen anhand der FieldId 161 | if (is_int($fieldIdOrName)) { 162 | $fieldQry = 'SELECT * FROM ' . rex::getTablePrefix() . 'global_settings_field WHERE id=:idOrName LIMIT 2'; 163 | $invalidField = rex_i18n::msg('global_settings_field_error_invalid_fieldid'); 164 | } // Löschen anhand des Feldnames 165 | elseif (is_string($fieldIdOrName)) { 166 | $fieldQry = 'SELECT * FROM ' . rex::getTablePrefix() . 'global_settings_field WHERE name=:idOrName LIMIT 2'; 167 | $invalidField = rex_i18n::msg('global_settings_field_error_invalid_name'); 168 | } else { 169 | throw new InvalidArgumentException('global_settings: Unexpected type for $fieldIdOrName!'); 170 | } 171 | // Feld existiert? 172 | $sql = rex_sql::factory(); 173 | $sql->setQuery($fieldQry, [':idOrName' => $fieldIdOrName]); 174 | 175 | if (1 != $sql->getRows()) { 176 | return $invalidField; 177 | } 178 | 179 | $name = $sql->getValue('name'); 180 | $field_id = $sql->getValue('id'); 181 | 182 | $prefix = rex_global_settings_meta_prefix($name); 183 | $metaTable = rex_global_settings_meta_table($prefix); 184 | 185 | // Spalte existiert? 186 | $sql->setQuery('SELECT * FROM ' . $metaTable . ' LIMIT 1'); 187 | if (!in_array($name, $sql->getFieldnames())) { 188 | return rex_i18n::msg('global_settings_field_error_invalid_name'); 189 | } 190 | 191 | $sql->setTable(rex::getTablePrefix() . 'global_settings_field'); 192 | $sql->setWhere(['id' => $field_id]); 193 | 194 | $sql->delete(); 195 | 196 | $tableManager = new rex_global_settings_table_manager($metaTable); 197 | return $tableManager->deleteColumn($name); 198 | } 199 | 200 | /** 201 | * Extrahiert den Prefix aus dem Namen eine Spalte. 202 | */ 203 | function rex_global_settings_meta_prefix($name) 204 | { 205 | if (!is_string($name)) { 206 | return false; 207 | } 208 | 209 | if (($pos = strpos($name, '_')) !== false) { 210 | return substr(strtolower($name), 0, $pos + 1); 211 | } 212 | 213 | return false; 214 | } 215 | 216 | /** 217 | * Gibt die mit dem Prefix verbundenen Tabellennamen zurück. 218 | */ 219 | function rex_global_settings_meta_table($prefix) 220 | { 221 | $metaTables = rex_addon::get('global_settings')->getProperty('metaTables', []); 222 | 223 | if (isset($metaTables[$prefix])) { 224 | return $metaTables[$prefix]; 225 | } 226 | 227 | return false; 228 | } 229 | 230 | /** 231 | * Bindet ggf extensions ein. 232 | */ 233 | function rex_global_settings_extensions_handler(rex_extension_point $ep) 234 | { 235 | $page = $ep->getSubject(); 236 | $mainpage = rex_be_controller::getCurrentPagePart(1); 237 | $mypage = 'global_settings'; 238 | 239 | // additional javascripts 240 | if ('global_settings' == $mainpage) { 241 | rex_view::addJsFile(rex_url::addonAssets($mypage, 'js/spectrum.js')); 242 | rex_view::addJsFile(rex_url::addonAssets($mypage, 'js/global_settings.js')); 243 | 244 | rex_view::addCssFile(rex_url::addonAssets($mypage, 'css/spectrum.css')); 245 | rex_view::addCssFile(rex_url::addonAssets($mypage, 'css/global_settings.css')); 246 | } 247 | } 248 | -------------------------------------------------------------------------------- /lib/table_expander.php: -------------------------------------------------------------------------------- 1 | metaPrefix = $metaPrefix; 11 | $this->tableManager = new rex_global_settings_table_manager($metaTable); 12 | 13 | parent::__construct($tableName, rex_i18n::msg('global_settings_field_fieldset'), $whereCondition, $method, $debug); 14 | } 15 | 16 | public function init() 17 | { 18 | // ----- EXTENSION POINT 19 | // IDs aller Feldtypen bei denen das Parameter-Feld eingeblendet werden soll 20 | $typeFields = rex_extension::registerPoint(new rex_extension_point('GLOBAL_SETTINGS_TYPE_FIELDS', [REX_GLOBAL_SETTINGS_FIELD_SELECT, REX_GLOBAL_SETTINGS_FIELD_RADIO, REX_GLOBAL_SETTINGS_FIELD_CHECKBOX, REX_GLOBAL_SETTINGS_FIELD_REX_MEDIA_WIDGET, REX_GLOBAL_SETTINGS_FIELD_REX_MEDIALIST_WIDGET, REX_GLOBAL_SETTINGS_FIELD_REX_LINK_WIDGET, REX_GLOBAL_SETTINGS_FIELD_REX_LINKLIST_WIDGET])); 21 | 22 | $field = $this->addTextField('name'); 23 | $field->setLabel(rex_i18n::msg('global_settings_field_label_name')); 24 | $field->setAttribute('id', 'global-settings-name-field'); 25 | 26 | $field = $this->addSelectField('priority'); 27 | $field->setLabel(rex_i18n::msg('global_settings_field_label_priority')); 28 | $select = $field->getSelect(); 29 | $select->setSize(1); 30 | $select->addOption(rex_i18n::msg('global_settings_field_first_priority'), 1); 31 | // Im Edit Mode das Feld selbst nicht als Position einf�gen 32 | $qry = 'SELECT name,priority FROM ' . $this->tableName . ' WHERE `name` LIKE "' . $this->metaPrefix . '%"'; 33 | if ($this->isEditMode()) { 34 | $qry .= ' AND id != ' . $this->getParam('field_id'); 35 | } 36 | $qry .= ' ORDER BY priority'; 37 | $sql = rex_sql::factory(); 38 | $sql->setQuery($qry); 39 | $value = 1; 40 | for ($i = 0; $i < $sql->getRows(); ++$i) { 41 | $value = $sql->getValue('priority') + 1; 42 | $select->addOption( 43 | rex_i18n::rawMsg('global_settings_field_after_priority', rex_global_settings::getStrippedField($sql->getValue('name'))), 44 | $value, 45 | ); 46 | $sql->next(); 47 | } 48 | if (!$this->isEditMode()) { 49 | $select->setSelected($value); 50 | } 51 | 52 | $field = $this->addTextField('title'); 53 | $field->setLabel(rex_i18n::msg('global_settings_field_label_title')); 54 | $field->setNotice(rex_i18n::msg('global_settings_field_notice_title')); 55 | 56 | $field = $this->addTextField('notice'); 57 | $field->setLabel(rex_i18n::msg('global_settings_field_label_note')); 58 | 59 | $gq = rex_sql::factory(); 60 | $gq->setQuery('SELECT dbtype,id FROM ' . rex::getTablePrefix() . 'global_settings_type'); 61 | $textFields = []; 62 | foreach ($gq->getArray() as $f) { 63 | if ('text' == $f['dbtype']) { 64 | $textFields[$f['id']] = $f['id']; 65 | } 66 | } 67 | 68 | $field = $this->addSelectField('type_id'); 69 | $field->setLabel(rex_i18n::msg('global_settings_field_label_type')); 70 | $field->setAttribute('onchange', 'gs_checkConditionalFields(this, new Array(' . implode(',', $typeFields) . '), new Array(' . implode(',', $textFields) . '));'); 71 | $select = $field->getSelect(); 72 | $select->setSize(1); 73 | 74 | $qry = 'SELECT label,id FROM ' . rex::getTablePrefix() . 'global_settings_type'; 75 | $select->addSqlOptions($qry); 76 | 77 | $notices = ''; 78 | for ($i = 1; $i < REX_GLOBAL_SETTINGS_FIELD_COUNT; ++$i) { 79 | if (rex_i18n::hasMsg('global_settings_field_params_notice_' . $i)) { 80 | $notices .= '' . "\n"; 81 | } 82 | } 83 | $notices .= ' 84 | '; 88 | 89 | $field = $this->addTextAreaField('params'); 90 | $field->setLabel(rex_i18n::msg('global_settings_field_label_params')); 91 | $field->setNotice($notices); 92 | 93 | $field = $this->addTextAreaField('attributes'); 94 | $field->setLabel(rex_i18n::msg('global_settings_field_label_attributes')); 95 | $notice = rex_i18n::msg('global_settings_field_attributes_notice') . "\n"; 96 | $field->setNotice($notice); 97 | 98 | $field = $this->addTextAreaField('callback'); 99 | $field->setLabel(rex_i18n::msg('global_settings_field_label_callback')); 100 | $notice = rex_i18n::msg('global_settings_field_label_notice') . "\n"; 101 | $field->setNotice($notice); 102 | 103 | $field = $this->addTextField('default'); 104 | $field->setLabel(rex_i18n::msg('global_settings_field_label_default')); 105 | 106 | /*if ('clang_' !== $this->metaPrefix) { 107 | $attributes = []; 108 | $attributes['internal::fieldClass'] = 'rex_form_restrictons_element'; 109 | $field = $this->addField('', 'restrictions', null, $attributes); 110 | $field->setLabel(rex_i18n::msg('global_settings_field_label_restrictions')); 111 | $field->setAttribute('size', 10); 112 | $field->setAttribute('class', 'form-control'); 113 | }*/ 114 | 115 | parent::init(); 116 | } 117 | 118 | protected function delete() 119 | { 120 | // Infos zuerst selektieren, da nach parent::delete() nicht mehr in der db 121 | $sql = rex_sql::factory(); 122 | $sql->setDebug($this->debug); 123 | $sql->setTable($this->tableName); 124 | $sql->setWhere($this->whereCondition); 125 | $sql->select('name'); 126 | $columnName = $sql->getValue('name'); 127 | 128 | if (($result = parent::delete()) === true) { 129 | // Prios neu setzen, damit keine lücken entstehen 130 | $this->organizePriorities(1, 2); 131 | return $this->tableManager->deleteColumn($columnName); 132 | } 133 | 134 | return $result; 135 | } 136 | 137 | protected function preSave($fieldsetName, $fieldName, $fieldValue, rex_sql $saveSql) 138 | { 139 | if ($fieldsetName == $this->getFieldsetName() && 'name' == $fieldName) { 140 | // Den Namen mit Prefix speichern 141 | return $this->addPrefix($fieldValue); 142 | } 143 | 144 | return parent::preSave($fieldsetName, $fieldName, $fieldValue, $saveSql); 145 | } 146 | 147 | protected function preView($fieldsetName, $fieldName, $fieldValue) 148 | { 149 | if ($fieldsetName == $this->getFieldsetName() && 'name' == $fieldName) { 150 | // Den Namen ohne Prefix anzeigen 151 | return $this->stripPrefix($fieldValue); 152 | } 153 | return parent::preView($fieldsetName, $fieldName, $fieldValue); 154 | } 155 | 156 | public function addPrefix($string) 157 | { 158 | $lowerString = strtolower($string); 159 | if (substr($lowerString, 0, strlen($this->metaPrefix)) !== $this->metaPrefix) { 160 | return $this->metaPrefix . $string; 161 | } 162 | return $string; 163 | } 164 | 165 | public function stripPrefix($string) 166 | { 167 | $lowerString = strtolower($string ?? ''); 168 | if (substr($lowerString, 0, strlen($this->metaPrefix)) === $this->metaPrefix) { 169 | return substr($string, strlen($this->metaPrefix)); 170 | } 171 | return $string; 172 | } 173 | 174 | protected function validate() 175 | { 176 | $fieldName = $this->elementPostValue($this->getFieldsetName(), 'name'); 177 | if ('' == $fieldName) { 178 | return rex_i18n::msg('global_settings_field_error_name'); 179 | } 180 | 181 | if (preg_match('/[^a-zA-Z0-9\_]/', $fieldName)) { 182 | return rex_i18n::msg('global_settings_field_error_chars_name'); 183 | } 184 | 185 | // Pruefen ob schon eine Spalte mit dem Namen existiert (nur beim add noetig) 186 | if (!$this->isEditMode()) { 187 | // die tabelle selbst checken 188 | if ($this->tableManager->hasColumn($this->addPrefix($fieldName))) { 189 | return rex_i18n::msg('global_settings_field_error_unique_name'); 190 | } 191 | 192 | // das meta-schema checken 193 | $sql = rex_sql::factory(); 194 | $sql->setQuery('SELECT * FROM ' . $this->tableName . ' WHERE name="' . $this->addPrefix($fieldName) . '" LIMIT 1'); 195 | if (1 == $sql->getRows()) { 196 | return rex_i18n::msg('global_settings_field_error_unique_name'); 197 | } 198 | } 199 | 200 | return parent::validate(); 201 | } 202 | 203 | protected function save() 204 | { 205 | $fieldName = $this->elementPostValue($this->getFieldsetName(), 'name'); 206 | 207 | // Den alten Wert aus der DB holen 208 | // Dies muss hier geschehen, da in parent::save() die Werte fuer die DB mit den 209 | // POST werten ueberschrieben werden! 210 | $fieldOldName = ''; 211 | $fieldOldPriority = 9999999999999; // dirty, damit die prio richtig l�uft... 212 | $fieldOldDefault = ''; 213 | if (1 == $this->sql->getRows()) { 214 | $fieldOldName = $this->sql->getValue('name'); 215 | $fieldOldPriority = $this->sql->getValue('priority'); 216 | $fieldOldDefault = $this->sql->getValue('default'); 217 | } 218 | 219 | if (parent::save()) { 220 | $this->organizePriorities($this->elementPostValue($this->getFieldsetName(), 'priority'), $fieldOldPriority); 221 | 222 | $fieldName = $this->addPrefix($fieldName); 223 | $fieldType = $this->elementPostValue($this->getFieldsetName(), 'type_id'); 224 | $fieldDefault = $this->elementPostValue($this->getFieldsetName(), 'default'); 225 | 226 | $sql = rex_sql::factory(); 227 | $sql->setDebug($this->debug); 228 | $result = $sql->getArray('SELECT `dbtype`, `dblength` FROM `' . rex::getTablePrefix() . 'global_settings_type` WHERE id=' . $fieldType); 229 | $fieldDbType = $result[0]['dbtype']; 230 | $fieldDbLength = $result[0]['dblength']; 231 | 232 | // TEXT Spalten duerfen in MySQL keine Defaultwerte haben 233 | if ('text' == $fieldDbType) { 234 | $fieldDefault = null; 235 | } 236 | 237 | if ($this->isEditMode()) { 238 | // Spalte in der Tabelle ver�ndern 239 | $tmRes = $this->tableManager->editColumn($fieldOldName, $fieldName, $fieldDbType, $fieldDbLength, $fieldDefault); 240 | } else { 241 | // Spalte in der Tabelle anlegen 242 | $tmRes = $this->tableManager->addColumn($fieldName, $fieldDbType, $fieldDbLength, $fieldDefault); 243 | } 244 | rex_delete_cache(); 245 | 246 | if ($tmRes) { 247 | // DefaultWerte setzen 248 | if ($fieldDefault != $fieldOldDefault) { 249 | try { 250 | $upd = rex_sql::factory(); 251 | $upd->setDebug($this->debug); 252 | $upd->setTable($this->tableManager->getTableName()); 253 | $upd->setWhere([$fieldName => $fieldOldDefault]); 254 | $upd->setValue($fieldName, $fieldDefault); 255 | $upd->update(); 256 | return true; 257 | } catch (rex_sql_exception $e) { 258 | return false; 259 | } 260 | } 261 | 262 | // Default werte haben schon zuvor gepasst, daher true zur�ckgeben 263 | return true; 264 | } 265 | } 266 | 267 | return false; 268 | } 269 | 270 | public function getPrefix() 271 | { 272 | return $this->metaPrefix; 273 | } 274 | 275 | protected function organizePriorities($newPrio, $oldPrio) 276 | { 277 | if ($newPrio == $oldPrio) { 278 | return; 279 | } 280 | 281 | // replace LIKE wildcards 282 | $metaPrefix = str_replace(['_', '%'], ['\_', '\%'], $this->metaPrefix); 283 | 284 | rex_sql_util::organizePriorities( 285 | $this->tableName, 286 | 'priority', 287 | 'name LIKE "' . $metaPrefix . '%"', 288 | 'priority, updatedate desc', 289 | ); 290 | } 291 | } 292 | -------------------------------------------------------------------------------- /assets/css/spectrum.css: -------------------------------------------------------------------------------- 1 | /*** 2 | Spectrum Colorpicker v1.8.0 3 | https://github.com/bgrins/spectrum 4 | Author: Brian Grinstead 5 | License: MIT 6 | ***/ 7 | 8 | .sp-container { 9 | position: absolute; 10 | top: 0; 11 | left: 0; 12 | display: inline-block; 13 | *display: inline; 14 | *zoom: 1; 15 | /* https://github.com/bgrins/spectrum/issues/40 */ 16 | z-index: 9999994; 17 | overflow: hidden; 18 | } 19 | 20 | .sp-container.sp-flat { 21 | position: relative; 22 | } 23 | 24 | /* Fix for * { box-sizing: border-box; } */ 25 | .sp-container, 26 | .sp-container * { 27 | -webkit-box-sizing: content-box; 28 | -moz-box-sizing: content-box; 29 | box-sizing: content-box; 30 | } 31 | 32 | /* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */ 33 | .sp-top { 34 | position: relative; 35 | width: 100%; 36 | display: inline-block; 37 | } 38 | 39 | .sp-top-inner { 40 | position: absolute; 41 | top: 0; 42 | left: 0; 43 | bottom: 0; 44 | right: 0; 45 | } 46 | 47 | .sp-color { 48 | position: absolute; 49 | top: 0; 50 | left: 0; 51 | bottom: 0; 52 | right: 20%; 53 | } 54 | 55 | .sp-hue { 56 | position: absolute; 57 | top: 0; 58 | right: 0; 59 | bottom: 0; 60 | left: 84%; 61 | height: 100%; 62 | } 63 | 64 | .sp-clear-enabled .sp-hue { 65 | top: 33px; 66 | height: 77.5%; 67 | } 68 | 69 | .sp-fill { 70 | padding-top: 80%; 71 | } 72 | 73 | .sp-sat, .sp-val { 74 | position: absolute; 75 | top: 0; 76 | left: 0; 77 | right: 0; 78 | bottom: 0; 79 | } 80 | 81 | .sp-alpha-enabled .sp-top { 82 | margin-bottom: 18px; 83 | } 84 | 85 | .sp-alpha-enabled .sp-alpha { 86 | display: block; 87 | } 88 | 89 | .sp-alpha-handle { 90 | position: absolute; 91 | top: -4px; 92 | bottom: -4px; 93 | width: 6px; 94 | left: 50%; 95 | cursor: pointer; 96 | border: 1px solid black; 97 | background: white; 98 | opacity: .8; 99 | } 100 | 101 | .sp-alpha { 102 | display: none; 103 | position: absolute; 104 | bottom: -14px; 105 | right: 0; 106 | left: 0; 107 | height: 8px; 108 | } 109 | 110 | .sp-alpha-inner { 111 | border: solid 1px #333333; 112 | } 113 | 114 | .sp-clear { 115 | display: none; 116 | } 117 | 118 | .sp-clear.sp-clear-display { 119 | background-position: center; 120 | } 121 | 122 | .sp-clear-enabled .sp-clear { 123 | display: block; 124 | position: absolute; 125 | top: 0px; 126 | right: 0; 127 | bottom: 0; 128 | left: 84%; 129 | height: 28px; 130 | } 131 | 132 | /* Don't allow text selection */ 133 | .sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-clear, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button { 134 | -webkit-user-select: none; 135 | -moz-user-select: -moz-none; 136 | -o-user-select: none; 137 | user-select: none; 138 | } 139 | 140 | .sp-container.sp-input-disabled .sp-input-container { 141 | display: none; 142 | } 143 | 144 | .sp-container.sp-buttons-disabled .sp-button-container { 145 | display: none; 146 | } 147 | 148 | .sp-container.sp-palette-buttons-disabled .sp-palette-button-container { 149 | display: none; 150 | } 151 | 152 | .sp-palette-only .sp-picker-container { 153 | display: none; 154 | } 155 | 156 | .sp-palette-disabled .sp-palette-container { 157 | display: none; 158 | } 159 | 160 | .sp-initial-disabled .sp-initial { 161 | display: none; 162 | } 163 | 164 | 165 | /* Gradients for hue, saturation and value instead of images. Not pretty... but it works */ 166 | .sp-sat { 167 | background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#ffffff), to(rgba(204, 154, 129, 0))); 168 | background-image: -webkit-linear-gradient(left, #ffffff, rgba(204, 154, 129, 0)); 169 | background-image: -moz-linear-gradient(left, #ffffff, rgba(204, 154, 129, 0)); 170 | background-image: -o-linear-gradient(left, #ffffff, rgba(204, 154, 129, 0)); 171 | background-image: -ms-linear-gradient(left, #ffffff, rgba(204, 154, 129, 0)); 172 | background-image: linear-gradient(to right, #ffffff, rgba(204, 154, 129, 0)); 173 | -ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)"; 174 | filter: progid:DXImageTransform.Microsoft.gradient(GradientType=1, startColorstr="#FFFFFFFF", endColorstr="#00CC9A81"); 175 | } 176 | 177 | .sp-val { 178 | background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0))); 179 | background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); 180 | background-image: -moz-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); 181 | background-image: -o-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); 182 | background-image: -ms-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0)); 183 | background-image: linear-gradient(to top, #000000, rgba(204, 154, 129, 0)); 184 | -ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)"; 185 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#00CC9A81", endColorstr="#FF000000"); 186 | } 187 | 188 | .sp-hue { 189 | background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); 190 | background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); 191 | background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); 192 | background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000)); 193 | background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); 194 | background: linear-gradient(to bottom, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); 195 | } 196 | 197 | /* IE filters do not support multiple color stops. 198 | Generate 6 divs, line them up, and do two color gradients for each. 199 | Yes, really. 200 | */ 201 | .sp-1 { 202 | height: 17%; 203 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff0000", endColorstr="#ffff00"); 204 | } 205 | 206 | .sp-2 { 207 | height: 16%; 208 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#ffff00", endColorstr="#00ff00"); 209 | } 210 | 211 | .sp-3 { 212 | height: 17%; 213 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#00ff00", endColorstr="#00ffff"); 214 | } 215 | 216 | .sp-4 { 217 | height: 17%; 218 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#00ffff", endColorstr="#0000ff"); 219 | } 220 | 221 | .sp-5 { 222 | height: 16%; 223 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#0000ff", endColorstr="#ff00ff"); 224 | } 225 | 226 | .sp-6 { 227 | height: 17%; 228 | filter: progid:DXImageTransform.Microsoft.gradient(startColorstr="#ff00ff", endColorstr="#ff0000"); 229 | } 230 | 231 | .sp-hidden { 232 | display: none !important; 233 | } 234 | 235 | /* Clearfix hack */ 236 | .sp-cf:before, .sp-cf:after { 237 | content: ""; 238 | display: table; 239 | } 240 | 241 | .sp-cf:after { 242 | clear: both; 243 | } 244 | 245 | .sp-cf { 246 | *zoom: 1; 247 | } 248 | 249 | /* Mobile devices, make hue slider bigger so it is easier to slide */ 250 | @media (max-device-width: 480px) { 251 | .sp-color { 252 | right: 40%; 253 | } 254 | 255 | .sp-hue { 256 | left: 63%; 257 | } 258 | 259 | .sp-fill { 260 | padding-top: 60%; 261 | } 262 | } 263 | 264 | .sp-dragger { 265 | border-radius: 5px; 266 | height: 5px; 267 | width: 5px; 268 | border: 1px solid #ffffff; 269 | background: #000000; 270 | cursor: pointer; 271 | position: absolute; 272 | top: 0; 273 | left: 0; 274 | } 275 | 276 | .sp-slider { 277 | position: absolute; 278 | top: 0; 279 | cursor: pointer; 280 | height: 3px; 281 | left: -1px; 282 | right: -1px; 283 | border: 1px solid #000000; 284 | background: white; 285 | opacity: .8; 286 | } 287 | 288 | /* 289 | Theme authors: 290 | Here are the basic themeable display options (colors, fonts, global widths). 291 | See http://bgrins.github.io/spectrum/themes/ for instructions. 292 | */ 293 | 294 | .sp-container { 295 | border-radius: 0; 296 | background-color: #ececec; 297 | border: solid 1px #f0c49b; 298 | padding: 0; 299 | } 300 | 301 | .sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue, .sp-clear { 302 | font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif; 303 | -webkit-box-sizing: border-box; 304 | -moz-box-sizing: border-box; 305 | -ms-box-sizing: border-box; 306 | box-sizing: border-box; 307 | } 308 | 309 | .sp-top { 310 | margin-bottom: 3px; 311 | } 312 | 313 | .sp-color, .sp-hue, .sp-clear { 314 | border: solid 1px #666666; 315 | } 316 | 317 | /* Input */ 318 | .sp-input-container { 319 | float: right; 320 | width: 100px; 321 | margin-bottom: 4px; 322 | } 323 | 324 | .sp-initial-disabled .sp-input-container { 325 | width: 100%; 326 | } 327 | 328 | .sp-input { 329 | font-size: 12px !important; 330 | border: 1px inset; 331 | padding: 4px 5px; 332 | margin: 0; 333 | width: 100%; 334 | background: transparent; 335 | border-radius: 3px; 336 | color: #222222; 337 | } 338 | 339 | .sp-input:focus { 340 | border: 1px solid orange; 341 | } 342 | 343 | .sp-input.sp-validation-error { 344 | border: 1px solid red; 345 | background: #ffdddd; 346 | } 347 | 348 | .sp-picker-container, .sp-palette-container { 349 | float: left; 350 | position: relative; 351 | padding: 10px; 352 | padding-bottom: 300px; 353 | margin-bottom: -290px; 354 | } 355 | 356 | .sp-picker-container { 357 | width: 172px; 358 | border-left: solid 1px #ffffff; 359 | } 360 | 361 | /* Palettes */ 362 | .sp-palette-container { 363 | border-right: solid 1px #cccccc; 364 | } 365 | 366 | .sp-palette-only .sp-palette-container { 367 | border: 0; 368 | } 369 | 370 | .sp-palette .sp-thumb-el { 371 | display: block; 372 | position: relative; 373 | float: left; 374 | width: 24px; 375 | height: 15px; 376 | margin: 3px; 377 | cursor: pointer; 378 | border: solid 2px transparent; 379 | } 380 | 381 | .sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active { 382 | border-color: orange; 383 | } 384 | 385 | .sp-thumb-el { 386 | position: relative; 387 | } 388 | 389 | /* Initial */ 390 | .sp-initial { 391 | float: left; 392 | border: solid 1px #333333; 393 | } 394 | 395 | .sp-initial span { 396 | width: 30px; 397 | height: 25px; 398 | border: none; 399 | display: block; 400 | float: left; 401 | margin: 0; 402 | } 403 | 404 | .sp-initial .sp-clear-display { 405 | background-position: center; 406 | } 407 | 408 | /* Buttons */ 409 | .sp-palette-button-container, 410 | .sp-button-container { 411 | float: right; 412 | } 413 | 414 | /* Replacer (the little preview div that shows up instead of the ) */ 415 | .sp-replacer { 416 | margin: 0; 417 | overflow: hidden; 418 | cursor: pointer; 419 | padding: 4px; 420 | display: inline-block; 421 | *zoom: 1; 422 | *display: inline; 423 | border: solid 1px #91765d; 424 | background: #eeeeee; 425 | color: #333333; 426 | vertical-align: middle; 427 | } 428 | 429 | .sp-replacer:hover, .sp-replacer.sp-active { 430 | border-color: #f0c49b; 431 | color: #111111; 432 | } 433 | 434 | .sp-replacer.sp-disabled { 435 | cursor: default; 436 | border-color: silver; 437 | color: silver; 438 | } 439 | 440 | .sp-dd { 441 | padding: 2px 0; 442 | height: 16px; 443 | line-height: 16px; 444 | float: left; 445 | font-size: 10px; 446 | } 447 | 448 | .sp-preview { 449 | position: relative; 450 | width: 25px; 451 | height: 20px; 452 | border: solid 1px #222222; 453 | margin-right: 5px; 454 | float: left; 455 | z-index: 0; 456 | } 457 | 458 | .sp-palette { 459 | *width: 220px; 460 | max-width: 220px; 461 | } 462 | 463 | .sp-palette .sp-thumb-el { 464 | width: 16px; 465 | height: 16px; 466 | margin: 2px 1px; 467 | border: solid 1px #d0d0d0; 468 | } 469 | 470 | .sp-container { 471 | padding-bottom: 0; 472 | } 473 | 474 | 475 | /* Buttons: http://hellohappy.org/css3-buttons/ */ 476 | .sp-container button { 477 | background-color: #eeeeee; 478 | background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc); 479 | background-image: -moz-linear-gradient(top, #eeeeee, #cccccc); 480 | background-image: -ms-linear-gradient(top, #eeeeee, #cccccc); 481 | background-image: -o-linear-gradient(top, #eeeeee, #cccccc); 482 | background-image: linear-gradient(to bottom, #eeeeee, #cccccc); 483 | border: 1px solid #cccccc; 484 | border-bottom: 1px solid #bbbbbb; 485 | border-radius: 3px; 486 | color: #333333; 487 | font-size: 14px; 488 | line-height: 1; 489 | padding: 5px 4px; 490 | text-align: center; 491 | text-shadow: 0 1px 0 #eeeeee; 492 | vertical-align: middle; 493 | } 494 | 495 | .sp-container button:hover { 496 | background-color: #dddddd; 497 | background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb); 498 | background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb); 499 | background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb); 500 | background-image: -o-linear-gradient(top, #dddddd, #bbbbbb); 501 | background-image: linear-gradient(to bottom, #dddddd, #bbbbbb); 502 | border: 1px solid #bbbbbb; 503 | border-bottom: 1px solid #999999; 504 | cursor: pointer; 505 | text-shadow: 0 1px 0 #dddddd; 506 | } 507 | 508 | .sp-container button:active { 509 | border: 1px solid #aaaaaa; 510 | border-bottom: 1px solid #888888; 511 | -webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; 512 | -moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; 513 | -ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; 514 | -o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; 515 | box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee; 516 | } 517 | 518 | .sp-cancel { 519 | font-size: 11px; 520 | color: #d93f3f !important; 521 | margin: 0; 522 | padding: 2px; 523 | margin-right: 5px; 524 | vertical-align: middle; 525 | text-decoration: none; 526 | 527 | } 528 | 529 | .sp-cancel:hover { 530 | color: #d93f3f !important; 531 | text-decoration: underline; 532 | } 533 | 534 | 535 | .sp-palette span:hover, .sp-palette span.sp-thumb-active { 536 | border-color: #000000; 537 | } 538 | 539 | .sp-preview, .sp-alpha, .sp-thumb-el { 540 | position: relative; 541 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); 542 | } 543 | 544 | .sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner { 545 | display: block; 546 | position: absolute; 547 | top: 0; 548 | left: 0; 549 | bottom: 0; 550 | right: 0; 551 | } 552 | 553 | .sp-palette .sp-thumb-inner { 554 | background-position: 50% 50%; 555 | background-repeat: no-repeat; 556 | } 557 | 558 | .sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner { 559 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=); 560 | } 561 | 562 | .sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner { 563 | background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=); 564 | } 565 | 566 | .sp-clear-display { 567 | background-repeat: no-repeat; 568 | background-position: center; 569 | background-image: url(data:image/gif;base64,R0lGODlhFAAUAPcAAAAAAJmZmZ2dnZ6enqKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq/Hx8fLy8vT09PX19ff39/j4+Pn5+fr6+vv7+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAAUABQAAAihAP9FoPCvoMGDBy08+EdhQAIJCCMybCDAAYUEARBAlFiQQoMABQhKUJBxY0SPICEYHBnggEmDKAuoPMjS5cGYMxHW3IiT478JJA8M/CjTZ0GgLRekNGpwAsYABHIypcAgQMsITDtWJYBR6NSqMico9cqR6tKfY7GeBCuVwlipDNmefAtTrkSzB1RaIAoXodsABiZAEFB06gIBWC1mLVgBa0AAOw==); 570 | } 571 | -------------------------------------------------------------------------------- /lib/handler/handler.php: -------------------------------------------------------------------------------- 1 | reset(); 31 | for ($i = 0; $i < $sqlFields->getRows(); $i++, $sqlFields->next()) { 32 | // Umschliessendes Tag von Label und Formularelement 33 | $tag = 'p'; 34 | $tag_attr = ''; 35 | 36 | $name = $sqlFields->getValue('name'); 37 | $notice = $sqlFields->getValue('notice'); 38 | $title = $sqlFields->getValue('title'); 39 | $params = $sqlFields->getValue('params'); 40 | $typeLabel = $sqlFields->getValue('label'); 41 | $attr = $sqlFields->getValue('attributes'); 42 | $dblength = $sqlFields->getValue('dblength'); 43 | 44 | $attrArray = rex_string::split($attr); 45 | if (isset($attrArray['perm']) && 'tab' !== $typeLabel) { 46 | if (!rex::getUser()->hasPerm($attrArray['perm'])) { 47 | continue; 48 | } 49 | unset($attrArray['perm']); 50 | } 51 | 52 | if ('tab' !== $typeLabel && $fieldWithinTab && $hideByTabPerm) { 53 | continue; 54 | } 55 | 56 | $defaultValue = $sqlFields->getValue('default'); 57 | if ($activeItem) { 58 | $itemValue = (string) $activeItem->getValue($name); 59 | 60 | if (str_contains($itemValue, '|+|')) { 61 | // Alte notation mit |+| als Trenner 62 | $dbvalues = explode('|+|', (string) $activeItem->getValue($name)); 63 | } else { 64 | // Neue Notation mit | als Trenner 65 | $dbvalues = explode('|', (string) $activeItem->getValue($name)); 66 | } 67 | } else { 68 | $dbvalues = (array) $sqlFields->getValue('default'); 69 | } 70 | 71 | if ('' != $title) { 72 | $label = rex_i18n::translate($title); 73 | } else { 74 | $label = htmlspecialchars($name); 75 | } 76 | 77 | $id = 'rex-global_settings-' . htmlspecialchars(preg_replace('/[^a-zA-Z0-9_-]/', '_', $name)); 78 | $labelIt = true; 79 | 80 | $label = ''; 81 | 82 | $field = ''; 83 | 84 | switch ($typeLabel) { 85 | case 'text': 86 | $tag_attr = ' class="form-control"'; 87 | 88 | $rexInput = rex_global_settings_input::factory($typeLabel); 89 | $rexInput->addAttributes($attrArray); 90 | $rexInput->setAttribute('id', $id); 91 | $rexInput->setAttribute('name', $name); 92 | if ($dblength > 0) { 93 | $rexInput->setAttribute('maxlength', $dblength); 94 | } 95 | if ($activeItem) { 96 | $rexInput->setValue($activeItem->getValue($name)); 97 | } else { 98 | $rexInput->setValue($defaultValue); 99 | } 100 | $field = $rexInput->getHtml(); 101 | 102 | $e = []; 103 | $e['label'] = $label; 104 | $e['field'] = $field; 105 | $e['note'] = $notice; 106 | $fragment = new rex_fragment(); 107 | $fragment->setVar('elements', [$e], false); 108 | $field = $fragment->parse('core/form/form.php'); 109 | 110 | break; 111 | case 'rgbacolorpicker': 112 | case 'colorpicker': 113 | $tag_attr = ' class="form-control"'; 114 | 115 | $rexInput = rex_global_settings_input::factory($typeLabel); 116 | $rexInput->addAttributes($attrArray); 117 | $rexInput->setAttribute('id', $id); 118 | $rexInput->setAttribute('name', $name); 119 | if ($dblength > 0) { 120 | $rexInput->setAttribute('maxlength', $dblength); 121 | } 122 | if ($activeItem) { 123 | $rexInput->setValue($activeItem->getValue($name)); 124 | } else { 125 | $rexInput->setValue($defaultValue); 126 | } 127 | $field = $rexInput->getHtml(); 128 | 129 | $e = []; 130 | $e['label'] = $label; 131 | $e['field'] = $field; 132 | $e['note'] = $notice; 133 | $fragment = new rex_fragment(); 134 | $fragment->setVar('elements', [$e], false); 135 | $field = $fragment->parse('core/form/form.php'); 136 | 137 | break; 138 | case 'checkbox': 139 | // Beachte auch default values in multiple fields bei ADD. 140 | // Im EDIT wurde dies bereits vorher gehandelt 141 | if (!$activeItem) { 142 | $defaultValue = explode('|', $defaultValue); 143 | } 144 | 145 | $name .= '[]'; 146 | // no break 147 | case 'radio': 148 | $formElements = []; 149 | 150 | $values = []; 151 | if ('SELECT' == rex_sql::getQueryType($params)) { 152 | $sql = rex_sql::factory(); 153 | $value_groups = $sql->getDBArray($params, [], PDO::FETCH_NUM); 154 | foreach ($value_groups as $value_group) { 155 | if (isset($value_group[1])) { 156 | $values[$value_group[1]] = $value_group[0]; 157 | } else { 158 | $values[$value_group[0]] = $value_group[0]; 159 | } 160 | } 161 | } else { 162 | $value_groups = explode('|', $params); 163 | foreach ($value_groups as $value_group) { 164 | // check ob key:value paar 165 | // und der wert beginnt nicht mit "translate:" 166 | if (str_contains($value_group, ':') 167 | && !str_starts_with($value_group, 'translate:') 168 | ) { 169 | $temp = explode(':', $value_group, 2); 170 | $values[$temp[0]] = rex_i18n::translate($temp[1]); 171 | } else { 172 | $values[$value_group] = rex_i18n::translate($value_group); 173 | } 174 | } 175 | } 176 | 177 | $oneValue = (1 == count($values)); 178 | 179 | $attrStr = ''; 180 | $classAdd = ''; 181 | $inline = false; 182 | 183 | if (false !== $key = array_search('inline', $attrArray)) { 184 | $inline = true; 185 | unset($attrArray[$key]); 186 | } 187 | foreach ($attrArray as $key => $value) { 188 | if ('class' == $key) { 189 | $classAdd = ' ' . $value; 190 | } else { 191 | $attrStr = ' ' . $key . '="' . $value . '"'; 192 | } 193 | } 194 | 195 | if (!$activeItem) { 196 | $dbvalues = (array) $defaultValue; 197 | } 198 | 199 | foreach ($values as $key => $value) { 200 | // wenn man keine Werte angibt (Boolean Chkbox/Radio) 201 | // Dummy Wert annehmen, damit an/aus unterscheidung funktioniert 202 | if ($oneValue && '' == $key) { 203 | $key = 'true'; 204 | } 205 | 206 | $selected = ''; 207 | if (in_array($key, $dbvalues)) { 208 | $selected = ' checked="checked"'; 209 | } 210 | 211 | $currentId = $id; 212 | 213 | $e = []; 214 | if ($oneValue) { 215 | $e['label'] = $label; 216 | } else { 217 | $currentId .= '-' . htmlspecialchars(preg_replace('/[^a-zA-Z0-9_-]/', '_', $key)); 218 | $e['label'] = ''; 219 | } 220 | $e['field'] = ''; 221 | $formElements[] = $e; 222 | } 223 | 224 | $fragment = new rex_fragment(); 225 | $fragment->setVar('elements', $formElements, false); 226 | $fragment->setVar('inline', $inline); 227 | 228 | if ('radio' == $typeLabel) { 229 | $field = $fragment->parse('core/form/radio.php'); 230 | } else { 231 | if (!$oneValue) { 232 | $fragment->setVar('grouped', true); 233 | } 234 | $field = $fragment->parse('core/form/checkbox.php'); 235 | } 236 | 237 | if (!$oneValue) { 238 | $e = []; 239 | $e['label'] = $label; 240 | $e['field'] = $field; 241 | $e['note'] = $notice; 242 | $fragment = new rex_fragment(); 243 | $fragment->setVar('elements', [$e], false); 244 | $field = $fragment->parse('core/form/form.php'); 245 | } 246 | 247 | break; 248 | case 'select': 249 | $tag_attr = ' class="form-control"'; 250 | 251 | $select = new rex_select(); 252 | $select->setStyle('class="form-control"'); 253 | $select->setName($name); 254 | $select->setId($id); 255 | 256 | $multiple = false; 257 | foreach ($attrArray as $attr_name => $attr_value) { 258 | if (empty($attr_name)) { 259 | continue; 260 | } 261 | 262 | $select->setAttribute($attr_name, $attr_value); 263 | 264 | if ('multiple' == $attr_name) { 265 | $multiple = true; 266 | $select->setName($name . '[]'); 267 | $select->setMultiple(); 268 | } 269 | } 270 | 271 | // Beachte auch default values in multiple fields bei ADD. 272 | // Im EDIT wurde dies bereits vorher gehandelt 273 | if ($multiple && !$activeItem) { 274 | $dbvalues = explode('|', $defaultValue); 275 | } 276 | 277 | // hier mit den "raw"-values arbeiten, da die rex_select klasse selbst escaped 278 | $select->setSelected($dbvalues); 279 | 280 | if ('SELECT' == rex_sql::getQueryType($params)) { 281 | // Werte via SQL Laden 282 | $select->addDBSqlOptions($params); 283 | } else { 284 | // Optionen mit | separiert 285 | // eine einzelne Option kann mit key:value separiert werden 286 | $values = []; 287 | $value_groups = explode('|', $params); 288 | foreach ($value_groups as $value_group) { 289 | // check ob key:value paar 290 | // und der wert beginnt nicht mit "translate:" 291 | if (str_contains($value_group, ':') 292 | && !str_starts_with($value_group, 'translate:') 293 | ) { 294 | $temp = explode(':', $value_group, 2); 295 | $values[$temp[0]] = rex_i18n::translate($temp[1]); 296 | } else { 297 | $values[$value_group] = rex_i18n::translate($value_group); 298 | } 299 | } 300 | $select->addOptions($values); 301 | } 302 | 303 | $field .= $select->get(); 304 | 305 | $e = []; 306 | $e['label'] = $label; 307 | $e['field'] = $field; 308 | $e['note'] = $notice; 309 | $fragment = new rex_fragment(); 310 | $fragment->setVar('elements', [$e], false); 311 | $field = $fragment->parse('core/form/form.php'); 312 | 313 | break; 314 | case 'date': 315 | case 'time': 316 | case 'datetime': 317 | $tag_attr = ' class="form-control-date"'; 318 | 319 | $active = 0 != $dbvalues[0]; 320 | if ('' == $dbvalues[0]) { 321 | $dbvalues[0] = time(); 322 | } 323 | 324 | $inputValue = []; 325 | $inputValue['year'] = date('Y', $dbvalues[0]); 326 | $inputValue['month'] = date('n', $dbvalues[0]); 327 | $inputValue['day'] = date('j', $dbvalues[0]); 328 | $inputValue['hour'] = date('G', $dbvalues[0]); 329 | $inputValue['minute'] = date('i', $dbvalues[0]); 330 | 331 | $rexInput = rex_global_settings_input::factory($typeLabel); 332 | $rexInput->addAttributes($attrArray); 333 | $rexInput->setAttribute('id', $id); 334 | $rexInput->setAttribute('name', $name); 335 | $rexInput->setValue($inputValue); 336 | $field = $rexInput->getHtml(); 337 | 338 | $checked = $active ? ' checked="checked"' : ''; 339 | $field .= ''; 340 | 341 | $e = []; 342 | $e['label'] = $label; 343 | $e['field'] = $field; 344 | $e['note'] = $notice; 345 | $fragment = new rex_fragment(); 346 | $fragment->setVar('elements', [$e], false); 347 | $field = $fragment->parse('core/form/form.php'); 348 | 349 | break; 350 | case 'textarea': 351 | $tag_attr = ' class="form-control"'; 352 | 353 | $rexInput = rex_global_settings_input::factory($typeLabel); 354 | $rexInput->addAttributes($attrArray); 355 | $rexInput->setAttribute('id', $id); 356 | $rexInput->setAttribute('name', $name); 357 | if ($activeItem) { 358 | $rexInput->setValue($activeItem->getValue($name)); 359 | } else { 360 | $rexInput->setValue($defaultValue); 361 | } 362 | $field = $rexInput->getHtml(); 363 | 364 | $e = []; 365 | $e['label'] = $label; 366 | $e['field'] = $field; 367 | $e['note'] = $notice; 368 | $fragment = new rex_fragment(); 369 | $fragment->setVar('elements', [$e], false); 370 | $field = $fragment->parse('core/form/form.php'); 371 | 372 | break; 373 | case 'legend': 374 | $tag = ''; 375 | $tag_attr = ''; 376 | $labelIt = false; 377 | 378 | // tabindex entfernen, macht bei einer legend wenig sinn 379 | $attr = preg_replace('@tabindex="[^"]*"@', '', $attr); 380 | 381 | $field = '' . $label . ''; 382 | 383 | /** 384 | * add notice to legend. 385 | */ 386 | if ($notice) { 387 | $field .= '

    ' . $notice . '

    '; 388 | } 389 | 390 | break; 391 | case 'tab': 392 | $tag = ''; 393 | $tag_attr = ''; 394 | $labelIt = false; 395 | $fieldWithinTab = true; 396 | $hideByTabPerm = false; 397 | 398 | if (isset($attrArray['perm'])) { 399 | if (!rex::getUser()->hasPerm($attrArray['perm'])) { 400 | $hideByTabPerm = true; 401 | break; 402 | } 403 | } 404 | 405 | // tabindex entfernen, macht bei einer legend wenig sinn 406 | $attr = preg_replace('@tabindex="[^"]*"@', '', $attr); 407 | 408 | // $field = ''; 409 | 410 | if (0 == count($tabs)) { 411 | $field = '
    '; 412 | } else { 413 | $field = '
    '; 414 | } 415 | 416 | /** 417 | * add notice to tabs. 418 | */ 419 | if ($notice) { 420 | $field .= '

    ' . $notice . '

    '; 421 | } 422 | 423 | $tabs[] = ['name' => $label, 'id' => $id]; 424 | 425 | break; 426 | case 'REX_MEDIA_WIDGET': 427 | $tag = 'div'; 428 | $tag_attr = ' class="rex-form-widget"'; 429 | 430 | $paramArray = rex_string::split($params); 431 | 432 | $rexInput = rex_global_settings_input::factory('mediabutton'); 433 | $rexInput->addAttributes($attrArray); 434 | $rexInput->setButtonId($media_id); 435 | $rexInput->setAttribute('name', $name); 436 | $rexInput->setValue($dbvalues[0]); 437 | 438 | if (isset($paramArray['category'])) { 439 | $rexInput->setCategoryId($paramArray['category']); 440 | } 441 | if (isset($paramArray['types'])) { 442 | $rexInput->setTypes($paramArray['types']); 443 | } 444 | if (isset($paramArray['preview'])) { 445 | $rexInput->setPreview($paramArray['preview']); 446 | } 447 | 448 | $id = $rexInput->getAttribute('id'); 449 | $field = $rexInput->getHtml(); 450 | 451 | $e = []; 452 | $e['label'] = $label; 453 | $e['field'] = $field; 454 | $e['note'] = $notice; 455 | $fragment = new rex_fragment(); 456 | $fragment->setVar('elements', [$e], false); 457 | $field = $fragment->parse('core/form/form.php'); 458 | 459 | ++$media_id; 460 | break; 461 | case 'REX_MEDIALIST_WIDGET': 462 | $tag = 'div'; 463 | $tag_attr = ' class="rex-form-widget"'; 464 | 465 | $paramArray = rex_string::split($params); 466 | 467 | $name .= '[]'; 468 | $rexInput = rex_global_settings_input::factory('medialistbutton'); 469 | $rexInput->addAttributes($attrArray); 470 | $rexInput->setButtonId($mlist_id); 471 | $rexInput->setAttribute('name', $name); 472 | $rexInput->setValue($dbvalues[0]); 473 | 474 | if (isset($paramArray['category'])) { 475 | $rexInput->setCategoryId($paramArray['category']); 476 | } 477 | if (isset($paramArray['types'])) { 478 | $rexInput->setTypes($paramArray['types']); 479 | } 480 | if (isset($paramArray['preview'])) { 481 | $rexInput->setPreview($paramArray['preview']); 482 | } 483 | 484 | $id = $rexInput->getAttribute('id'); 485 | $field = $rexInput->getHtml(); 486 | 487 | $e = []; 488 | $e['label'] = $label; 489 | $e['field'] = $field; 490 | $e['note'] = $notice; 491 | $fragment = new rex_fragment(); 492 | $fragment->setVar('elements', [$e], false); 493 | $field = $fragment->parse('core/form/form.php'); 494 | 495 | ++$mlist_id; 496 | break; 497 | case 'REX_LINK_WIDGET': 498 | $tag = 'div'; 499 | $tag_attr = ' class="rex-form-widget"'; 500 | 501 | $paramArray = rex_string::split($params); 502 | $category = ''; 503 | if (isset($paramArray['category'])) { 504 | $category = $paramArray['category']; 505 | } elseif ($activeItem) { 506 | $category = $activeItem->getValue('category_id'); 507 | } 508 | 509 | $rexInput = rex_global_settings_input::factory('linkbutton'); 510 | $rexInput->addAttributes($attrArray); 511 | $rexInput->setButtonId($link_id); 512 | $rexInput->setCategoryId($category); 513 | $rexInput->setAttribute('name', $name); 514 | $rexInput->setValue($dbvalues[0]); 515 | $id = $rexInput->getAttribute('id'); 516 | $field = $rexInput->getHtml(); 517 | 518 | $e = []; 519 | $e['label'] = $label; 520 | $e['field'] = $field; 521 | $e['note'] = $notice; 522 | $fragment = new rex_fragment(); 523 | $fragment->setVar('elements', [$e], false); 524 | $field = $fragment->parse('core/form/form.php'); 525 | 526 | ++$link_id; 527 | break; 528 | case 'REX_LINKLIST_WIDGET': 529 | $tag = 'div'; 530 | $tag_attr = ' class="rex-form-widget"'; 531 | 532 | $paramArray = rex_string::split($params); 533 | $category = ''; 534 | if (isset($paramArray['category'])) { 535 | $category = $paramArray['category']; 536 | } elseif ($activeItem) { 537 | $category = $activeItem->getValue('category_id'); 538 | } 539 | 540 | $name .= '[]'; 541 | $rexInput = rex_global_settings_input::factory('linklistbutton'); 542 | $rexInput->addAttributes($attrArray); 543 | $rexInput->setButtonId($llist_id); 544 | $rexInput->setCategoryId($category); 545 | $rexInput->setAttribute('name', $name); 546 | $rexInput->setValue(implode(',', $dbvalues)); 547 | $id = $rexInput->getAttribute('id'); 548 | $field = $rexInput->getHtml(); 549 | 550 | $e = []; 551 | $e['label'] = $label; 552 | $e['field'] = $field; 553 | $e['note'] = $notice; 554 | $fragment = new rex_fragment(); 555 | $fragment->setVar('elements', [$e], false); 556 | $field = $fragment->parse('core/form/form.php'); 557 | 558 | ++$llist_id; 559 | break; 560 | default: 561 | // ----- EXTENSION POINT 562 | [$field, $tag, $tag_attr, $id, $label, $labelIt] = 563 | rex_extension::registerPoint(new rex_extension_point( 564 | 'GLOBAL_SETTINGS_CUSTOM_FIELD', 565 | [ 566 | $field, 567 | $tag, 568 | $tag_attr, 569 | $id, 570 | $label, 571 | $labelIt, 572 | 'values' => $dbvalues, 573 | 'rawvalues' => $dbvalues, 574 | 'type' => $typeLabel, 575 | 'sql' => $sqlFields, 576 | ], 577 | )); 578 | } 579 | 580 | $s .= $this->renderFormItem($field, $tag, $tag_attr, $id, $label, $labelIt, $typeLabel); 581 | } 582 | 583 | $out = $s; 584 | 585 | if (count($tabs) > 0) { 586 | $s .= '
    '; // close tab panel 587 | 588 | $tabControl = '
    '; 589 | $tabControl = ''; 602 | $tabControl .= '
    '; 603 | $tabControl .= $s; 604 | $tabControl .= '
    '; 605 | 606 | // add js for persistant tabs (tabs keep position after reload ) 607 | $tabControl .= " 608 | "; 620 | 621 | $out = $tabControl; 622 | } 623 | 624 | return str_replace('">' . rex_global_settings::FIELD_PREFIX, '">', $out); 625 | } 626 | 627 | /** 628 | * Übernimmt die gePOSTeten werte in ein rex_sql-Objekt. 629 | * 630 | * @param array $params 631 | * @param rex_sql $sqlSave rex_sql-objekt, in das die aktuellen Werte gespeichert werden sollen 632 | * @param rex_sql $sqlFields rex_sql-objekt, dass die zu verarbeitenden Felder enthält 633 | */ 634 | public static function fetchRequestValues(&$params, &$sqlSave, $sqlFields) 635 | { 636 | if ('post' != rex_request_method()) { 637 | return; 638 | } 639 | 640 | $isRestrictedTab = false; 641 | 642 | for ($i = 0; $i < $sqlFields->getRows(); $i++, $sqlFields->next()) { 643 | $fieldName = $sqlFields->getValue('name'); 644 | $fieldType = $sqlFields->getValue('type_id'); 645 | $fieldAttributes = $sqlFields->getValue('attributes'); 646 | 647 | // dont save restricted fields 648 | $attrArray = rex_string::split($fieldAttributes); 649 | 650 | /** 651 | * check if the field is a tab 652 | * check permissions. 653 | */ 654 | if (REX_GLOBAL_SETTINGS_FIELD_TAB === $fieldType) { 655 | if (isset($attrArray['perm'])) { 656 | if (!rex::getUser()->hasPerm($attrArray['perm'])) { 657 | $isRestrictedTab = true; 658 | } 659 | } else { 660 | $isRestrictedTab = false; 661 | } 662 | } 663 | 664 | if (isset($attrArray['perm'])) { 665 | if (!rex::getUser()->hasPerm($attrArray['perm'])) { 666 | continue; 667 | } 668 | unset($attrArray['perm']); 669 | } 670 | 671 | if ($isRestrictedTab) { 672 | continue; 673 | } 674 | 675 | // Wert in SQL zum speichern 676 | $saveValue = self::getSaveValue($fieldName, $fieldType, $fieldAttributes); 677 | $sqlSave->setValue($fieldName, $saveValue); 678 | 679 | // Werte im aktuellen Objekt speichern, dass zur Anzeige verwendet wird 680 | if (isset($params['activeItem'])) { 681 | $params['activeItem']->setValue($fieldName, $saveValue); 682 | } 683 | } 684 | } 685 | 686 | /** 687 | * Retrieves the posted value for the given field and converts it into a saveable format. 688 | * 689 | * @param string $fieldName The name of the field 690 | * @param int $fieldType One of the REX_GLOBAL_SETTINGS_FIELD_* constants 691 | * @param string $fieldAttributes The attributes of the field 692 | * 693 | * @return string 694 | */ 695 | public static function getSaveValue($fieldName, $fieldType, $fieldAttributes) 696 | { 697 | if ('post' != rex_request_method()) { 698 | return null; 699 | } 700 | 701 | $postValue = rex_post($fieldName, 'array'); 702 | 703 | // handle date types with timestamps 704 | if (isset($postValue['year']) && isset($postValue['month']) && isset($postValue['day']) && isset($postValue['hour']) && isset($postValue['minute'])) { 705 | if (isset($postValue['active'])) { 706 | $saveValue = mktime((int) $postValue['hour'], (int) $postValue['minute'], 0, (int) $postValue['month'], (int) $postValue['day'], (int) $postValue['year']); 707 | } else { 708 | $saveValue = 0; 709 | } 710 | } // handle date types without timestamps 711 | elseif (isset($postValue['year']) && isset($postValue['month']) && isset($postValue['day'])) { 712 | if (isset($postValue['active'])) { 713 | $saveValue = mktime(0, 0, 0, (int) $postValue['month'], (int) $postValue['day'], (int) $postValue['year']); 714 | } else { 715 | $saveValue = 0; 716 | } 717 | } // handle time types 718 | elseif (isset($postValue['hour']) && isset($postValue['minute'])) { 719 | if (isset($postValue['active'])) { 720 | $saveValue = mktime((int) $postValue['hour'], (int) $postValue['minute'], 0, 0, 0, 0); 721 | } else { 722 | $saveValue = 0; 723 | } 724 | } else { 725 | if (count($postValue) > 1) { 726 | // Mehrwertige Felder 727 | $saveValue = '|' . implode('|', $postValue) . '|'; 728 | } else { 729 | $postValue = $postValue[0] ?? ''; 730 | if (REX_GLOBAL_SETTINGS_FIELD_SELECT == $fieldType && str_contains($fieldAttributes, 'multiple') 731 | || REX_GLOBAL_SETTINGS_FIELD_CHECKBOX == $fieldType 732 | ) { 733 | // Mehrwertiges Feld, aber nur ein Wert ausgewählt 734 | $saveValue = '|' . $postValue . '|'; 735 | } else { 736 | // Einwertige Felder 737 | $saveValue = $postValue; 738 | } 739 | } 740 | } 741 | 742 | return $saveValue; 743 | } 744 | 745 | /** 746 | * Ermittelt die global_settings felder mit dem Prefix $prefix limitiert auf die Kategorien $restrictions. 747 | * 748 | * @param string $prefix Feldprefix 749 | * @param string $filterCondition SQL Where-Bedingung zum einschränken der Metafelder 750 | * 751 | * @return rex_sql global_settings felder 752 | */ 753 | protected static function getSqlFields($prefix, $filterCondition = '') 754 | { 755 | // replace LIKE wildcards 756 | $prefix = str_replace(['_', '%'], ['\_', '\%'], $prefix); 757 | 758 | $qry = 'SELECT 759 | * 760 | FROM 761 | ' . rex::getTablePrefix() . 'global_settings_field p, 762 | ' . rex::getTablePrefix() . 'global_settings_type t 763 | WHERE 764 | `p`.`type_id` = `t`.`id` AND 765 | `p`.`name` LIKE "' . $prefix . '%" 766 | ' . $filterCondition . ' 767 | ORDER BY 768 | priority'; 769 | 770 | $sqlFields = rex_sql::factory(); 771 | // $sqlFields->setDebug(); 772 | $sqlFields->setQuery($qry); 773 | 774 | return $sqlFields; 775 | } 776 | 777 | /** 778 | * Erweitert das Meta-Formular um die neuen Meta-Felder. 779 | * 780 | * @param string $prefix Feldprefix 781 | * @param array $params EP Params 782 | * 783 | * @return string 784 | */ 785 | public function renderFormAndSave($prefix, array $params) 786 | { 787 | // Beim ADD gibts noch kein activeItem 788 | $activeItem = null; 789 | if (isset($params['activeItem'])) { 790 | $activeItem = $params['activeItem']; 791 | } 792 | 793 | $filterCondition = $this->buildFilterCondition($params); 794 | $sqlFields = $this->getSqlFields($prefix, $filterCondition); 795 | $params = $this->handleSave($params, $sqlFields); 796 | 797 | // trigger callback of sql fields 798 | if ('post' == rex_request_method()) { 799 | $this->fireCallbacks($sqlFields); 800 | } 801 | 802 | return self::renderMetaFields($sqlFields, $params); 803 | } 804 | 805 | protected function fireCallbacks(rex_sql $sqlFields) 806 | { 807 | foreach ($sqlFields as $row) { 808 | if ('' != $row->getValue('callback')) { 809 | // use a small sandbox, so the callback cannot affect our local variables 810 | $sandboxFunc = function ($field) { 811 | // TODO add var to ref the actual table (rex_article,...) 812 | $fieldName = $field->getValue('name'); 813 | $fieldType = $field->getValue('type_id'); 814 | $fieldAttributes = $field->getValue('attributes'); 815 | $fieldValue = self::getSaveValue($fieldName, $fieldType, $fieldAttributes); 816 | 817 | require rex_stream::factory('global_settings/' . $field->getValue('id') . '/callback', $field->getValue('callback')); 818 | }; 819 | // pass a clone to the custom handler, so the callback will not change our var 820 | $sandboxFunc(clone $row); 821 | } 822 | } 823 | } 824 | 825 | /** 826 | * Build a SQL Filter String which fits for the current context params. 827 | * 828 | * @param array $params EP Params 829 | */ 830 | abstract protected function buildFilterCondition(array $params); 831 | 832 | /** 833 | * Renders a field of the metaform. The rendered html will be returned. 834 | * 835 | * @param string $field The html-source of the field itself 836 | * @param string $tag The html-tag for the elements container, e.g. "p" 837 | * @param string $tag_attr Attributes for the elements container, e.g. " class='rex-widget'" 838 | * @param string $id The id of the field, used for current label or field-specific javascripts 839 | * @param string $label The textlabel of the field 840 | * @param bool $labelIt True when an additional label needs to be rendered, otherweise False 841 | * @param string $inputType The input type, e.g. "checkbox", "radio",.. 842 | * 843 | * @return string The rendered html 844 | */ 845 | abstract protected function renderFormItem($field, $tag, $tag_attr, $id, $label, $labelIt, $inputType); 846 | 847 | /** 848 | * Retrieves the activeItem from the current context. 849 | * Afterwards the actual metaForm extension will be rendered. 850 | * 851 | * @return string 852 | */ 853 | abstract public function extendForm(rex_extension_point $ep); 854 | 855 | /** 856 | * Retrieves the POST values from the metaform, fill it into a rex_sql object and save it to a database table. 857 | */ 858 | abstract protected function handleSave(array $params, rex_sql $sqlFields); 859 | } 860 | --------------------------------------------------------------------------------