mirror of
https://code.castopod.org/adaures/castopod
synced 2025-04-19 04:51:17 +00:00
refactor(plugins): create Field objects per field type in settings forms + handle rendering in class
update manifest.schema.json to have defaultValue type differ based on field type
This commit is contained in:
parent
d3a98db6d0
commit
34be5bccab
@ -19,6 +19,8 @@ class DropDeprecatedPodcastsFields extends BaseMigration
|
||||
#[Override]
|
||||
public function up(): void
|
||||
{
|
||||
// TODO: migrate data
|
||||
|
||||
$this->forge->dropColumn(
|
||||
'podcasts',
|
||||
'episode_description_footer_markdown,episode_description_footer_html,is_owner_email_removed_from_feed,medium,payment_pointer,verify_txt,custom_rss,partner_id,partner_link_url,partner_image_url'
|
||||
|
@ -55,7 +55,7 @@ use RuntimeException;
|
||||
* @property string $language_code
|
||||
* @property int $category_id
|
||||
* @property Category|null $category
|
||||
* @property string $other_categories_ids
|
||||
* @property int[] $other_categories_ids
|
||||
* @property Category[] $other_categories
|
||||
* @property string|null $parental_advisory
|
||||
* @property string|null $publisher
|
||||
@ -111,7 +111,10 @@ class Podcast extends Entity
|
||||
*/
|
||||
protected ?array $other_categories = null;
|
||||
|
||||
protected string $other_categories_ids = '';
|
||||
/**
|
||||
* @var int[]
|
||||
*/
|
||||
protected array $other_categories_ids = [];
|
||||
|
||||
/**
|
||||
* @var Episode[]|null
|
||||
@ -523,10 +526,13 @@ class Podcast extends Entity
|
||||
return $this->other_categories;
|
||||
}
|
||||
|
||||
public function getOtherCategoriesIds(): string
|
||||
/**
|
||||
* @return int[]
|
||||
*/
|
||||
public function getOtherCategoriesIds(): array
|
||||
{
|
||||
if ($this->other_categories_ids === '') {
|
||||
$this->other_categories_ids = implode(',', array_column($this->getOtherCategories(), 'id'));
|
||||
if ($this->other_categories_ids === []) {
|
||||
$this->other_categories_ids = array_column($this->getOtherCategories(), 'id');
|
||||
}
|
||||
|
||||
return $this->other_categories_ids;
|
||||
|
@ -21,4 +21,9 @@ class OtherRules
|
||||
{
|
||||
return is_array($str);
|
||||
}
|
||||
|
||||
public function is_string_or_list(mixed $str = null): bool
|
||||
{
|
||||
return is_string($str) || is_array($str);
|
||||
}
|
||||
}
|
||||
|
@ -10,12 +10,9 @@ class CodeEditor extends FormComponent
|
||||
{
|
||||
protected array $props = ['content', 'lang'];
|
||||
|
||||
/**
|
||||
* @var array<string, string>
|
||||
*/
|
||||
protected array $attributes = [
|
||||
'rows' => '6',
|
||||
'class' => 'textarea',
|
||||
'class' => 'bg-elevated w-full rounded-lg border-3 border-contrast focus:border-contrast focus-within:ring-accent transition',
|
||||
];
|
||||
|
||||
protected string $lang = '';
|
||||
|
@ -26,9 +26,15 @@ abstract class FormComponent extends Component
|
||||
|
||||
protected string $name;
|
||||
|
||||
protected string $value = '';
|
||||
/**
|
||||
* @var string|string[]|null
|
||||
*/
|
||||
protected string|array|null $value = null;
|
||||
|
||||
protected string $defaultValue = '';
|
||||
/**
|
||||
* @var string|string[]
|
||||
*/
|
||||
protected string|array $defaultValue = '';
|
||||
|
||||
protected bool $isRequired = false;
|
||||
|
||||
@ -61,8 +67,16 @@ abstract class FormComponent extends Component
|
||||
}
|
||||
}
|
||||
|
||||
protected function getValue(): string
|
||||
protected function getValue(): string|array
|
||||
{
|
||||
return old($this->name, $this->value === '' ? $this->defaultValue : $this->value);
|
||||
$valueCast = $this->casts['value'] ?? '';
|
||||
if ($valueCast === 'array') {
|
||||
return old($this->name, in_array($this->value, [[], null], true) ? $this->defaultValue : $this->value) ?? [];
|
||||
}
|
||||
|
||||
return old(
|
||||
$this->name,
|
||||
in_array($this->value, ['', null], true) ? $this->defaultValue : $this->value
|
||||
) ?? '';
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,9 @@ class SelectMulti extends FormComponent
|
||||
protected array $props = ['options'];
|
||||
|
||||
protected array $casts = [
|
||||
'options' => 'array',
|
||||
'value' => 'array',
|
||||
'defaultValue' => 'array',
|
||||
'options' => 'array',
|
||||
];
|
||||
|
||||
/**
|
||||
@ -36,9 +38,9 @@ class SelectMulti extends FormComponent
|
||||
$this->attributes = [...$defaultAttributes, ...$this->attributes];
|
||||
|
||||
$options = '';
|
||||
$selected = explode(',', $this->getValue()) ?? [];
|
||||
$selected = $this->getValue();
|
||||
foreach ($this->options as $option) {
|
||||
$options .= '<option ' . (array_key_exists('description', $option) ? 'data-label-description="' . $option['description'] . '" ' : '') . 'value="' . $option['value'] . '"' . (in_array((string) $option['value'], $selected, true) ? ' selected' : '') . '>' . $option['label'] . '</option>';
|
||||
$options .= '<option ' . (array_key_exists('description', $option) ? 'data-label-description="' . $option['description'] . '" ' : '') . 'value="' . $option['value'] . '"' . (in_array($option['value'], $selected, true) ? ' selected' : '') . '>' . $option['label'] . '</option>';
|
||||
}
|
||||
|
||||
$this->attributes['name'] = $this->name . '[]';
|
||||
|
@ -8,6 +8,10 @@ use Override;
|
||||
|
||||
class Textarea extends FormComponent
|
||||
{
|
||||
protected array $attributes = [
|
||||
'rows' => '6',
|
||||
];
|
||||
|
||||
public function setValue(string $value): void
|
||||
{
|
||||
$this->value = htmlspecialchars_decode($value);
|
||||
|
@ -9,7 +9,7 @@
|
||||
"php": "^8.3",
|
||||
"adaures/ipcat-php": "^v1.0.0",
|
||||
"adaures/podcast-persons-taxonomy": "^v1.0.1",
|
||||
"aws/aws-sdk-php": "^3.334.7",
|
||||
"aws/aws-sdk-php": "^3.336.2",
|
||||
"chrisjean/php-ico": "^1.0.4",
|
||||
"cocur/slugify": "^v4.6.0",
|
||||
"codeigniter4/framework": "v4.5.5",
|
||||
@ -35,8 +35,8 @@
|
||||
"codeigniter/phpstan-codeigniter": "v1.5.1",
|
||||
"mikey179/vfsstream": "^v1.6.12",
|
||||
"phpstan/extension-installer": "^1.4.3",
|
||||
"phpstan/phpstan": "^2.0.3",
|
||||
"phpunit/phpunit": "^11.5.1",
|
||||
"phpstan/phpstan": "^2.0.4",
|
||||
"phpunit/phpunit": "^11.5.2",
|
||||
"rector/rector": "^2.0.3",
|
||||
"symplify/coding-standard": "^12.2.3",
|
||||
"symplify/easy-coding-standard": "^12.5.4"
|
||||
|
64
composer.lock
generated
64
composer.lock
generated
@ -4,7 +4,7 @@
|
||||
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
|
||||
"This file is @generated automatically"
|
||||
],
|
||||
"content-hash": "8bdf144f383531caa188f1c211ec092a",
|
||||
"content-hash": "f95311413c714e2dcef9364da4348b30",
|
||||
"packages": [
|
||||
{
|
||||
"name": "adaures/ipcat-php",
|
||||
@ -189,16 +189,16 @@
|
||||
},
|
||||
{
|
||||
"name": "aws/aws-sdk-php",
|
||||
"version": "3.334.7",
|
||||
"version": "3.336.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/aws/aws-sdk-php.git",
|
||||
"reference": "8e0104e95a1edba209e077e6c4212b8cca04686f"
|
||||
"reference": "954bfdfc048840ca34afe2a2e1cbcff6681989c4"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/8e0104e95a1edba209e077e6c4212b8cca04686f",
|
||||
"reference": "8e0104e95a1edba209e077e6c4212b8cca04686f",
|
||||
"url": "https://api.github.com/repos/aws/aws-sdk-php/zipball/954bfdfc048840ca34afe2a2e1cbcff6681989c4",
|
||||
"reference": "954bfdfc048840ca34afe2a2e1cbcff6681989c4",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -275,9 +275,9 @@
|
||||
"support": {
|
||||
"forum": "https://forums.aws.amazon.com/forum.jspa?forumID=80",
|
||||
"issues": "https://github.com/aws/aws-sdk-php/issues",
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.334.7"
|
||||
"source": "https://github.com/aws/aws-sdk-php/tree/3.336.2"
|
||||
},
|
||||
"time": "2024-12-16T19:09:36+00:00"
|
||||
"time": "2024-12-20T19:05:10+00:00"
|
||||
},
|
||||
{
|
||||
"name": "brick/math",
|
||||
@ -1354,16 +1354,16 @@
|
||||
},
|
||||
{
|
||||
"name": "laminas/laminas-escaper",
|
||||
"version": "2.14.0",
|
||||
"version": "2.15.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/laminas/laminas-escaper.git",
|
||||
"reference": "0f7cb975f4443cf22f33408925c231225cfba8cb"
|
||||
"reference": "c612b0488ae486284c39885efca494c180f16351"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/0f7cb975f4443cf22f33408925c231225cfba8cb",
|
||||
"reference": "0f7cb975f4443cf22f33408925c231225cfba8cb",
|
||||
"url": "https://api.github.com/repos/laminas/laminas-escaper/zipball/c612b0488ae486284c39885efca494c180f16351",
|
||||
"reference": "c612b0488ae486284c39885efca494c180f16351",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -1375,12 +1375,12 @@
|
||||
"zendframework/zend-escaper": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"infection/infection": "^0.27.9",
|
||||
"laminas/laminas-coding-standard": "~3.0.0",
|
||||
"infection/infection": "^0.27.11",
|
||||
"laminas/laminas-coding-standard": "~3.0.1",
|
||||
"maglnet/composer-require-checker": "^3.8.0",
|
||||
"phpunit/phpunit": "^9.6.16",
|
||||
"phpunit/phpunit": "^9.6.22",
|
||||
"psalm/plugin-phpunit": "^0.19.0",
|
||||
"vimeo/psalm": "^5.21.1"
|
||||
"vimeo/psalm": "^5.26.1"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
@ -1407,7 +1407,7 @@
|
||||
"type": "community_bridge"
|
||||
}
|
||||
],
|
||||
"time": "2024-10-24T10:12:53+00:00"
|
||||
"time": "2024-12-17T19:39:54+00:00"
|
||||
},
|
||||
{
|
||||
"name": "league/commonmark",
|
||||
@ -3637,11 +3637,11 @@
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-main": "3.x-dev"
|
||||
},
|
||||
"phpstan": {
|
||||
"includes": ["extension.neon"]
|
||||
},
|
||||
"branch-alias": {
|
||||
"dev-main": "3.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
@ -4316,16 +4316,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpstan/phpstan",
|
||||
"version": "2.0.3",
|
||||
"version": "2.0.4",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/phpstan/phpstan.git",
|
||||
"reference": "46b4d3529b12178112d9008337beda0cc2a1a6b4"
|
||||
"reference": "50d276fc3bf1430ec315f2f109bbde2769821524"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/46b4d3529b12178112d9008337beda0cc2a1a6b4",
|
||||
"reference": "46b4d3529b12178112d9008337beda0cc2a1a6b4",
|
||||
"url": "https://api.github.com/repos/phpstan/phpstan/zipball/50d276fc3bf1430ec315f2f109bbde2769821524",
|
||||
"reference": "50d276fc3bf1430ec315f2f109bbde2769821524",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4360,7 +4360,7 @@
|
||||
"type": "github"
|
||||
}
|
||||
],
|
||||
"time": "2024-11-28T22:19:37+00:00"
|
||||
"time": "2024-12-17T17:14:01+00:00"
|
||||
},
|
||||
{
|
||||
"name": "phpunit/php-code-coverage",
|
||||
@ -4654,16 +4654,16 @@
|
||||
},
|
||||
{
|
||||
"name": "phpunit/phpunit",
|
||||
"version": "11.5.1",
|
||||
"version": "11.5.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/sebastianbergmann/phpunit.git",
|
||||
"reference": "2b94d4f2450b9869fa64a46fd8a6a41997aef56a"
|
||||
"reference": "153d0531b9f7e883c5053160cad6dd5ac28140b3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/2b94d4f2450b9869fa64a46fd8a6a41997aef56a",
|
||||
"reference": "2b94d4f2450b9869fa64a46fd8a6a41997aef56a",
|
||||
"url": "https://api.github.com/repos/sebastianbergmann/phpunit/zipball/153d0531b9f7e883c5053160cad6dd5ac28140b3",
|
||||
"reference": "153d0531b9f7e883c5053160cad6dd5ac28140b3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
@ -4677,13 +4677,13 @@
|
||||
"phar-io/manifest": "^2.0.4",
|
||||
"phar-io/version": "^3.2.1",
|
||||
"php": ">=8.2",
|
||||
"phpunit/php-code-coverage": "^11.0.7",
|
||||
"phpunit/php-code-coverage": "^11.0.8",
|
||||
"phpunit/php-file-iterator": "^5.1.0",
|
||||
"phpunit/php-invoker": "^5.0.1",
|
||||
"phpunit/php-text-template": "^4.0.1",
|
||||
"phpunit/php-timer": "^7.0.1",
|
||||
"sebastian/cli-parser": "^3.0.2",
|
||||
"sebastian/code-unit": "^3.0.1",
|
||||
"sebastian/code-unit": "^3.0.2",
|
||||
"sebastian/comparator": "^6.2.1",
|
||||
"sebastian/diff": "^6.0.2",
|
||||
"sebastian/environment": "^7.2.0",
|
||||
@ -4723,7 +4723,7 @@
|
||||
"support": {
|
||||
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
|
||||
"security": "https://github.com/sebastianbergmann/phpunit/security/policy",
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.1"
|
||||
"source": "https://github.com/sebastianbergmann/phpunit/tree/11.5.2"
|
||||
},
|
||||
"funding": [
|
||||
{
|
||||
@ -4739,7 +4739,7 @@
|
||||
"type": "tidelift"
|
||||
}
|
||||
],
|
||||
"time": "2024-12-11T10:52:48+00:00"
|
||||
"time": "2024-12-21T05:51:08+00:00"
|
||||
},
|
||||
{
|
||||
"name": "psr/container",
|
||||
|
@ -11,18 +11,19 @@
|
||||
"prepare": "astro telemetry disable"
|
||||
},
|
||||
"dependencies": {
|
||||
"@astrojs/check": "^0.9.3",
|
||||
"@astrojs/starlight": "^0.28.2",
|
||||
"@astrojs/starlight-tailwind": "^2.0.3",
|
||||
"@astrojs/tailwind": "^5.1.1",
|
||||
"@astrojs/check": "^0.9.4",
|
||||
"@astrojs/starlight": "^0.30.3",
|
||||
"@astrojs/starlight-tailwind": "^3.0.0",
|
||||
"@astrojs/tailwind": "^5.1.3",
|
||||
"@fontsource/inter": "^5.1.0",
|
||||
"@fontsource/rubik": "^5.1.0",
|
||||
"astro": "^4.15.9",
|
||||
"astro": "^5.1.0",
|
||||
"autoprefixer": "^10.4.20",
|
||||
"cssnano": "^7.0.6",
|
||||
"postcss-preset-env": "^10.0.5",
|
||||
"postcss-preset-env": "^10.1.2",
|
||||
"sharp": "^0.33.5",
|
||||
"tailwindcss": "^3.4.13",
|
||||
"typescript": "^5.6.2"
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "^5.7.2",
|
||||
"zod": "3.24.1"
|
||||
}
|
||||
}
|
||||
|
4622
docs/pnpm-lock.yaml
generated
4622
docs/pnpm-lock.yaml
generated
File diff suppressed because it is too large
Load Diff
8
docs/src/content.config.ts
Normal file
8
docs/src/content.config.ts
Normal file
@ -0,0 +1,8 @@
|
||||
import { defineCollection } from "astro:content";
|
||||
import { docsLoader, i18nLoader } from "@astrojs/starlight/loaders";
|
||||
import { docsSchema, i18nSchema } from "@astrojs/starlight/schema";
|
||||
|
||||
export const collections = {
|
||||
docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
|
||||
i18n: defineCollection({ loader: i18nLoader(), schema: i18nSchema() }),
|
||||
};
|
@ -1,7 +0,0 @@
|
||||
import { defineCollection } from "astro:content";
|
||||
import { docsSchema, i18nSchema } from "@astrojs/starlight/schema";
|
||||
|
||||
export const collections = {
|
||||
docs: defineCollection({ schema: docsSchema() }),
|
||||
i18n: defineCollection({ type: "data", schema: i18nSchema() }),
|
||||
};
|
@ -101,17 +101,18 @@ each property being a field key and the value being a `Field` object.
|
||||
|
||||
A field is a form element:
|
||||
|
||||
| Property | Type | Note |
|
||||
| ------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
|
||||
| `type` | `checkbox` \| `datetime` \| `email` \| `group` \| `html` \| `markdown` \| `number` \| `radio-group` \| `rss` \| `select-multiple` \| `select` \| `text` \| `textarea` \| `toggler` \| `url` | Default is `text` |
|
||||
| `label` (required) | `string` | Can be translated (see i18n) |
|
||||
| `hint` | `string` | Can be translated (see i18n) |
|
||||
| `helper` | `string` | Can be translated (see i18n) |
|
||||
| `defaultValue` | `string` | You can specify multiple comma separated values for `select-multiple` |
|
||||
| `optional` | `boolean` | Default is `false` |
|
||||
| `options` | `Options` | Required for `radio-group`, `select-multiple`, and `select` types. |
|
||||
| `multiple` | `boolean` | Default is `false` |
|
||||
| `fields` | `Array<string, Field>` | Required for `group` type |
|
||||
| Property | Type | Note |
|
||||
| ------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------- |
|
||||
| `type` | `checkbox`, `datetime`, `email`, `group`, `html`, `markdown`, `number`, `radio-group`, `rss`, `select-multiple`, `select`, `text`, `textarea`, `toggler`, `url` | Default is `text` |
|
||||
| `label` (required) | `string` | Can be translated (see i18n) |
|
||||
| `hint` | `string` | Can be translated (see i18n) |
|
||||
| `helper` | `string` | Can be translated (see i18n) |
|
||||
| `defaultValue` | `string` | You can specify multiple comma separated values for `select-multiple` |
|
||||
| `validationRules` | `string` \| `array` | See [available validation rules](#available-validation-rules) |
|
||||
| `optional` | `boolean` | Default is `false` |
|
||||
| `options` | `Options` | Required for `radio-group`, `select-multiple`, and `select` types. |
|
||||
| `multiple` | `boolean` | Default is `false` |
|
||||
| `fields` | `Array<string, Field>` | Required for `group` type |
|
||||
|
||||
#### Options object
|
||||
|
||||
@ -133,3 +134,35 @@ plugin is installed.
|
||||
|
||||
Repository where the plugin's code lives. Helpful for people who want to
|
||||
contribute.
|
||||
|
||||
#### Available validation rules
|
||||
|
||||
The following rules are a subset of
|
||||
[CodeIgniter4's validation rules](https://codeigniter.com/user_guide/libraries/validation.html#available-rules).
|
||||
|
||||
| Rule | Parameter | Description | Example |
|
||||
| --------------------- | --------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- |
|
||||
| alpha | No | Fails if field has anything other than alphabetic characters in ASCII. | |
|
||||
| alpha_dash | No | Fails if field contains anything other than alphanumeric characters, underscores or dashes in ASCII. | |
|
||||
| alpha_numeric | No | Fails if field contains anything other than alphanumeric characters in ASCII. | |
|
||||
| alpha_numeric_punct | No | Fails if field contains anything other than alphanumeric, space, or this limited set of punctuation characters: `~` (tilde), `!` (exclamation), `#` (number), `$` (dollar), `%` (percent), `&` (ampersand), `*` (asterisk), `-` (dash), `_` (underscore), `+` (plus), `=` (equals), `\|` (vertical bar),`:`(colon),`.` (period). | |
|
||||
| alpha_numeric_space | No | Fails if field contains anything other than alphanumeric or space characters in ASCII. | |
|
||||
| alpha_space | No | Fails if field contains anything other than alphabetic characters or spaces in ASCII. | |
|
||||
| decimal | No | Fails if field contains anything other than a decimal number. Also accepts a `+` or `-` sign for the number. | |
|
||||
| differs | Yes | Fails if field does not differ from the one in the parameter. | `differs[field_name]` |
|
||||
| exact_length | Yes | Fails if field length is not exactly the parameter value. One or more comma-separated values are possible. | `exact_length[5]` or `exact_length[5,8,12]` |
|
||||
| greater_than | Yes | Fails if field is less than or equal to the parameter value or not numeric. | `greater_than[8]` |
|
||||
| greater_than_equal_to | Yes | Fails if field is less than the parameter value, or not numeric. | `greater_than_equal_to[5]` |
|
||||
| hex | No | Fails if field contains anything other than hexadecimal characters. | |
|
||||
| in_list | Yes | Fails if field is not within a predetermined list. | `in_list[red,blue,green]` |
|
||||
| integer | No | Fails if field contains anything other than an integer. | |
|
||||
| is_natural | No | Fails if field contains anything other than a natural number: `0`, `1`, `2`, `3`, etc. | |
|
||||
| is_natural_no_zero | No | Fails if field contains anything other than a natural number, except zero: `1`, `2`, `3`, etc. | |
|
||||
| less_than | Yes | Fails if field is greater than or equal to the parameter value or not numeric. | `less_than[8]` |
|
||||
| less_than_equal_to | Yes | Fails if field is greater than the parameter value or not numeric. | `less_than_equal_to[8]` |
|
||||
| max_length | Yes | Fails if field is longer than the parameter value. | `max_length[8]` |
|
||||
| min_length | Yes | Fails if field is shorter than the parameter value. | `min_length[3]` |
|
||||
| not_in_list | Yes | Fails if field is within a predetermined list. | `not_in_list[red,blue,green]` |
|
||||
| regex_match | Yes | Fails if field does not match the regular expression. | `regex_match[/regex/]` |
|
||||
| valid_base64 | No | Fails if field contains anything other than valid Base64 characters. | |
|
||||
| valid_date | Yes | Fails if field does not contain a valid date. Any string that `strtotime()` accepts is valid if you don't specify an optional parameter that matches a date format. | `valid_date[d/m/Y]` |
|
||||
|
@ -71,12 +71,12 @@ class CreatePlugin extends BaseCommand
|
||||
$pluginName = CLI::prompt(
|
||||
'Plugin name (<vendor>/<name>)',
|
||||
'acme/hello-world',
|
||||
Manifest::VALIDATION_RULES['name']
|
||||
Manifest::$validation_rules['name']
|
||||
);
|
||||
CLI::newLine();
|
||||
$description = CLI::prompt('Description', '', Manifest::VALIDATION_RULES['description']);
|
||||
$description = CLI::prompt('Description', '', Manifest::$validation_rules['description']);
|
||||
CLI::newLine();
|
||||
$license = CLI::prompt('License', 'UNLICENSED', Manifest::VALIDATION_RULES['license']);
|
||||
$license = CLI::prompt('License', 'UNLICENSED', Manifest::$validation_rules['license']);
|
||||
CLI::newLine();
|
||||
$hooks = CLI::promptByMultipleKeys('Which hooks do you want to implement?', Plugins::HOOKS);
|
||||
|
||||
|
@ -18,6 +18,7 @@ use Modules\Plugins\Core\Markdown;
|
||||
use Modules\Plugins\Core\Plugins;
|
||||
use Modules\Plugins\Core\RSS;
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
use Modules\Plugins\Manifest\Fields\Group;
|
||||
|
||||
class PluginController extends BaseController
|
||||
{
|
||||
@ -154,7 +155,6 @@ class PluginController extends BaseController
|
||||
string $podcastId = null,
|
||||
string $episodeId = null
|
||||
): RedirectResponse {
|
||||
|
||||
$plugin = $this->plugins->getPlugin($vendor, $package);
|
||||
|
||||
if (! $plugin instanceof BasePlugin) {
|
||||
@ -182,29 +182,35 @@ class PluginController extends BaseController
|
||||
}
|
||||
|
||||
if ($field->multiple) {
|
||||
if ($field->type === 'group') {
|
||||
if ($field instanceof Group) {
|
||||
foreach ($field->fields as $subField) {
|
||||
$typeRules = $this->plugins::FIELDS_VALIDATIONS[$subField->type];
|
||||
if (! in_array('permit_empty', $typeRules, true)) {
|
||||
$typeRules[] = $subField->optional ? 'permit_empty' : 'required';
|
||||
}
|
||||
|
||||
$rules[sprintf('%s.*.%s', $field->key, $subField->key)] = $typeRules;
|
||||
$rules[sprintf('%s.*.%s', $field->key, $subField->key)] = [
|
||||
...$typeRules,
|
||||
...$subField->validationRules,
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$rules[$field->key . '.*'] = $typeRules;
|
||||
$rules[$field->key . '.*'] = [...$typeRules, ...$field->validationRules];
|
||||
}
|
||||
} elseif ($field->type === 'group') {
|
||||
} elseif ($field instanceof Group) {
|
||||
foreach ($field->fields as $subField) {
|
||||
$typeRules = $this->plugins::FIELDS_VALIDATIONS[$subField->type];
|
||||
if (! in_array('permit_empty', $typeRules, true)) {
|
||||
$typeRules[] = $subField->optional ? 'permit_empty' : 'required';
|
||||
}
|
||||
|
||||
$rules[sprintf('%s.%s', $field->key, $subField->key)] = $typeRules;
|
||||
$rules[sprintf('%s.%s', $field->key, $subField->key)] = [
|
||||
...$typeRules,
|
||||
...$subField->validationRules,
|
||||
];
|
||||
}
|
||||
} else {
|
||||
$rules[$field->key] = $typeRules;
|
||||
$rules[$field->key] = [...$typeRules, ...$field->validationRules];
|
||||
}
|
||||
}
|
||||
|
||||
@ -288,7 +294,7 @@ class PluginController extends BaseController
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($field->type === 'group') {
|
||||
if ($field instanceof Group) {
|
||||
foreach ($val as $subKey => $subVal) {
|
||||
/** @var Field|false $subField */
|
||||
$subField = array_column($field->fields, null, 'key')[$subKey] ?? false;
|
||||
@ -305,7 +311,7 @@ class PluginController extends BaseController
|
||||
$value[$key] = $this->castValue($val, $field->type);
|
||||
}
|
||||
}
|
||||
} elseif ($field->type === 'group') {
|
||||
} elseif ($field instanceof Group) {
|
||||
foreach ($fieldValue as $subKey => $subVal) {
|
||||
/** @var Field|false $subField */
|
||||
$subField = array_column($field->fields, null, 'key')[$subKey] ?? false;
|
||||
@ -340,10 +346,9 @@ class PluginController extends BaseController
|
||||
$value,
|
||||
$this->request->getPost('client_timezone')
|
||||
)->setTimezone(app_timezone()),
|
||||
'markdown' => new Markdown($value),
|
||||
'rss' => new RSS($value),
|
||||
'comma-separated-string' => implode(',', $value),
|
||||
default => $value,
|
||||
'markdown' => new Markdown($value),
|
||||
'rss' => new RSS($value),
|
||||
default => $value,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -52,14 +52,13 @@ class Plugins
|
||||
];
|
||||
|
||||
public const FIELDS_CASTS = [
|
||||
'checkbox' => 'bool',
|
||||
'datetime' => 'datetime',
|
||||
'markdown' => 'markdown',
|
||||
'number' => 'int',
|
||||
'rss' => 'rss',
|
||||
'toggler' => 'bool',
|
||||
'url' => 'uri',
|
||||
'select-multiple' => 'comma-separated-string',
|
||||
'checkbox' => 'bool',
|
||||
'datetime' => 'datetime',
|
||||
'markdown' => 'markdown',
|
||||
'number' => 'int',
|
||||
'rss' => 'rss',
|
||||
'toggler' => 'bool',
|
||||
'url' => 'uri',
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -4,7 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest;
|
||||
|
||||
use Override;
|
||||
use RuntimeException;
|
||||
|
||||
/**
|
||||
* @property 'checkbox'|'datetime'|'email'|'group'|'html'|'markdown'|'number'|'radio-group'|'rss'|'select-multiple'|'select'|'text'|'textarea'|'toggler'|'url' $type
|
||||
@ -14,28 +14,20 @@ use Override;
|
||||
* @property string $helper
|
||||
* @property string $defaultValue
|
||||
* @property bool $optional
|
||||
* @property Option[] $options
|
||||
* @property bool $multiple
|
||||
* @property Field[] $fields
|
||||
* @property string[] $validationRules
|
||||
*/
|
||||
class Field extends ManifestObject
|
||||
class Field extends ManifestObject implements FieldInterface
|
||||
{
|
||||
protected const VALIDATION_RULES = [
|
||||
'type' => 'permit_empty|in_list[checkbox,datetime,email,group,html,markdown,number,radio-group,rss,select-multiple,select,text,textarea,toggler,url]',
|
||||
'key' => 'required|alpha_dash',
|
||||
'label' => 'required|string',
|
||||
'hint' => 'permit_empty|string',
|
||||
'helper' => 'permit_empty|string',
|
||||
'defaultValue' => 'permit_empty|string',
|
||||
'optional' => 'permit_empty|is_boolean',
|
||||
'options' => 'permit_empty|is_list',
|
||||
'multiple' => 'permit_empty|is_boolean',
|
||||
'fields' => 'permit_empty|is_list',
|
||||
];
|
||||
|
||||
protected const CASTS = [
|
||||
'options' => [Option::class],
|
||||
'fields' => [self::class],
|
||||
public static array $validation_rules = [
|
||||
'type' => 'permit_empty|in_list[checkbox,datetime,email,group,html,markdown,number,radio-group,rss,select-multiple,select,text,textarea,toggler,url]',
|
||||
'key' => 'required|alpha_dash',
|
||||
'label' => 'required|string',
|
||||
'hint' => 'permit_empty|string',
|
||||
'helper' => 'permit_empty|string',
|
||||
'validationRules' => 'permit_empty|is_string_or_list',
|
||||
'optional' => 'permit_empty|is_boolean',
|
||||
'multiple' => 'permit_empty|is_boolean',
|
||||
];
|
||||
|
||||
protected string $type = 'text';
|
||||
@ -48,65 +40,83 @@ class Field extends ManifestObject
|
||||
|
||||
protected string $helper = '';
|
||||
|
||||
protected string $defaultValue = '';
|
||||
/**
|
||||
* @var string[]
|
||||
*/
|
||||
protected array $validationRules = [];
|
||||
|
||||
protected bool $optional = false;
|
||||
|
||||
protected bool $multiple = false;
|
||||
|
||||
/**
|
||||
* @var Option[]
|
||||
*/
|
||||
protected array $options = [];
|
||||
|
||||
#[Override]
|
||||
public function loadData(array $data): void
|
||||
public function getLabel(): string
|
||||
{
|
||||
if (array_key_exists('options', $data)) {
|
||||
$newOptions = [];
|
||||
foreach ($data['options'] as $key => $option) {
|
||||
$option['value'] = $key;
|
||||
$newOptions[] = $option;
|
||||
}
|
||||
return $this->getTranslated('label');
|
||||
}
|
||||
|
||||
$data['options'] = $newOptions;
|
||||
}
|
||||
public function getHint(): string
|
||||
{
|
||||
return $this->getTranslated('hint');
|
||||
}
|
||||
|
||||
if (array_key_exists('fields', $data)) {
|
||||
$newFields = [];
|
||||
foreach ($data['fields'] as $key => $field) {
|
||||
$field['key'] = $key;
|
||||
$newFields[] = $field;
|
||||
}
|
||||
|
||||
$data['fields'] = $newFields;
|
||||
}
|
||||
|
||||
parent::loadData($data);
|
||||
public function getHelper(): string
|
||||
{
|
||||
return $this->getTranslated('helper');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{label:string,value:string,description:string}[]
|
||||
* @param string|list<string> $values
|
||||
*/
|
||||
public function getOptionsArray(string $pluginKey): array
|
||||
public function setValidationRules(string|array $values): void
|
||||
{
|
||||
$i18nKey = sprintf('%s.settings.%s.%s.options', $pluginKey, $this->type, $this->key);
|
||||
|
||||
$optionsArray = [];
|
||||
foreach ($this->options as $option) {
|
||||
$optionsArray[] = [
|
||||
'value' => $option->value,
|
||||
'label' => $option->getTranslated($i18nKey, 'label'),
|
||||
'description' => $option->getTranslated($i18nKey, 'description'),
|
||||
];
|
||||
$validationRules = [];
|
||||
if (is_string($values)) {
|
||||
$validationRules = explode('|', $values);
|
||||
}
|
||||
|
||||
return $optionsArray;
|
||||
$allowedRules = [
|
||||
'alpha',
|
||||
'alpha_dash',
|
||||
'alpha_numeric',
|
||||
'alpha_numeric_punct',
|
||||
'alpha_numeric_space',
|
||||
'alpha_space',
|
||||
'decimal',
|
||||
'differs',
|
||||
'exact_length',
|
||||
'greater_than',
|
||||
'greater_than_equal_to',
|
||||
'hex',
|
||||
'in_list',
|
||||
'integer',
|
||||
'is_natural',
|
||||
'is_natural_no_zero',
|
||||
'less_than',
|
||||
'less_than_equal_to',
|
||||
'max_length',
|
||||
'min_length',
|
||||
'not_in_list',
|
||||
'regex_match',
|
||||
'valid_base64',
|
||||
'valid_date',
|
||||
];
|
||||
foreach ($validationRules as $rule) {
|
||||
foreach ($allowedRules as $allowedRule) {
|
||||
if (str_starts_with($rule, $allowedRule)) {
|
||||
$this->validationRules[] = $rule;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getTranslated(string $pluginKey, string $property): string
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$key = sprintf('Plugin.%s.settings.%s.%s.%s', $pluginKey, $this->type, $this->key, $property);
|
||||
throw new RuntimeException('Render function not defined in parent Field class');
|
||||
}
|
||||
|
||||
private function getTranslated(string $property): string
|
||||
{
|
||||
$key = sprintf('Plugin.%s.settings.%s.%s.%s', $this->pluginKey, $this->type, $this->key, $property);
|
||||
|
||||
/** @var string $i18nField */
|
||||
$i18nField = lang($key);
|
||||
|
10
modules/Plugins/Manifest/FieldInterface.php
Normal file
10
modules/Plugins/Manifest/FieldInterface.php
Normal file
@ -0,0 +1,10 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest;
|
||||
|
||||
interface FieldInterface
|
||||
{
|
||||
public function render(string $name, mixed $value, string $class = ''): string;
|
||||
}
|
34
modules/Plugins/Manifest/Fields/Checkbox.php
Normal file
34
modules/Plugins/Manifest/Fields/Checkbox.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
|
||||
/**
|
||||
* @property bool $defaultValue
|
||||
*/
|
||||
class Checkbox extends Field
|
||||
{
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|is_boolean',
|
||||
];
|
||||
|
||||
protected bool $defaultValue = false;
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$value = $value ? 'yes' : '';
|
||||
return <<<HTML
|
||||
<x-Forms.Checkbox
|
||||
class="{$class}"
|
||||
name="{$name}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
value="{$value}"
|
||||
defaultValue="{$this->defaultValue}"
|
||||
>{$this->label}</x-Forms.Checkbox>
|
||||
HTML;
|
||||
}
|
||||
}
|
37
modules/Plugins/Manifest/Fields/Datetime.php
Normal file
37
modules/Plugins/Manifest/Fields/Datetime.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
|
||||
/**
|
||||
* @property string $defaultValue
|
||||
*/
|
||||
class Datetime extends Field
|
||||
{
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|valid_date',
|
||||
];
|
||||
|
||||
protected string $defaultValue = '';
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$isRequired = $this->optional ? 'false' : 'true';
|
||||
return <<<HTML
|
||||
<x-Forms.Field
|
||||
as="DatetimePicker"
|
||||
class="{$class}"
|
||||
name="{$name}"
|
||||
label="{$this->label}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
isRequired="{$isRequired}"
|
||||
value="{$value}"
|
||||
defaultValue="{$this->defaultValue}"
|
||||
/>
|
||||
HTML;
|
||||
}
|
||||
}
|
38
modules/Plugins/Manifest/Fields/Email.php
Normal file
38
modules/Plugins/Manifest/Fields/Email.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
|
||||
/**
|
||||
* @property string $defaultValue
|
||||
*/
|
||||
class Email extends Field
|
||||
{
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|valid_email',
|
||||
];
|
||||
|
||||
protected string $defaultValue = '';
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$isRequired = $this->optional ? 'false' : 'true';
|
||||
return <<<HTML
|
||||
<x-Forms.Field
|
||||
as="Input"
|
||||
class="{$class}"
|
||||
type="email"
|
||||
name="{$name}"
|
||||
label="{$this->label}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
isRequired="{$isRequired}"
|
||||
value="{$value}"
|
||||
defaultValue="{$this->defaultValue}"
|
||||
/>
|
||||
HTML;
|
||||
}
|
||||
}
|
36
modules/Plugins/Manifest/Fields/Group.php
Normal file
36
modules/Plugins/Manifest/Fields/Group.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
use Modules\Plugins\Manifest\WithFieldsTrait;
|
||||
use Override;
|
||||
use RuntimeException;
|
||||
|
||||
class Group extends Field
|
||||
{
|
||||
use WithFieldsTrait;
|
||||
|
||||
public function __construct(string $pluginKey)
|
||||
{
|
||||
$this->injectRules();
|
||||
|
||||
parent::__construct($pluginKey);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function loadData(array $data): void
|
||||
{
|
||||
$data = $this->transformData($data);
|
||||
|
||||
parent::loadData($data);
|
||||
}
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
// TODO: render group, depending on multiple
|
||||
throw new RuntimeException('Render function not defined in Group Field class');
|
||||
}
|
||||
}
|
39
modules/Plugins/Manifest/Fields/Html.php
Normal file
39
modules/Plugins/Manifest/Fields/Html.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
|
||||
/**
|
||||
* @property string $defaultValue
|
||||
*/
|
||||
class Html extends Field
|
||||
{
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|string',
|
||||
];
|
||||
|
||||
protected string $defaultValue = '';
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$isRequired = $this->optional ? 'false' : 'true';
|
||||
$value = htmlspecialchars($value ?? '');
|
||||
return <<<HTML
|
||||
<x-Forms.Field
|
||||
as="CodeEditor"
|
||||
lang="html"
|
||||
class="{$class}"
|
||||
name="{$name}"
|
||||
label="{$this->label}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
isRequired="{$isRequired}"
|
||||
value="{$value}"
|
||||
defaultValue="{$this->defaultValue}"
|
||||
/>
|
||||
HTML;
|
||||
}
|
||||
}
|
37
modules/Plugins/Manifest/Fields/Markdown.php
Normal file
37
modules/Plugins/Manifest/Fields/Markdown.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
|
||||
/**
|
||||
* @property string $defaultValue
|
||||
*/
|
||||
class Markdown extends Field
|
||||
{
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|string',
|
||||
];
|
||||
|
||||
protected string $defaultValue = '';
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$isRequired = $this->optional ? 'false' : 'true';
|
||||
return <<<HTML
|
||||
<x-Forms.Field
|
||||
as="MarkdownEditor"
|
||||
class="{$class}"
|
||||
name="{$name}"
|
||||
label="{$this->label}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
isRequired="{$isRequired}"
|
||||
value="{$value}"
|
||||
defaultValue="{$this->defaultValue}"
|
||||
/>
|
||||
HTML;
|
||||
}
|
||||
}
|
38
modules/Plugins/Manifest/Fields/Number.php
Normal file
38
modules/Plugins/Manifest/Fields/Number.php
Normal file
@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
|
||||
/**
|
||||
* @property int|null $defaultValue
|
||||
*/
|
||||
class Number extends Field
|
||||
{
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|numeric',
|
||||
];
|
||||
|
||||
protected ?int $defaultValue = null;
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$isRequired = $this->optional ? 'false' : 'true';
|
||||
return <<<HTML
|
||||
<x-Forms.Field
|
||||
as="Input"
|
||||
type="number"
|
||||
class="{$class}"
|
||||
name="{$name}"
|
||||
label="{$this->label}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
isRequired="{$isRequired}"
|
||||
value="{$value}"
|
||||
defaultValue="{$this->defaultValue}"
|
||||
/>
|
||||
HTML;
|
||||
}
|
||||
}
|
57
modules/Plugins/Manifest/Fields/RadioGroup.php
Normal file
57
modules/Plugins/Manifest/Fields/RadioGroup.php
Normal file
@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
use Modules\Plugins\Manifest\WithOptionsTrait;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* @property string $defaultValue
|
||||
*/
|
||||
class RadioGroup extends Field
|
||||
{
|
||||
use WithOptionsTrait;
|
||||
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|string',
|
||||
];
|
||||
|
||||
protected string $defaultValue = '';
|
||||
|
||||
public function __construct(string $pluginKey)
|
||||
{
|
||||
$this->injectRules();
|
||||
|
||||
parent::__construct($pluginKey);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function loadData(array $data): void
|
||||
{
|
||||
$data = $this->transformData($data);
|
||||
|
||||
parent::loadData($data);
|
||||
}
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$isRequired = $this->optional ? 'false' : 'true';
|
||||
$options = esc(json_encode($this->getOptionsArray()));
|
||||
return <<<HTML
|
||||
<x-Forms.RadioGroup
|
||||
class="{$class}"
|
||||
name="{$name}"
|
||||
label="{$this->label}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
options="{$options}"
|
||||
isRequired="{$isRequired}"
|
||||
value="{$value}"
|
||||
defaultValue="{$this->defaultValue}"
|
||||
/>
|
||||
HTML;
|
||||
}
|
||||
}
|
40
modules/Plugins/Manifest/Fields/Rss.php
Normal file
40
modules/Plugins/Manifest/Fields/Rss.php
Normal file
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
|
||||
/**
|
||||
* @property string $defaultValue
|
||||
*/
|
||||
class Rss extends Field
|
||||
{
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|string',
|
||||
];
|
||||
|
||||
protected string $defaultValue = '';
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$isRequired = $this->optional ? 'false' : 'true';
|
||||
$value = htmlspecialchars((string) $value);
|
||||
$defaultValue = esc($this->defaultValue);
|
||||
return <<<HTML
|
||||
<x-Forms.Field
|
||||
as="CodeEditor"
|
||||
lang="xml"
|
||||
class="{$class}"
|
||||
name="{$name}"
|
||||
label="{$this->label}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
isRequired="{$isRequired}"
|
||||
value="{$value}"
|
||||
defaultValue="{$defaultValue}"
|
||||
/>
|
||||
HTML;
|
||||
}
|
||||
}
|
64
modules/Plugins/Manifest/Fields/Select.php
Normal file
64
modules/Plugins/Manifest/Fields/Select.php
Normal file
@ -0,0 +1,64 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
use Modules\Plugins\Manifest\Option;
|
||||
use Modules\Plugins\Manifest\WithOptionsTrait;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* @property string $defaultValue
|
||||
*/
|
||||
class Select extends Field
|
||||
{
|
||||
use WithOptionsTrait;
|
||||
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|string',
|
||||
'options' => 'is_list',
|
||||
];
|
||||
|
||||
protected array $casts = [
|
||||
'options' => [Option::class],
|
||||
];
|
||||
|
||||
protected string $defaultValue = '';
|
||||
|
||||
public function __construct(string $pluginKey)
|
||||
{
|
||||
$this->injectRules();
|
||||
|
||||
parent::__construct($pluginKey);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function loadData(array $data): void
|
||||
{
|
||||
$data = $this->transformData($data);
|
||||
|
||||
parent::loadData($data);
|
||||
}
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$isRequired = $this->optional ? 'false' : 'true';
|
||||
$options = esc(json_encode($this->getOptionsArray()));
|
||||
return <<<HTML
|
||||
<x-Forms.Field
|
||||
as="Select"
|
||||
class="{$class}"
|
||||
name="{$name}"
|
||||
label="{$this->label}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
options="{$options}"
|
||||
isRequired="{$isRequired}"
|
||||
value="{$value}"
|
||||
defaultValue="{$this->defaultValue}"
|
||||
/>
|
||||
HTML;
|
||||
}
|
||||
}
|
63
modules/Plugins/Manifest/Fields/SelectMultiple.php
Normal file
63
modules/Plugins/Manifest/Fields/SelectMultiple.php
Normal file
@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
use Modules\Plugins\Manifest\WithOptionsTrait;
|
||||
use Override;
|
||||
|
||||
/**
|
||||
* @property list<string> $defaultValue
|
||||
*/
|
||||
class SelectMultiple extends Field
|
||||
{
|
||||
use WithOptionsTrait;
|
||||
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|is_list',
|
||||
];
|
||||
|
||||
/**
|
||||
* @var list<string>
|
||||
*/
|
||||
protected array $defaultValue = [];
|
||||
|
||||
public function __construct(string $pluginKey)
|
||||
{
|
||||
$this->injectRules();
|
||||
|
||||
parent::__construct($pluginKey);
|
||||
}
|
||||
|
||||
#[Override]
|
||||
public function loadData(array $data): void
|
||||
{
|
||||
$data = $this->transformData($data);
|
||||
|
||||
parent::loadData($data);
|
||||
}
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$isRequired = $this->optional ? 'false' : 'true';
|
||||
$options = esc(json_encode($this->getOptionsArray()));
|
||||
$value = esc(json_encode($value));
|
||||
$defaultValue = esc(json_encode($this->defaultValue));
|
||||
return <<<HTML
|
||||
<x-Forms.Field
|
||||
as="SelectMulti"
|
||||
class="{$class}"
|
||||
name="{$name}"
|
||||
label="{$this->label}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
options="{$options}"
|
||||
isRequired="{$isRequired}"
|
||||
value="{$value}"
|
||||
defaultValue="{$defaultValue}"
|
||||
/>
|
||||
HTML;
|
||||
}
|
||||
}
|
37
modules/Plugins/Manifest/Fields/Text.php
Normal file
37
modules/Plugins/Manifest/Fields/Text.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
|
||||
/**
|
||||
* @property string $defaultValue
|
||||
*/
|
||||
class Text extends Field
|
||||
{
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|string',
|
||||
];
|
||||
|
||||
protected string $defaultValue = '';
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$isRequired = $this->optional ? 'false' : 'true';
|
||||
return <<<HTML
|
||||
<x-Forms.Field
|
||||
as="Input"
|
||||
class="{$class}"
|
||||
name="{$name}"
|
||||
label="{$this->label}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
isRequired="{$isRequired}"
|
||||
value="{$value}"
|
||||
defaultValue="{$this->defaultValue}"
|
||||
/>
|
||||
HTML;
|
||||
}
|
||||
}
|
37
modules/Plugins/Manifest/Fields/Textarea.php
Normal file
37
modules/Plugins/Manifest/Fields/Textarea.php
Normal file
@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
|
||||
/**
|
||||
* @property string $defaultValue
|
||||
*/
|
||||
class Textarea extends Field
|
||||
{
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|string',
|
||||
];
|
||||
|
||||
protected string $defaultValue = '';
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$isRequired = $this->optional ? 'false' : 'true';
|
||||
return <<<HTML
|
||||
<x-Forms.Field
|
||||
as="Textarea"
|
||||
class="{$class}"
|
||||
name="{$name}"
|
||||
label="{$this->label}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
isRequired="{$isRequired}"
|
||||
value="{$value}"
|
||||
defaultValue="{$this->defaultValue}"
|
||||
/>
|
||||
HTML;
|
||||
}
|
||||
}
|
34
modules/Plugins/Manifest/Fields/Toggler.php
Normal file
34
modules/Plugins/Manifest/Fields/Toggler.php
Normal file
@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
|
||||
/**
|
||||
* @property bool $defaultValue
|
||||
*/
|
||||
class Toggler extends Field
|
||||
{
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|is_boolean',
|
||||
];
|
||||
|
||||
protected bool $defaultValue = false;
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$value = $value ? 'yes' : '';
|
||||
return <<<HTML
|
||||
<x-Forms.Toggler
|
||||
class="{$class}"
|
||||
name="{$name}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
value="{$value}"
|
||||
defaultValue="{$this->defaultValue}"
|
||||
>{$this->label}</x-Forms.Toggler>
|
||||
HTML;
|
||||
}
|
||||
}
|
39
modules/Plugins/Manifest/Fields/Url.php
Normal file
39
modules/Plugins/Manifest/Fields/Url.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest\Fields;
|
||||
|
||||
use Modules\Plugins\Manifest\Field;
|
||||
|
||||
/**
|
||||
* @property string $defaultValue
|
||||
*/
|
||||
class Url extends Field
|
||||
{
|
||||
public static array $validation_rules = [
|
||||
'defaultValue' => 'permit_empty|valid_url_strict',
|
||||
];
|
||||
|
||||
protected string $defaultValue = '';
|
||||
|
||||
public function render(string $name, mixed $value, string $class = ''): string
|
||||
{
|
||||
$isRequired = $this->optional ? 'false' : 'true';
|
||||
return <<<HTML
|
||||
<x-Forms.Field
|
||||
as="Input"
|
||||
class="{$class}"
|
||||
type="url"
|
||||
placeholder="https://…"
|
||||
name="{$name}"
|
||||
label="{$this->label}"
|
||||
hint="{$this->hint}"
|
||||
helper="{$this->helper}"
|
||||
isRequired="{$isRequired}"
|
||||
value="{$value}"
|
||||
defaultValue="{$this->defaultValue}"
|
||||
/>
|
||||
HTML;
|
||||
}
|
||||
}
|
@ -23,10 +23,7 @@ use CodeIgniter\HTTP\URI;
|
||||
*/
|
||||
class Manifest extends ManifestObject
|
||||
{
|
||||
/**
|
||||
* @var array<string,string>
|
||||
*/
|
||||
public const VALIDATION_RULES = [
|
||||
public static array $validation_rules = [
|
||||
'name' => 'required|max_length[128]|regex_match[/^[a-z0-9]([_.-]?[a-z0-9]+)*\/[a-z0-9]([_.-]?[a-z0-9]+)*$/]',
|
||||
'version' => 'required|regex_match[/^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$/]',
|
||||
'description' => 'permit_empty|max_length[256]',
|
||||
@ -41,7 +38,7 @@ class Manifest extends ManifestObject
|
||||
'repository' => 'permit_empty|is_list',
|
||||
];
|
||||
|
||||
protected const CASTS = [
|
||||
protected array $casts = [
|
||||
'authors' => [Person::class],
|
||||
'homepage' => URI::class,
|
||||
'settings' => Settings::class,
|
||||
|
@ -9,12 +9,15 @@ use Exception;
|
||||
|
||||
abstract class ManifestObject
|
||||
{
|
||||
protected const VALIDATION_RULES = [];
|
||||
/**
|
||||
* @var array<string,string>
|
||||
*/
|
||||
public static array $validation_rules = [];
|
||||
|
||||
/**
|
||||
* @var array<string,string|array{string}>
|
||||
*/
|
||||
protected const CASTS = [];
|
||||
protected array $casts = [];
|
||||
|
||||
/**
|
||||
* @var array<string,array<string,string>>
|
||||
@ -25,11 +28,28 @@ abstract class ManifestObject
|
||||
protected readonly string $pluginKey,
|
||||
) {
|
||||
self::$errors[$pluginKey] = [];
|
||||
|
||||
$class = static::class;
|
||||
$validation_rules = [];
|
||||
$casts = [];
|
||||
while ($class = get_parent_class($class)) {
|
||||
$validation_rules = [...$validation_rules, ...get_class_vars($class)['validation_rules']];
|
||||
$casts = [...$casts, ...get_class_vars($class)['casts']];
|
||||
}
|
||||
|
||||
$this::$validation_rules = [...$validation_rules, ...$this::$validation_rules];
|
||||
$this->casts = [...$casts, ...$this->casts];
|
||||
}
|
||||
|
||||
public function __get(string $name): mixed
|
||||
{
|
||||
if (property_exists($this, $name)) {
|
||||
// if a get method exists for this property, return that
|
||||
$method = 'get' . str_replace(' ', '', ucwords(str_replace(['-', '_'], ' ', $name)));
|
||||
if (method_exists($this, $method)) {
|
||||
return $this->{$method}();
|
||||
}
|
||||
|
||||
return $this->{$name};
|
||||
}
|
||||
|
||||
@ -73,7 +93,7 @@ abstract class ManifestObject
|
||||
/** @var Validation $validation */
|
||||
$validation = service('validation');
|
||||
|
||||
$validation->setRules($this::VALIDATION_RULES);
|
||||
$validation->setRules($this::$validation_rules);
|
||||
|
||||
if (! $validation->run($data)) {
|
||||
foreach ($validation->getErrors() as $key => $message) {
|
||||
@ -84,23 +104,30 @@ abstract class ManifestObject
|
||||
}
|
||||
|
||||
foreach ($validation->getValidated() as $key => $value) {
|
||||
if (array_key_exists($key, $this::CASTS)) {
|
||||
$cast = $this::CASTS[$key];
|
||||
$method = 'set' . str_replace(' ', '', ucwords(str_replace('_', ' ', $key)));
|
||||
if (is_callable([$this, $method])) {
|
||||
$this->{$method}($value);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (is_array($cast)) {
|
||||
if (is_array($value)) {
|
||||
foreach ($value as $valueKey => $valueElement) {
|
||||
if (is_subclass_of($cast[0], self::class)) {
|
||||
$value[$valueKey] = new $cast[0]($this->pluginKey);
|
||||
$value[$valueKey]->loadData($valueElement);
|
||||
} else {
|
||||
$value[$valueKey] = new $cast[0]($valueElement);
|
||||
}
|
||||
if (array_key_exists($key, $this->casts)) {
|
||||
$cast = $this->casts[$key];
|
||||
if (is_array($cast) && is_array($value)) {
|
||||
foreach ($value as $valueKey => $valueElement) {
|
||||
if (is_subclass_of($cast[0], self::class)) {
|
||||
$manifestClass = $cast[0] === Field::class ? $this->getFieldClass(
|
||||
$valueElement
|
||||
) : $cast[0];
|
||||
$value[$valueKey] = new $manifestClass($this->pluginKey);
|
||||
$value[$valueKey]->loadData($valueElement);
|
||||
} else {
|
||||
$value[$valueKey] = new $cast[0]($valueElement);
|
||||
}
|
||||
}
|
||||
} elseif (is_subclass_of($cast, self::class)) {
|
||||
$manifestClass = $cast === Field::class ? $this->getFieldClass($value) : $cast;
|
||||
$valueElement = $value;
|
||||
$value = new $cast($this->pluginKey);
|
||||
$value = new $manifestClass($this->pluginKey);
|
||||
$value->loadData($valueElement ?? []);
|
||||
} else {
|
||||
$value = new $cast($value ?? []);
|
||||
@ -123,4 +150,17 @@ abstract class ManifestObject
|
||||
{
|
||||
self::$errors[$this->pluginKey][$errorKey] = $errorMessage;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $data
|
||||
*/
|
||||
private function getFieldClass(array $data): string
|
||||
{
|
||||
$fieldType = $data['type'] ?? 'text';
|
||||
return rtrim(Field::class, "\Field") . '\\Fields\\' . str_replace(
|
||||
' ',
|
||||
'',
|
||||
ucwords(str_replace('-', ' ', $fieldType))
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -11,7 +11,7 @@ namespace Modules\Plugins\Manifest;
|
||||
*/
|
||||
class Option extends ManifestObject
|
||||
{
|
||||
protected const VALIDATION_RULES = [
|
||||
public static array $validation_rules = [
|
||||
'label' => 'required|string',
|
||||
'value' => 'required|alpha_numeric_punct',
|
||||
'description' => 'permit_empty|string',
|
||||
|
@ -15,18 +15,18 @@ use Override;
|
||||
*/
|
||||
class Person extends ManifestObject
|
||||
{
|
||||
protected const VALIDATION_RULES = [
|
||||
protected const AUTHOR_STRING_PATTERN = '/^(?<name>[^<>()]*)\s*(<(?<email>.*)>)?\s*(\((?<url>.*)\))?$/';
|
||||
|
||||
public static array $validation_rules = [
|
||||
'name' => 'required',
|
||||
'email' => 'permit_empty|valid_email',
|
||||
'url' => 'permit_empty|valid_url_strict',
|
||||
];
|
||||
|
||||
protected const AUTHOR_STRING_PATTERN = '/^(?<name>[^<>()]*)\s*(<(?<email>.*)>)?\s*(\((?<url>.*)\))?$/';
|
||||
|
||||
/**
|
||||
* @var array<string,array{string}|string>
|
||||
*/
|
||||
protected const CASTS = [
|
||||
protected array $casts = [
|
||||
'url' => URI::class,
|
||||
];
|
||||
|
||||
|
@ -13,7 +13,7 @@ use CodeIgniter\HTTP\URI;
|
||||
*/
|
||||
class Repository extends ManifestObject
|
||||
{
|
||||
protected const VALIDATION_RULES = [
|
||||
public static array $validation_rules = [
|
||||
'type' => 'permit_empty|in_list[git]',
|
||||
'url' => 'required|valid_url_strict',
|
||||
'directory' => 'permit_empty',
|
||||
@ -22,7 +22,7 @@ class Repository extends ManifestObject
|
||||
/**
|
||||
* @var array<string,array{string}|string>
|
||||
*/
|
||||
protected const CASTS = [
|
||||
protected array $casts = [
|
||||
'url' => URI::class,
|
||||
];
|
||||
|
||||
|
@ -13,7 +13,7 @@ use Override;
|
||||
*/
|
||||
class Settings extends ManifestObject
|
||||
{
|
||||
protected const VALIDATION_RULES = [
|
||||
public static array $validation_rules = [
|
||||
'general' => 'permit_empty|is_list',
|
||||
'podcast' => 'permit_empty|is_list',
|
||||
'episode' => 'permit_empty|is_list',
|
||||
@ -22,7 +22,7 @@ class Settings extends ManifestObject
|
||||
/**
|
||||
* @var array<string,array{string}|string>
|
||||
*/
|
||||
protected const CASTS = [
|
||||
protected array $casts = [
|
||||
'general' => [Field::class],
|
||||
'podcast' => [Field::class],
|
||||
'episode' => [Field::class],
|
||||
|
45
modules/Plugins/Manifest/WithFieldsTrait.php
Normal file
45
modules/Plugins/Manifest/WithFieldsTrait.php
Normal file
@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest;
|
||||
|
||||
/**
|
||||
* @property Field[] $fields
|
||||
*/
|
||||
trait WithFieldsTrait
|
||||
{
|
||||
/**
|
||||
* @var Field[]
|
||||
*/
|
||||
protected array $options = [];
|
||||
|
||||
public function injectRules(): void
|
||||
{
|
||||
$this::$validation_rules = [...$this::$validation_rules, ...[
|
||||
'fields' => 'is_list',
|
||||
]];
|
||||
$this->casts = [...$this->casts, ...[
|
||||
'fields' => [Field::class],
|
||||
]];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $data
|
||||
* @return array<mixed>
|
||||
*/
|
||||
public function transformData(array $data): array
|
||||
{
|
||||
if (array_key_exists('fields', $data)) {
|
||||
$newFields = [];
|
||||
foreach ($data['fields'] as $key => $field) {
|
||||
$field['key'] = $key;
|
||||
$newFields[] = $field;
|
||||
}
|
||||
|
||||
$data['fields'] = $newFields;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
}
|
69
modules/Plugins/Manifest/WithOptionsTrait.php
Normal file
69
modules/Plugins/Manifest/WithOptionsTrait.php
Normal file
@ -0,0 +1,69 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace Modules\Plugins\Manifest;
|
||||
|
||||
/**
|
||||
* @property Option[] $options
|
||||
*/
|
||||
trait WithOptionsTrait
|
||||
{
|
||||
/**
|
||||
* @var Option[]
|
||||
*/
|
||||
protected array $options = [];
|
||||
|
||||
public function injectRules(): void
|
||||
{
|
||||
if (isset($this::$validation_rules)) {
|
||||
$this::$validation_rules = [...$this::$validation_rules, ...[
|
||||
'options' => 'is_list',
|
||||
]];
|
||||
}
|
||||
|
||||
if (isset($this->casts)) {
|
||||
$this->casts = [...$this->casts, ...[
|
||||
'options' => [Option::class],
|
||||
]];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<mixed> $data
|
||||
* @return array<mixed>
|
||||
*/
|
||||
public function transformData(array $data): array
|
||||
{
|
||||
if (array_key_exists('options', $data)) {
|
||||
$newOptions = [];
|
||||
foreach ($data['options'] as $key => $option) {
|
||||
$option['value'] = $key;
|
||||
$newOptions[] = $option;
|
||||
}
|
||||
|
||||
$data['options'] = $newOptions;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array{label:string,value:string,description:string}[]
|
||||
*/
|
||||
public function getOptionsArray(): array
|
||||
{
|
||||
$i18nKey = sprintf('%s.settings.%s.%s.options', $this->pluginKey, $this->type, $this->key);
|
||||
|
||||
$optionsArray = [];
|
||||
foreach ($this->options as $option) {
|
||||
$optionsArray[] = [
|
||||
'value' => $option->value,
|
||||
'label' => $option->getTranslated($i18nKey, 'label'),
|
||||
'description' => $option->getTranslated($i18nKey, 'description'),
|
||||
];
|
||||
}
|
||||
|
||||
return $optionsArray;
|
||||
}
|
||||
}
|
@ -204,32 +204,30 @@
|
||||
"optional": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"defaultValue": {
|
||||
"type": "string"
|
||||
},
|
||||
"options": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[A-Za-z0-9]+[\\w\\-\\:\\.]*$": { "$ref": "#/$defs/option" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
|
||||
"validationRules": {
|
||||
"anyOf": [
|
||||
{
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
"multiple": {
|
||||
"type": "boolean"
|
||||
},
|
||||
"fields": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[A-Za-z]+[\\w\\-\\:\\.]*$": { "$ref": "#/$defs/field" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["label"],
|
||||
"additionalProperties": false,
|
||||
"unevaluatedProperties": false,
|
||||
"allOf": [
|
||||
{ "$ref": "#/$defs/field-multiple-implies-options-is-required" },
|
||||
{ "$ref": "#/$defs/field-group-type-implies-fields-is-required" }
|
||||
{ "$ref": "#/$defs/require-fields-for-group-type" },
|
||||
{ "$ref": "#/$defs/default-value-based-on-type" }
|
||||
]
|
||||
},
|
||||
"option": {
|
||||
@ -246,37 +244,160 @@
|
||||
"additionalProperties": false
|
||||
},
|
||||
"field-multiple-implies-options-is-required": {
|
||||
"anyOf": [
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {
|
||||
"enum": ["radio-group", "select", "select-multiple"]
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"options": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[A-Za-z0-9]+[\\w\\-\\:\\.]*$": { "$ref": "#/$defs/option" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["options"]
|
||||
}
|
||||
},
|
||||
"require-fields-for-group-type": {
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "group"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"fields": {
|
||||
"type": "object",
|
||||
"patternProperties": {
|
||||
"^[A-Za-z]+[\\w\\-\\:\\.]*$": { "$ref": "#/$defs/field" }
|
||||
},
|
||||
"additionalProperties": false
|
||||
}
|
||||
},
|
||||
"required": ["fields"]
|
||||
}
|
||||
},
|
||||
"default-value-based-on-type": {
|
||||
"allOf": [
|
||||
{
|
||||
"not": {
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {
|
||||
"anyOf": [
|
||||
{ "const": "radio-group" },
|
||||
{ "const": "select" },
|
||||
{ "const": "select-multiple" }
|
||||
"enum": [
|
||||
"html",
|
||||
"markdown",
|
||||
"radio-group",
|
||||
"rss",
|
||||
"select",
|
||||
"text",
|
||||
"textarea"
|
||||
]
|
||||
}
|
||||
},
|
||||
"required": ["type"]
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"defaultValue": { "type": "string" }
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "required": ["options"] }
|
||||
]
|
||||
},
|
||||
"field-group-type-implies-fields-is-required": {
|
||||
"anyOf": [
|
||||
{
|
||||
"not": {
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {
|
||||
"anyOf": [{ "const": "group" }]
|
||||
"enum": ["checkbox", "toggler"]
|
||||
}
|
||||
},
|
||||
"required": ["type"]
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"defaultValue": { "type": "boolean" }
|
||||
}
|
||||
}
|
||||
},
|
||||
{ "required": ["fields"] }
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "datetime"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"defaultValue": { "type": "string", "format": "date-time" }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "email"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"defaultValue": { "type": "string", "format": "email" }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "number"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"defaultValue": { "type": "number" }
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "select-multiple"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"defaultValue": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"type": "string"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"if": {
|
||||
"properties": {
|
||||
"type": {
|
||||
"const": "url"
|
||||
}
|
||||
}
|
||||
},
|
||||
"then": {
|
||||
"properties": {
|
||||
"defaultValue": { "type": "string", "format": "uri" }
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
10
package.json
10
package.json
@ -35,7 +35,7 @@
|
||||
"@codemirror/lang-xml": "^6.1.0",
|
||||
"@codemirror/language": "^6.10.7",
|
||||
"@codemirror/state": "^6.5.0",
|
||||
"@codemirror/view": "^6.35.3",
|
||||
"@codemirror/view": "^6.36.1",
|
||||
"@floating-ui/dom": "^1.6.12",
|
||||
"@github/clipboard-copy-element": "^1.3.0",
|
||||
"@github/hotkey": "^3.1.1",
|
||||
@ -51,7 +51,7 @@
|
||||
"leaflet.markercluster": "^1.5.3",
|
||||
"lit": "^3.2.1",
|
||||
"marked": "^15.0.4",
|
||||
"wavesurfer.js": "^7.8.11",
|
||||
"wavesurfer.js": "^7.8.12",
|
||||
"xml-formatter": "^3.6.3"
|
||||
},
|
||||
"devDependencies": {
|
||||
@ -76,7 +76,7 @@
|
||||
"eslint": "^9.17.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-prettier": "^5.2.1",
|
||||
"globals": "^15.13.0",
|
||||
"globals": "^15.14.0",
|
||||
"husky": "^9.1.7",
|
||||
"is-ci": "^4.1.0",
|
||||
"lint-staged": "^15.2.11",
|
||||
@ -91,10 +91,10 @@
|
||||
"stylelint": "^16.12.0",
|
||||
"stylelint-config-standard": "^36.0.1",
|
||||
"svgo": "^3.3.2",
|
||||
"tailwindcss": "^3.4.16",
|
||||
"tailwindcss": "^3.4.17",
|
||||
"typescript": "~5.7.2",
|
||||
"typescript-eslint": "^8.18.1",
|
||||
"vite": "^6.0.3",
|
||||
"vite": "^6.0.5",
|
||||
"vite-plugin-pwa": "^0.21.1",
|
||||
"workbox-build": "^7.3.0",
|
||||
"workbox-core": "^7.3.0",
|
||||
|
116
pnpm-lock.yaml
generated
116
pnpm-lock.yaml
generated
@ -29,8 +29,8 @@ importers:
|
||||
specifier: ^6.5.0
|
||||
version: 6.5.0
|
||||
"@codemirror/view":
|
||||
specifier: ^6.35.3
|
||||
version: 6.35.3
|
||||
specifier: ^6.36.1
|
||||
version: 6.36.1
|
||||
"@floating-ui/dom":
|
||||
specifier: ^1.6.12
|
||||
version: 1.6.12
|
||||
@ -77,8 +77,8 @@ importers:
|
||||
specifier: ^15.0.4
|
||||
version: 15.0.4
|
||||
wavesurfer.js:
|
||||
specifier: ^7.8.11
|
||||
version: 7.8.11
|
||||
specifier: ^7.8.12
|
||||
version: 7.8.12
|
||||
xml-formatter:
|
||||
specifier: ^3.6.3
|
||||
version: 3.6.3
|
||||
@ -112,10 +112,10 @@ importers:
|
||||
version: 13.2.3(semantic-release@24.2.0(typescript@5.7.2))
|
||||
"@tailwindcss/forms":
|
||||
specifier: ^0.5.9
|
||||
version: 0.5.9(tailwindcss@3.4.16)
|
||||
version: 0.5.9(tailwindcss@3.4.17)
|
||||
"@tailwindcss/typography":
|
||||
specifier: ^0.5.15
|
||||
version: 0.5.15(tailwindcss@3.4.16)
|
||||
version: 0.5.15(tailwindcss@3.4.17)
|
||||
"@types/eslint__js":
|
||||
specifier: ^8.42.3
|
||||
version: 8.42.3
|
||||
@ -147,8 +147,8 @@ importers:
|
||||
specifier: ^5.2.1
|
||||
version: 5.2.1(@types/eslint@9.6.1)(eslint-config-prettier@9.1.0(eslint@9.17.0(jiti@2.4.1)))(eslint@9.17.0(jiti@2.4.1))(prettier@3.4.2)
|
||||
globals:
|
||||
specifier: ^15.13.0
|
||||
version: 15.13.0
|
||||
specifier: ^15.14.0
|
||||
version: 15.14.0
|
||||
husky:
|
||||
specifier: ^9.1.7
|
||||
version: 9.1.7
|
||||
@ -192,8 +192,8 @@ importers:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2
|
||||
tailwindcss:
|
||||
specifier: ^3.4.16
|
||||
version: 3.4.16
|
||||
specifier: ^3.4.17
|
||||
version: 3.4.17
|
||||
typescript:
|
||||
specifier: ~5.7.2
|
||||
version: 5.7.2
|
||||
@ -201,11 +201,11 @@ importers:
|
||||
specifier: ^8.18.1
|
||||
version: 8.18.1(eslint@9.17.0(jiti@2.4.1))(typescript@5.7.2)
|
||||
vite:
|
||||
specifier: ^6.0.3
|
||||
version: 6.0.3(@types/node@22.9.0)(jiti@2.4.1)(terser@5.36.0)(yaml@2.6.1)
|
||||
specifier: ^6.0.5
|
||||
version: 6.0.5(@types/node@22.9.0)(jiti@2.4.1)(terser@5.36.0)(yaml@2.6.1)
|
||||
vite-plugin-pwa:
|
||||
specifier: ^0.21.1
|
||||
version: 0.21.1(vite@6.0.3(@types/node@22.9.0)(jiti@2.4.1)(terser@5.36.0)(yaml@2.6.1))(workbox-build@7.3.0)(workbox-window@7.3.0)
|
||||
version: 0.21.1(vite@6.0.5(@types/node@22.9.0)(jiti@2.4.1)(terser@5.36.0)(yaml@2.6.1))(workbox-build@7.3.0)(workbox-window@7.3.0)
|
||||
workbox-build:
|
||||
specifier: ^7.3.0
|
||||
version: 7.3.0
|
||||
@ -1083,10 +1083,10 @@ packages:
|
||||
integrity: sha512-MwBHVK60IiIHDcoMet78lxt6iw5gJOGSbNbOIVBHWVXIH4/Nq1+GQgLLGgI1KlnN86WDXsPudVaqYHKBIx7Eyw==,
|
||||
}
|
||||
|
||||
"@codemirror/view@6.35.3":
|
||||
"@codemirror/view@6.36.1":
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-ScY7L8+EGdPl4QtoBiOzE4FELp7JmNUsBvgBcCakXWM2uiv/K89VAzU3BMDscf0DsACLvTKePbd5+cFDTcei6g==,
|
||||
integrity: sha512-miD1nyT4m4uopZaDdO2uXU/LLHliKNYL9kB1C1wJHrunHLm/rpkb5QVSokqgw9hFqEZakrdlb/VGWX8aYZTslQ==,
|
||||
}
|
||||
|
||||
"@colors/colors@1.5.0":
|
||||
@ -4796,10 +4796,10 @@ packages:
|
||||
}
|
||||
engines: { node: ">=18" }
|
||||
|
||||
globals@15.13.0:
|
||||
globals@15.14.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-49TewVEz0UxZjr1WYYsWpPrhyC/B/pA8Bq0fUmet2n+eR7yn0IvNzNaoBwnK6mdkzcN+se7Ez9zUgULTz2QH4g==,
|
||||
integrity: sha512-OkToC372DtlQeje9/zHIo5CT8lRP/FUgEOKBEhU4e0abL7J7CD24fD9ohiLN5hagG/kWCYj4K5oaxxtj2Z0Dig==,
|
||||
}
|
||||
engines: { node: ">=18" }
|
||||
|
||||
@ -8267,10 +8267,10 @@ packages:
|
||||
}
|
||||
engines: { node: ">=10.0.0" }
|
||||
|
||||
tailwindcss@3.4.16:
|
||||
tailwindcss@3.4.17:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-TI4Cyx7gDiZ6r44ewaJmt0o6BrMCT5aK5e0rmJ/G9Xq3w7CX/5VXl/zIPEJZFUK5VEqwByyhqNPycPlvcK4ZNw==,
|
||||
integrity: sha512-w33E2aCvSDP0tW9RZuNXadXlkHXqFzSkQew/aIa2i/Sj8fThxwovwlXHSPXTbAHwEIhBFXAedUhP2tueAKP8Og==,
|
||||
}
|
||||
engines: { node: ">=14.0.0" }
|
||||
hasBin: true
|
||||
@ -8699,10 +8699,10 @@ packages:
|
||||
"@vite-pwa/assets-generator":
|
||||
optional: true
|
||||
|
||||
vite@6.0.3:
|
||||
vite@6.0.5:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-Cmuo5P0ENTN6HxLSo6IHsjCLn/81Vgrp81oaiFFMRa8gGDj5xEjIcEpf2ZymZtZR8oU0P2JX5WuUp/rlXcHkAw==,
|
||||
integrity: sha512-akD5IAH/ID5imgue2DYhzsEwCi0/4VKY31uhMLEYJwPP4TiUp8pL5PIK+Wo7H8qT8JY9i+pVfPydcFPYD1EL7g==,
|
||||
}
|
||||
engines: { node: ^18.0.0 || ^20.0.0 || >=22.0.0 }
|
||||
hasBin: true
|
||||
@ -8748,10 +8748,10 @@ packages:
|
||||
integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==,
|
||||
}
|
||||
|
||||
wavesurfer.js@7.8.11:
|
||||
wavesurfer.js@7.8.12:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-bZs7A0vtTVOhuPoDGOXVevAIm+KVYBGwddjL9AeOS7kp/oPcVH9hQWQyR2rBAAfN6s0BKI+EdPEalkNaOmkA6A==,
|
||||
integrity: sha512-Ovyv3ASEXXWmQVh3clpaZufkraRSg2Uv+28Z5zBHL4nB1HgTZ64lcFMUXX7yZlV5WAIN5ST9w3naaYmOdV2+iw==,
|
||||
}
|
||||
|
||||
wcwidth@1.0.1:
|
||||
@ -9015,14 +9015,6 @@ packages:
|
||||
integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==,
|
||||
}
|
||||
|
||||
yaml@2.6.0:
|
||||
resolution:
|
||||
{
|
||||
integrity: sha512-a6ae//JvKDEra2kdi1qzCyrJW/WZCgFi8ydDV+eXExl95t+5R+ijnqHJbz9tmMh8FUjx3iv2fCQ4dclAQlO2UQ==,
|
||||
}
|
||||
engines: { node: ">= 14" }
|
||||
hasBin: true
|
||||
|
||||
yaml@2.6.1:
|
||||
resolution:
|
||||
{
|
||||
@ -9785,23 +9777,23 @@ snapshots:
|
||||
"@babel/helper-string-parser": 7.25.9
|
||||
"@babel/helper-validator-identifier": 7.25.9
|
||||
|
||||
"@codemirror/autocomplete@6.18.2(@codemirror/language@6.10.7)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3)":
|
||||
"@codemirror/autocomplete@6.18.2(@codemirror/language@6.10.7)(@codemirror/state@6.5.0)(@codemirror/view@6.36.1)(@lezer/common@1.2.3)":
|
||||
dependencies:
|
||||
"@codemirror/language": 6.10.7
|
||||
"@codemirror/state": 6.5.0
|
||||
"@codemirror/view": 6.35.3
|
||||
"@codemirror/view": 6.36.1
|
||||
"@lezer/common": 1.2.3
|
||||
|
||||
"@codemirror/commands@6.7.1":
|
||||
dependencies:
|
||||
"@codemirror/language": 6.10.7
|
||||
"@codemirror/state": 6.5.0
|
||||
"@codemirror/view": 6.35.3
|
||||
"@codemirror/view": 6.36.1
|
||||
"@lezer/common": 1.2.3
|
||||
|
||||
"@codemirror/lang-css@6.3.1(@codemirror/view@6.35.3)":
|
||||
"@codemirror/lang-css@6.3.1(@codemirror/view@6.36.1)":
|
||||
dependencies:
|
||||
"@codemirror/autocomplete": 6.18.2(@codemirror/language@6.10.7)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3)
|
||||
"@codemirror/autocomplete": 6.18.2(@codemirror/language@6.10.7)(@codemirror/state@6.5.0)(@codemirror/view@6.36.1)(@lezer/common@1.2.3)
|
||||
"@codemirror/language": 6.10.7
|
||||
"@codemirror/state": 6.5.0
|
||||
"@lezer/common": 1.2.3
|
||||
@ -9811,39 +9803,39 @@ snapshots:
|
||||
|
||||
"@codemirror/lang-html@6.4.9":
|
||||
dependencies:
|
||||
"@codemirror/autocomplete": 6.18.2(@codemirror/language@6.10.7)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3)
|
||||
"@codemirror/lang-css": 6.3.1(@codemirror/view@6.35.3)
|
||||
"@codemirror/autocomplete": 6.18.2(@codemirror/language@6.10.7)(@codemirror/state@6.5.0)(@codemirror/view@6.36.1)(@lezer/common@1.2.3)
|
||||
"@codemirror/lang-css": 6.3.1(@codemirror/view@6.36.1)
|
||||
"@codemirror/lang-javascript": 6.2.2
|
||||
"@codemirror/language": 6.10.7
|
||||
"@codemirror/state": 6.5.0
|
||||
"@codemirror/view": 6.35.3
|
||||
"@codemirror/view": 6.36.1
|
||||
"@lezer/common": 1.2.3
|
||||
"@lezer/css": 1.1.9
|
||||
"@lezer/html": 1.3.10
|
||||
|
||||
"@codemirror/lang-javascript@6.2.2":
|
||||
dependencies:
|
||||
"@codemirror/autocomplete": 6.18.2(@codemirror/language@6.10.7)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3)
|
||||
"@codemirror/autocomplete": 6.18.2(@codemirror/language@6.10.7)(@codemirror/state@6.5.0)(@codemirror/view@6.36.1)(@lezer/common@1.2.3)
|
||||
"@codemirror/language": 6.10.7
|
||||
"@codemirror/lint": 6.8.2
|
||||
"@codemirror/state": 6.5.0
|
||||
"@codemirror/view": 6.35.3
|
||||
"@codemirror/view": 6.36.1
|
||||
"@lezer/common": 1.2.3
|
||||
"@lezer/javascript": 1.4.21
|
||||
|
||||
"@codemirror/lang-xml@6.1.0":
|
||||
dependencies:
|
||||
"@codemirror/autocomplete": 6.18.2(@codemirror/language@6.10.7)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3)
|
||||
"@codemirror/autocomplete": 6.18.2(@codemirror/language@6.10.7)(@codemirror/state@6.5.0)(@codemirror/view@6.36.1)(@lezer/common@1.2.3)
|
||||
"@codemirror/language": 6.10.7
|
||||
"@codemirror/state": 6.5.0
|
||||
"@codemirror/view": 6.35.3
|
||||
"@codemirror/view": 6.36.1
|
||||
"@lezer/common": 1.2.3
|
||||
"@lezer/xml": 1.0.5
|
||||
|
||||
"@codemirror/language@6.10.7":
|
||||
dependencies:
|
||||
"@codemirror/state": 6.5.0
|
||||
"@codemirror/view": 6.35.3
|
||||
"@codemirror/view": 6.36.1
|
||||
"@lezer/common": 1.2.3
|
||||
"@lezer/highlight": 1.2.1
|
||||
"@lezer/lr": 1.4.2
|
||||
@ -9852,20 +9844,20 @@ snapshots:
|
||||
"@codemirror/lint@6.8.2":
|
||||
dependencies:
|
||||
"@codemirror/state": 6.5.0
|
||||
"@codemirror/view": 6.35.3
|
||||
"@codemirror/view": 6.36.1
|
||||
crelt: 1.0.6
|
||||
|
||||
"@codemirror/search@6.5.7":
|
||||
dependencies:
|
||||
"@codemirror/state": 6.5.0
|
||||
"@codemirror/view": 6.35.3
|
||||
"@codemirror/view": 6.36.1
|
||||
crelt: 1.0.6
|
||||
|
||||
"@codemirror/state@6.5.0":
|
||||
dependencies:
|
||||
"@marijn/find-cluster-break": 1.0.2
|
||||
|
||||
"@codemirror/view@6.35.3":
|
||||
"@codemirror/view@6.36.1":
|
||||
dependencies:
|
||||
"@codemirror/state": 6.5.0
|
||||
style-mod: 4.1.2
|
||||
@ -10857,18 +10849,18 @@ snapshots:
|
||||
dependencies:
|
||||
defer-to-connect: 2.0.1
|
||||
|
||||
"@tailwindcss/forms@0.5.9(tailwindcss@3.4.16)":
|
||||
"@tailwindcss/forms@0.5.9(tailwindcss@3.4.17)":
|
||||
dependencies:
|
||||
mini-svg-data-uri: 1.4.4
|
||||
tailwindcss: 3.4.16
|
||||
tailwindcss: 3.4.17
|
||||
|
||||
"@tailwindcss/typography@0.5.15(tailwindcss@3.4.16)":
|
||||
"@tailwindcss/typography@0.5.15(tailwindcss@3.4.17)":
|
||||
dependencies:
|
||||
lodash.castarray: 4.4.0
|
||||
lodash.isplainobject: 4.0.6
|
||||
lodash.merge: 4.6.2
|
||||
postcss-selector-parser: 6.0.10
|
||||
tailwindcss: 3.4.16
|
||||
tailwindcss: 3.4.17
|
||||
|
||||
"@trysound/sax@0.2.0": {}
|
||||
|
||||
@ -11342,13 +11334,13 @@ snapshots:
|
||||
|
||||
codemirror@6.0.1(@lezer/common@1.2.3):
|
||||
dependencies:
|
||||
"@codemirror/autocomplete": 6.18.2(@codemirror/language@6.10.7)(@codemirror/state@6.5.0)(@codemirror/view@6.35.3)(@lezer/common@1.2.3)
|
||||
"@codemirror/autocomplete": 6.18.2(@codemirror/language@6.10.7)(@codemirror/state@6.5.0)(@codemirror/view@6.36.1)(@lezer/common@1.2.3)
|
||||
"@codemirror/commands": 6.7.1
|
||||
"@codemirror/language": 6.10.7
|
||||
"@codemirror/lint": 6.8.2
|
||||
"@codemirror/search": 6.5.7
|
||||
"@codemirror/state": 6.5.0
|
||||
"@codemirror/view": 6.35.3
|
||||
"@codemirror/view": 6.36.1
|
||||
transitivePeerDependencies:
|
||||
- "@lezer/common"
|
||||
|
||||
@ -12165,7 +12157,7 @@ snapshots:
|
||||
|
||||
foreground-child@3.3.0:
|
||||
dependencies:
|
||||
cross-spawn: 7.0.3
|
||||
cross-spawn: 7.0.6
|
||||
signal-exit: 4.1.0
|
||||
|
||||
form-data-encoder@4.0.2: {}
|
||||
@ -12320,7 +12312,7 @@ snapshots:
|
||||
|
||||
globals@14.0.0: {}
|
||||
|
||||
globals@15.13.0: {}
|
||||
globals@15.14.0: {}
|
||||
|
||||
globalthis@1.0.4:
|
||||
dependencies:
|
||||
@ -13421,7 +13413,7 @@ snapshots:
|
||||
postcss-load-config@4.0.2(postcss@8.4.49):
|
||||
dependencies:
|
||||
lilconfig: 3.1.3
|
||||
yaml: 2.6.0
|
||||
yaml: 2.6.1
|
||||
optionalDependencies:
|
||||
postcss: 8.4.49
|
||||
|
||||
@ -14293,7 +14285,7 @@ snapshots:
|
||||
string-width: 4.2.3
|
||||
strip-ansi: 6.0.1
|
||||
|
||||
tailwindcss@3.4.16:
|
||||
tailwindcss@3.4.17:
|
||||
dependencies:
|
||||
"@alloc/quick-lru": 5.2.0
|
||||
arg: 5.0.2
|
||||
@ -14537,18 +14529,18 @@ snapshots:
|
||||
spdx-correct: 3.2.0
|
||||
spdx-expression-parse: 3.0.1
|
||||
|
||||
vite-plugin-pwa@0.21.1(vite@6.0.3(@types/node@22.9.0)(jiti@2.4.1)(terser@5.36.0)(yaml@2.6.1))(workbox-build@7.3.0)(workbox-window@7.3.0):
|
||||
vite-plugin-pwa@0.21.1(vite@6.0.5(@types/node@22.9.0)(jiti@2.4.1)(terser@5.36.0)(yaml@2.6.1))(workbox-build@7.3.0)(workbox-window@7.3.0):
|
||||
dependencies:
|
||||
debug: 4.3.7
|
||||
pretty-bytes: 6.1.1
|
||||
tinyglobby: 0.2.10
|
||||
vite: 6.0.3(@types/node@22.9.0)(jiti@2.4.1)(terser@5.36.0)(yaml@2.6.1)
|
||||
vite: 6.0.5(@types/node@22.9.0)(jiti@2.4.1)(terser@5.36.0)(yaml@2.6.1)
|
||||
workbox-build: 7.3.0
|
||||
workbox-window: 7.3.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
vite@6.0.3(@types/node@22.9.0)(jiti@2.4.1)(terser@5.36.0)(yaml@2.6.1):
|
||||
vite@6.0.5(@types/node@22.9.0)(jiti@2.4.1)(terser@5.36.0)(yaml@2.6.1):
|
||||
dependencies:
|
||||
esbuild: 0.24.0
|
||||
postcss: 8.4.49
|
||||
@ -14562,7 +14554,7 @@ snapshots:
|
||||
|
||||
w3c-keyname@2.2.8: {}
|
||||
|
||||
wavesurfer.js@7.8.11: {}
|
||||
wavesurfer.js@7.8.12: {}
|
||||
|
||||
wcwidth@1.0.1:
|
||||
dependencies:
|
||||
@ -14775,8 +14767,6 @@ snapshots:
|
||||
|
||||
yallist@3.1.1: {}
|
||||
|
||||
yaml@2.6.0: {}
|
||||
|
||||
yaml@2.6.1: {}
|
||||
|
||||
yargs-parser@18.1.3:
|
||||
|
@ -1,184 +0,0 @@
|
||||
<?php switch ($type): case 'checkbox': ?>
|
||||
<x-Forms.Checkbox
|
||||
class="<?= $class ?>"
|
||||
name="<?= $name ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
value="<?= $value ? 'yes' : '' ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
><?= $label ?></x-Forms.Checkbox>
|
||||
<?php break;
|
||||
case 'toggler': ?>
|
||||
<x-Forms.Toggler
|
||||
class="<?= $class ?>"
|
||||
name="<?= $name ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
value="<?= $value ? 'yes' : '' ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
><?= $label ?></x-Forms.Toggler>
|
||||
<?php break;
|
||||
case 'radio-group': ?>
|
||||
<x-Forms.RadioGroup
|
||||
class="<?= $class ?>"
|
||||
name="<?= $name ?>"
|
||||
label="<?= $label ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
options="<?= $options ?>"
|
||||
isRequired="<?= $optional ? 'false' : 'true' ?>"
|
||||
value="<?= $value ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
/>
|
||||
<?php break;
|
||||
case 'select': ?>
|
||||
<x-Forms.Field
|
||||
as="Select"
|
||||
class="<?= $class ?>"
|
||||
name="<?= $name ?>"
|
||||
label="<?= $label ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
options="<?= $options ?>"
|
||||
isRequired="<?= $optional ? 'false' : 'true' ?>"
|
||||
value="<?= $value ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
/>
|
||||
<?php break;
|
||||
case 'select-multiple': ?>
|
||||
<x-Forms.Field
|
||||
as="SelectMulti"
|
||||
class="<?= $class ?>"
|
||||
name="<?= $name ?>"
|
||||
label="<?= $label ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
options="<?= $options ?>"
|
||||
isRequired="<?= $optional ? 'false' : 'true' ?>"
|
||||
value="<?= $value ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
/>
|
||||
<?php break;
|
||||
case 'email': ?>
|
||||
<x-Forms.Field
|
||||
as="Input"
|
||||
class="<?= $class ?>"
|
||||
type="email"
|
||||
name="<?= $name ?>"
|
||||
label="<?= $label ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
isRequired="<?= $optional ? 'false' : 'true' ?>"
|
||||
value="<?= $value ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
/>
|
||||
<?php break;
|
||||
case 'url': ?>
|
||||
<x-Forms.Field
|
||||
as="Input"
|
||||
class="<?= $class ?>"
|
||||
type="url"
|
||||
placeholder="https://…"
|
||||
name="<?= $name ?>"
|
||||
label="<?= $label ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
isRequired="<?= $optional ? 'false' : 'true' ?>"
|
||||
value="<?= $value ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
/>
|
||||
<?php break;
|
||||
case 'number': ?>
|
||||
<x-Forms.Field
|
||||
as="Input"
|
||||
class="<?= $class ?>"
|
||||
type="number"
|
||||
name="<?= $name ?>"
|
||||
label="<?= $label ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
isRequired="<?= $optional ? 'false' : 'true' ?>"
|
||||
value="<?= $value ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
/>
|
||||
<?php break;
|
||||
case 'textarea': ?>
|
||||
<x-Forms.Field
|
||||
as="Textarea"
|
||||
class="<?= $class ?>"
|
||||
name="<?= $name ?>"
|
||||
label="<?= $label ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
isRequired="<?= $optional ? 'false' : 'true' ?>"
|
||||
value="<?= $value ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
/>
|
||||
<?php break;
|
||||
case 'html': ?>
|
||||
<x-Forms.Field
|
||||
as="CodeEditor"
|
||||
lang="html"
|
||||
class="<?= $class ?>"
|
||||
name="<?= $name ?>"
|
||||
label="<?= $label ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
isRequired="<?= $optional ? 'false' : 'true' ?>"
|
||||
value="<?= htmlspecialchars($value) ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
/>
|
||||
<?php break;
|
||||
case 'markdown': ?>
|
||||
<x-Forms.Field
|
||||
as="MarkdownEditor"
|
||||
class="<?= $class ?>"
|
||||
name="<?= $name ?>"
|
||||
label="<?= $label ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
isRequired="<?= $optional ? 'false' : 'true' ?>"
|
||||
value="<?= $value ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
/>
|
||||
<?php break;
|
||||
case 'rss': ?>
|
||||
<x-Forms.Field
|
||||
as="CodeEditor"
|
||||
lang="xml"
|
||||
class="<?= $class ?>"
|
||||
name="<?= $name ?>"
|
||||
label="<?= $label ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
isRequired="<?= $optional ? 'false' : 'true' ?>"
|
||||
value="<?= htmlspecialchars($value) ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
/>
|
||||
<?php break;
|
||||
case 'datetime': ?>
|
||||
<x-Forms.Field
|
||||
as="DatetimePicker"
|
||||
class="<?= $class ?>"
|
||||
name="<?= $name ?>"
|
||||
label="<?= $label ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
isRequired="<?= $optional ? 'false' : 'true' ?>"
|
||||
value="<?= $value ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
/>
|
||||
<?php break;
|
||||
default: ?>
|
||||
<x-Forms.Field
|
||||
as="Input"
|
||||
class="<?= $class ?>"
|
||||
name="<?= $name ?>"
|
||||
label="<?= $label ?>"
|
||||
hint="<?= $hint ?>"
|
||||
helper="<?= $helper ?>"
|
||||
isRequired="<?= $optional ? 'false' : 'true' ?>"
|
||||
value="<?= $value ?>"
|
||||
defaultValue="<?= $defaultValue ?>"
|
||||
/>
|
||||
<?php endswitch; ?>
|
@ -9,25 +9,14 @@
|
||||
if ($field->type === 'group'): ?>
|
||||
<div class="flex flex-col gap-4" data-field-array="<?= $field->key ?>">
|
||||
<fieldset class="flex flex-col gap-6 rounded" data-field-array-container="<?= $field->key ?>">
|
||||
<legend class="relative z-10 mb-4 font-bold text-heading-foreground font-display before:w-full before:absolute before:h-1/2 before:left-0 before:bottom-0 before:rounded-full before:bg-heading-background before:z-[-10] tracking-wide text-base"><?= $field->getTranslated($plugin->getKey(), 'label') ?></legend>
|
||||
<legend class="relative z-10 mb-4 font-bold text-heading-foreground font-display before:w-full before:absolute before:h-1/2 before:left-0 before:bottom-0 before:rounded-full before:bg-heading-background before:z-[-10] tracking-wide text-base"><?= $field->label ?></legend>
|
||||
<?php
|
||||
$fieldArrayValues = get_plugin_setting($plugin->getKey(), $field->key, $context) ?? [''];
|
||||
foreach ($fieldArrayValues as $index => $value): ?>
|
||||
<fieldset class="relative flex flex-col border border-subtle p-4 rounded-tl-none rounded-md gap-2 bg-base" data-field-array-item="<?= $index ?>">
|
||||
<legend class="absolute font-mono left-0 -top-px -ml-6 rounded-l-full rounded-r-none w-6 text-xs h-6 inline-flex items-center justify-center font-semibold border border-subtle bg-base"><span class="sr-only"><?= $field->getTranslated($plugin->getKey(), 'label') ?></span> <span data-field-array-number><?= $index + 1 ?></span></legend>
|
||||
<legend class="absolute font-mono left-0 -top-px -ml-6 rounded-l-full rounded-r-none w-6 text-xs h-6 inline-flex items-center justify-center font-semibold border border-subtle bg-base"><span class="sr-only"><?= $field->label ?></span> <span data-field-array-number><?= $index + 1 ?></span></legend>
|
||||
<?php foreach ($field->fields as $subfield): ?>
|
||||
<?= view('plugins/_field', [
|
||||
'class' => 'flex-1',
|
||||
'type' => $subfield->type,
|
||||
'name' => sprintf('%s[%s][%s]', $field->key, $index, $subfield->key),
|
||||
'label' => $subfield->getTranslated($plugin->getKey(), 'label'),
|
||||
'hint' => $subfield->getTranslated($plugin->getKey(), 'hint'),
|
||||
'value' => $value[$subfield->key] ?? null,
|
||||
'helper' => $subfield->getTranslated($plugin->getKey(), 'helper'),
|
||||
'defaultValue' => esc($subfield->defaultValue),
|
||||
'options' => esc(json_encode($subfield->getOptionsArray($plugin->getKey()))),
|
||||
'optional' => $subfield->optional,
|
||||
]) ?>
|
||||
<?= $subfield->render(sprintf('%s[%s][%s]', $field->key, $index, $subfield->key), $value[$subfield->key] ?? null, 'flex-1'); ?>
|
||||
<?php endforeach; ?>
|
||||
<x-IconButton variant="danger" glyph="delete-bin-fill" data-field-array-delete="<?= $index ?>" class="absolute right-0 top-0 -mt-4 -mr-4"><?= lang('Common.forms.fieldArray.remove') ?></x-IconButton>
|
||||
</fieldset>
|
||||
@ -42,18 +31,7 @@
|
||||
foreach ($fieldArrayValue as $index => $value): ?>
|
||||
<div class="relative flex items-end" data-field-array-item="<?= $index ?>">
|
||||
<span class="self-start mr-1 -ml-5 w-4 rtl text-sm before:content-['.']" data-field-array-number style="direction:rtl"><?= $index + 1 ?></span>
|
||||
<?= view('plugins/_field', [
|
||||
'class' => 'flex-1',
|
||||
'type' => $field->type,
|
||||
'name' => sprintf('%s[%s]', $field->key, $index),
|
||||
'label' => $field->getTranslated($plugin->getKey(), 'label'),
|
||||
'hint' => $field->getTranslated($plugin->getKey(), 'hint'),
|
||||
'value' => $value,
|
||||
'helper' => $field->getTranslated($plugin->getKey(), 'helper'),
|
||||
'defaultValue' => esc($field->defaultValue),
|
||||
'options' => esc(json_encode($field->getOptionsArray($plugin->getKey()))),
|
||||
'optional' => $field->optional,
|
||||
]) ?>
|
||||
<?= $field->render(sprintf('%s[%s]', $field->key, $index), $value, 'flex-1'); ?>
|
||||
<x-IconButton variant="danger" glyph="delete-bin-fill" data-field-array-delete="<?= $index ?>" type="button" class="mb-2 ml-2"><?= lang('Common.forms.fieldArray.remove') ?></x-IconButton>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
@ -64,35 +42,13 @@
|
||||
<?php elseif ($field->type === 'group'):
|
||||
$value = get_plugin_setting($plugin->getKey(), $field->key, $context); ?>
|
||||
<fieldset class="flex flex-col border border-subtle p-4 rounded-tl-none rounded-md gap-2 bg-base">
|
||||
<legend class="relative z-10 font-bold text-heading-foreground font-display before:w-full before:absolute before:h-1/2 before:left-0 before:bottom-0 before:rounded-full before:bg-heading-background before:z-[-10] tracking-wide text-base"><?= $field->getTranslated($plugin->getKey(), 'label') ?></legend>
|
||||
<legend class="relative z-10 font-bold text-heading-foreground font-display before:w-full before:absolute before:h-1/2 before:left-0 before:bottom-0 before:rounded-full before:bg-heading-background before:z-[-10] tracking-wide text-base"><?= $field->label ?></legend>
|
||||
<?php foreach ($field->fields as $subfield): ?>
|
||||
<?= view('plugins/_field', [
|
||||
'class' => 'flex-1',
|
||||
'type' => $subfield->type,
|
||||
'name' => sprintf('%s[%s]', $field->key, $subfield->key),
|
||||
'label' => $subfield->getTranslated($plugin->getKey(), 'label'),
|
||||
'hint' => $subfield->getTranslated($plugin->getKey(), 'hint'),
|
||||
'value' => $value[$subfield->key] ?? null,
|
||||
'helper' => $subfield->getTranslated($plugin->getKey(), 'helper'),
|
||||
'defaultValue' => esc($subfield->defaultValue),
|
||||
'options' => esc(json_encode($subfield->getOptionsArray($plugin->getKey()))),
|
||||
'optional' => $subfield->optional,
|
||||
]) ?>
|
||||
<?= $subfield->render(sprintf('%s[%s]', $field->key, $subfield->key), $value[$subfield->key] ?? null, 'flex-1'); ?>
|
||||
<?php endforeach; ?>
|
||||
</fieldset>
|
||||
<?php else: ?>
|
||||
<?= view('plugins/_field', [
|
||||
'class' => '',
|
||||
'type' => $field->type,
|
||||
'name' => $field->key,
|
||||
'label' => $field->getTranslated($plugin->getKey(), 'label'),
|
||||
'hint' => $field->getTranslated($plugin->getKey(), 'hint'),
|
||||
'value' => get_plugin_setting($plugin->getKey(), $field->key, $context),
|
||||
'helper' => $field->getTranslated($plugin->getKey(), 'helper'),
|
||||
'defaultValue' => esc($field->defaultValue),
|
||||
'options' => esc(json_encode($field->getOptionsArray($plugin->getKey()))),
|
||||
'optional' => $field->optional,
|
||||
]) ?>
|
||||
<?= $field->render($field->key, get_plugin_setting($plugin->getKey(), $field->key, $context)); ?>
|
||||
<?php endif; ?>
|
||||
<?php endforeach; ?>
|
||||
|
||||
@ -101,4 +57,5 @@
|
||||
<?php endif; ?>
|
||||
|
||||
<x-Button class="self-end mt-4" variant="primary" type="submit"><?= lang('Common.forms.save') ?></x-Button>
|
||||
</form>
|
||||
</form>
|
||||
|
||||
|
@ -102,7 +102,7 @@
|
||||
name="other_categories"
|
||||
label="<?= esc(lang('Podcast.form.other_categories')) ?>"
|
||||
data-max-item-count="2"
|
||||
value="<?= $podcast->other_categories_ids ?>"
|
||||
value="<?= esc(json_encode($podcast->other_categories_ids)) ?>"
|
||||
options="<?= esc(json_encode($categoryOptions)) ?>" />
|
||||
|
||||
<x-Forms.RadioGroup
|
||||
|
Loading…
x
Reference in New Issue
Block a user