first version

This commit is contained in:
Bastian Allgeier
2019-01-13 23:17:34 +01:00
commit 01277f79f2
595 changed files with 82913 additions and 0 deletions

View File

@@ -0,0 +1,64 @@
<?php
use Kirby\Toolkit\A;
use Kirby\Toolkit\Str;
return [
'mixins' => ['options'],
'props' => [
/**
* Unset inherited props
*/
'after' => null,
'before' => null,
'icon' => null,
'placeholder' => null,
/**
* Arranges the checkboxes in the given number of columns
*/
'columns' => function (int $columns = 1) {
return $columns;
},
/**
* Default value for the field, which will be used when a Page/File/User is created
*/
'default' => function ($default = null) {
return Str::split($default, ',');
},
/**
* Maximum number of checked boxes
*/
'max' => function (int $max = null) {
return $max;
},
/**
* Minimum number of checked boxes
*/
'min' => function (int $min = null) {
return $min;
},
'value' => function ($value = null) {
return Str::split($value, ',');
},
],
'computed' => [
'options' => function (): array {
return $this->getOptions();
},
'default' => function () {
return $this->sanitizeOptions($this->default);
},
'value' => function () {
return $this->sanitizeOptions($this->value);
},
],
'save' => function ($value): string {
return A::join($value, ', ');
},
'validations' => [
'options',
'max',
'min'
]
];

76
kirby/config/fields/date.php Executable file
View File

@@ -0,0 +1,76 @@
<?php
return [
'props' => [
/**
* Default date when a new Page/File/User gets created
*/
'default' => function ($default = null) {
return $default;
},
/**
* Changes the calendar icon to something custom
*/
'icon' => function (string $icon = "calendar") {
return $icon;
},
/**
* Youngest date, which can be selected/saved
*/
'max' => function (string $max = null) {
return $this->toDate($max);
},
/**
* Oldest date, which can be selected/saved
*/
'min' => function (string $min = null) {
return $this->toDate($min);
},
/**
* The placeholder is not available
*/
'placeholder' => null,
/**
* Pass true or an array of time field options to show the time selector.
*/
'time' => function ($time = false) {
return $time;
},
/**
* Must be a parseable date string
*/
'value' => function ($value = null) {
return $value;
},
],
'computed' => [
'default' => function () {
return $this->toDate($this->default);
},
'format' => function () {
return $this->props['format'] ?? ($this->time() === false ? 'Y-m-d' : 'Y-m-d H:i');
},
'value' => function () {
return $this->toDate($this->value);
},
],
'methods' => [
'toDate' => function ($value) {
if ($timestamp = timestamp($value, $this->time['step'] ?? 5)) {
return date(DATE_W3C, $timestamp);
}
return null;
}
],
'save' => function ($value) {
if ($value !== null && $date = strtotime($value)) {
return date($this->format(), $date);
}
return '';
},
'validations' => [
'date'
]
];

38
kirby/config/fields/email.php Executable file
View File

@@ -0,0 +1,38 @@
<?php
return [
'extends' => 'text',
'props' => [
/**
* Unset inherited props
*/
'converter' => null,
'counter' => null,
/**
* Sets the HTML5 autocomplete mode for the input
*/
'autocomplete' => function (string $autocomplete = 'email') {
return $autocomplete;
},
/**
* Changes the email icon to something custom
*/
'icon' => function (string $icon = 'email') {
return $icon;
},
/**
* Custom placeholder text, when the field is empty.
*/
'placeholder' => function ($value = null) {
return I18n::translate($value, $value) ?? I18n::translate('email.placeholder');
}
],
'validations' => [
'minlength',
'maxlength',
'email'
]
];

188
kirby/config/fields/files.php Executable file
View File

@@ -0,0 +1,188 @@
<?php
use Kirby\Toolkit\A;
return [
'props' => [
/**
* Unset inherited props
*/
'after' => null,
'before' => null,
'autofocus' => null,
'icon' => null,
'placeholder' => null,
/**
* Sets the file(s), which are selected by default when a new page is created
*/
'default' => function ($default = null) {
return $default;
},
/**
* The placeholder text if no pages have been selected yet
*/
'empty' => function ($empty = null) {
return I18n::translate($empty, $empty);
},
/**
* Image settings for each item
*/
'image' => function (array $image = null) {
return $image ?? [];
},
/**
* Info text
*/
'info' => function (string $info = null) {
return $info;
},
/**
* Changes the layout of the selected files. Available layouts: list, cards
*/
'layout' => function (string $layout = 'list') {
return $layout;
},
/**
* Minimum number of required files
*/
'min' => function (int $min = null) {
return $min;
},
/**
* Maximum number of allowed files
*/
'max' => function (int $max = null) {
return $max;
},
/**
* If false, only a single file can be selected
*/
'multiple' => function (bool $multiple = true) {
return $multiple;
},
/**
* Query for the files to be included
*/
'query' => function (string $query = 'page.files') {
return $query;
},
/**
* Layout size for cards
*/
'size' => function (string $size = null) {
return $size;
},
/**
* Main text
*/
'text' => function (string $text = '{{ file.filename }}') {
return $text;
},
'value' => function ($value = null) {
return $value;
}
],
'computed' => [
'parentModel' => function () {
if (is_string($this->parent) === true && $model = $this->model()->query($this->parent, 'Kirby\Cms\Model')) {
return $model;
}
return $this->model();
},
'parent' => function () {
return $this->parentModel->apiUrl(true);
},
'default' => function () {
return $this->toFiles($this->default);
},
'value' => function () {
return $this->toFiles($this->value);
},
],
'methods' => [
'fileResponse' => function ($file) {
if ($this->layout === 'list') {
$thumb = [
'width' => 100,
'height' => 100
];
} else {
$thumb = [
'width' => 400,
'height' => 400
];
}
$image = $file->panelImage($this->image, $thumb);
$model = $this->model();
$uuid = $file->parent() === $model ? $file->filename() : $file->id();
return [
'filename' => $file->filename(),
'text' => $file->toString($this->text),
'link' => $file->panelUrl(true),
'id' => $file->id(),
'uuid' => $uuid,
'url' => $file->url(),
'info' => $file->toString($this->info ?? false),
'image' => $image,
'icon' => $file->panelIcon($image),
'type' => $file->type(),
];
},
'toFiles' => function ($value = null) {
$files = [];
$kirby = kirby();
foreach (Yaml::decode($value) as $id) {
if (is_array($id) === true) {
$id = $id['id'] ?? null;
}
if ($id !== null && ($file = $this->kirby()->file($id, $this->model()))) {
$files[] = $this->fileResponse($file);
}
}
return $files;
}
],
'api' => function () {
return [
[
'pattern' => '/',
'action' => function () {
$field = $this->field();
$files = $field->model()->query($field->query(), 'Kirby\Cms\Files');
$data = [];
foreach ($files as $index => $file) {
$data[] = $field->fileResponse($file);
}
return $data;
}
]
];
},
'save' => function ($value = null) {
return A::pluck($value, 'uuid');
},
'validations' => [
'max',
'min'
]
];

View File

@@ -0,0 +1,27 @@
<?php
return [
'save' => false,
'props' => [
/**
* Unset inherited props
*/
'after' => null,
'autofocus' => null,
'before' => null,
'default' => null,
'disabled' => null,
'help' => null,
'icon' => null,
'placeholder' => null,
'required' => null,
'translate' => null,
/**
* If false, the prepended number will be hidden
*/
'numbered' => function (bool $numbered = true) {
return $numbered;
}
]
];

3
kirby/config/fields/hidden.php Executable file
View File

@@ -0,0 +1,3 @@
<?php
return [];

23
kirby/config/fields/info.php Executable file
View File

@@ -0,0 +1,23 @@
<?php
use Kirby\Toolkit\I18n;
return [
'props' => [
'text' => function ($value = null) {
return I18n::translate($value, $value);
},
],
'computed' => [
'text' => function () {
$text = $this->text;
if ($model = $this->model()) {
$text = $this->model()->toString($text);
}
return kirbytext($text);
}
],
'save' => false,
];

5
kirby/config/fields/line.php Executable file
View File

@@ -0,0 +1,5 @@
<?php
return [
'save' => false
];

View File

@@ -0,0 +1,43 @@
<?php
use Kirby\Form\Options;
return [
'props' => [
/**
* API settings for options requests. This will only take affect when <code>options</code> is set to <code>api</code>.
*/
'api' => function ($api = null) {
return $api;
},
/**
* An array with options
*/
'options' => function ($options = []) {
return $options;
},
/**
* Query settings for options queries. This will only take affect when <code>options</code> is set to <code>query</code>.
*/
'query' => function ($query = null) {
return $query;
},
],
'methods' => [
'getOptions' => function () {
return Options::factory(
$this->options(),
$this->props,
$this->model()
);
},
'sanitizeOption' => function ($option) {
$allowed = array_column($this->options(), 'value');
return in_array($option, $allowed, true) === true ? $option : null;
},
'sanitizeOptions' => function ($options) {
$allowed = array_column($this->options(), 'value');
return array_intersect($options, $allowed);
},
]
];

View File

@@ -0,0 +1,25 @@
<?php
return [
'extends' => 'tags',
'props' => [
/**
* Custom icon to replace the arrow down.
*/
'icon' => function (string $icon = null) {
return $icon;
},
/**
* Enable/disable the search in the dropdown
*/
'search' => function (bool $search = true) {
return $search;
},
/**
* If true, entries will be sorted alphabetically on selection
*/
'sort' => function (bool $sort = false) {
return $sort;
},
]
];

49
kirby/config/fields/number.php Executable file
View File

@@ -0,0 +1,49 @@
<?php
return [
'props' => [
/**
* Default number that will be saved when a new Page/User/File is created
*/
'default' => function ($default = null) {
return $this->toNumber($default);
},
/**
* The lowest allowed number
*/
'min' => function (float $min = null) {
return $min;
},
/**
* The highest allowed number
*/
'max' => function (float $max = null) {
return $max;
},
/**
* Allowed incremental steps between numbers (i.e 0.5)
*/
'step' => function ($step = 1) {
return $this->toNumber($step);
},
'value' => function ($value = null) {
return $this->toNumber($value);
}
],
'methods' => [
'toNumber' => function ($value) {
if ($this->isEmpty($value) === true) {
return null;
}
$value = str_replace(',', '.', $value);
$value = floatval($value);
return $value;
}
],
'validations' => [
'min',
'max'
]
];

188
kirby/config/fields/pages.php Executable file
View File

@@ -0,0 +1,188 @@
<?php
use Kirby\Toolkit\A;
use Kirby\Toolkit\I18n;
return [
'props' => [
/**
* Unset inherited props
*/
'after' => null,
'autofocus' => null,
'before' => null,
'icon' => null,
'placeholder' => null,
/**
* Default selected page(s) when a new Page/File/User is created
*/
'default' => function ($default = null) {
return $this->toPages($default);
},
/**
* The placeholder text if no pages have been selected yet
*/
'empty' => function ($empty = null) {
return I18n::translate($empty, $empty);
},
/**
* Image settings for each item
*/
'image' => function (array $image = null) {
return $image ?? [];
},
/**
* Info text
*/
'info' => function (string $info = null) {
return $info;
},
/**
* Changes the layout of the selected files. Available layouts: list, cards
*/
'layout' => function (string $layout = 'list') {
return $layout;
},
/**
* The minimum number of required selected pages
*/
'min' => function (int $min = null) {
return $min;
},
/**
* The maximum number of allowed selected pages
*/
'max' => function (int $max = null) {
return $max;
},
/**
* If false, only a single page can be selected
*/
'multiple' => function (bool $multiple = true) {
return $multiple;
},
/**
* Optional query to select a specific set of pages
*/
'query' => function (string $query = null) {
return $query;
},
/**
* Layout size for cards
*/
'size' => function (string $size = null) {
return $size;
},
/**
* Main text
*/
'text' => function (string $text = null) {
return $text;
},
'value' => function ($value = null) {
return $this->toPages($value);
},
],
'methods' => [
'pageResponse' => function ($page) {
if ($this->layout === 'list') {
$thumb = [
'width' => 100,
'height' => 100
];
} else {
$thumb = [
'width' => 400,
'height' => 400
];
}
$image = $page->panelImage($this->image, $thumb);
$model = $this->model();
return [
'text' => $page->toString($this->text ?? '{{ page.title }}'),
'link' => $page->panelUrl(true),
'id' => $page->id(),
'info' => $page->toString($this->info ?? false),
'image' => $image,
'icon' => $page->panelIcon($image),
'hasChildren' => $page->hasChildren(),
];
},
'toPages' => function ($value = null) {
$pages = [];
$kirby = kirby();
foreach (Yaml::decode($value) as $id) {
if (is_array($id) === true) {
$id = $id['id'] ?? null;
}
if ($id !== null && ($page = $kirby->page($id))) {
$pages[] = $this->pageResponse($page);
}
}
return $pages;
}
],
'api' => function () {
return [
[
'pattern' => '/',
'action' => function () {
$field = $this->field();
$query = $field->query();
if ($query) {
$pages = $field->model()->query($query, 'Kirby\Cms\Pages');
$model = null;
} else {
if (!$parent = $this->site()->find($this->requestQuery('parent'))) {
$parent = $this->site();
}
$pages = $parent->children();
$model = [
'id' => $parent->id() == '' ? null : $parent->id(),
'title' => $parent->title()->value()
];
}
$children = [];
foreach ($pages as $index => $page) {
if ($page->isReadable() === true) {
$children[] = $field->pageResponse($page);
}
}
return [
'model' => $model,
'pages' => $children
];
}
]
];
},
'save' => function ($value = null) {
return A::pluck($value, 'id');
},
'validations' => [
'max',
'min'
]
];

32
kirby/config/fields/radio.php Executable file
View File

@@ -0,0 +1,32 @@
<?php
return [
'mixins' => ['options'],
'props' => [
/**
* Unset inherited props
*/
'after' => null,
'before' => null,
'icon' => null,
'placeholder' => null,
/**
* Arranges the radio buttons in the given number of columns
*/
'columns' => function (int $columns = 1) {
return $columns;
},
],
'computed' => [
'options' => function (): array {
return $this->getOptions();
},
'default' => function () {
return $this->sanitizeOption($this->default);
},
'value' => function () {
return $this->sanitizeOption($this->value) ?? '';
}
]
];

24
kirby/config/fields/range.php Executable file
View File

@@ -0,0 +1,24 @@
<?php
return [
'extends' => 'number',
'props' => [
/**
* Unset inherited props
*/
'placeholder' => null,
/**
* The maximum value on the slider
*/
'max' => function (float $max = 100) {
return $max;
},
/**
* Enables/disables the tooltip and set the before and after values
*/
'tooltip' => function ($tooltip = true) {
return $tooltip;
},
]
];

18
kirby/config/fields/select.php Executable file
View File

@@ -0,0 +1,18 @@
<?php
return [
'extends' => 'radio',
'props' => [
/**
* Unset inherited props
*/
'columns' => null,
/**
* Custom icon to replace the arrow down.
*/
'icon' => function (string $icon = null) {
return $icon;
},
]
];

159
kirby/config/fields/structure.php Executable file
View File

@@ -0,0 +1,159 @@
<?php
use Kirby\Form\Form;
use Kirby\Cms\Blueprint;
return [
'props' => [
/**
* Unset inherited props
*/
'after' => null,
'before' => null,
'autofocus' => null,
'icon' => null,
'placeholder' => null,
/**
* Optional columns definition to only show selected fields in the structure table.
*/
'columns' => function (array $columns = []) {
// lower case all keys, because field names will
// be lowercase as well.
return array_change_key_case($columns);
},
/**
* Fields setup for the structure form. Works just like fields in regular forms.
*/
'fields' => function (array $fields) {
return $fields;
},
/**
* The number of entries that will be displayed on a single page. Afterwards pagination kicks in.
*/
'limit' => function (int $limit = null) {
return $limit;
},
/**
* Maximum allowed entries in the structure. Afterwards the "Add" button will be switched off.
*/
'max' => function (int $max = null) {
return $max;
},
/**
* Minimum required entries in the structure
*/
'min' => function (int $min = null) {
return $min;
},
/**
* Toggles drag & drop sorting
*/
'sortable' => function (bool $sortable = null) {
return $sortable;
},
/**
* Sorts the entries by the given field and order (i.e. title desc)
* Drag & drop is disabled in this case
*/
'sortBy' => function (string $sort = null) {
return $sort;
}
],
'computed' => [
'default' => function () {
return $this->rows($this->default);
},
'value' => function () {
return $this->rows($this->value);
},
'fields' => function () {
return $this->form()->fields()->toArray();
},
'columns' => function () {
$columns = [];
if (empty($this->columns)) {
foreach ($this->fields as $field) {
// Skip hidden fields.
// They should never be included as column
if ($field['type'] === 'hidden') {
continue;
}
$columns[$field['name']] = [
'type' => $field['type'],
'label' => $field['label'] ?? $field['name']
];
}
} else {
foreach ($this->columns as $columnName => $columnProps) {
if (is_array($columnProps) === false) {
$columnProps = [];
}
$field = $this->fields[$columnName] ?? null;
if (empty($field) === true) {
continue;
}
$columns[$columnName] = array_merge($columnProps, [
'type' => $field['type'],
'label' => $field['label'] ?? $field['name']
]);
}
}
return $columns;
},
],
'methods' => [
'rows' => function ($value) {
$rows = Yaml::decode($value);
$value = [];
foreach ($rows as $index => $row) {
if (is_array($row) === false) {
continue;
}
$value[] = $this->form($row)->values();
}
return $value;
},
'form' => function (array $values = []) {
return new Form([
'fields' => $this->attrs['fields'],
'values' => $values,
'model' => $this->model
]);
},
],
'api' => function () {
return [
[
'pattern' => 'validate',
'method' => 'ALL',
'action' => function () {
return array_values($this->field()->form($this->requestBody())->errors());
}
]
];
},
'save' => function () {
$data = [];
foreach ($this->value() as $row) {
$data[] = $this->form($row)->data();
}
return $data;
},
'validations' => [
'min',
'max'
]
];

91
kirby/config/fields/tags.php Executable file
View File

@@ -0,0 +1,91 @@
<?php
return [
'mixins' => ['options'],
'props' => [
/**
* Unset inherited props
*/
'after' => null,
'before' => null,
'placeholder' => null,
/**
* If set to <code>all</code>, any type of input is accepted. If set to <code>options</code> only the predefined options are accepted as input.
*/
'accept' => function ($value = 'all') {
return V::in($value, ['all', 'options']) ? $value : 'all';
},
/**
* Changes the tag icon
*/
'icon' => function ($icon = 'tag') {
return $icon;
},
/**
* Minimum number of required entries/tags
*/
'min' => function (int $min = null) {
return $min;
},
/**
* Maximum number of allowed entries/tags
*/
'max' => function (int $max = null) {
return $max;
},
/**
* Custom tags separator, which will be used to store tags in the content file
*/
'separator' => function (string $separator = ',') {
return $separator;
},
],
'computed' => [
'options' => function () {
return $this->getOptions();
},
'default' => function (): array {
return $this->toTags($this->default);
},
'value' => function (): array {
return $this->toTags($this->value);
}
],
'methods' => [
'toTags' => function ($value) {
$options = $this->options();
// transform into value-text objects
return array_map(function ($option) use ($options) {
// already a valid object
if (is_array($option) === true && isset($option['value'], $option['text']) === true) {
return $option;
}
$index = array_search($option, array_column($options, 'value'));
if ($index !== false) {
return $options[$index];
}
return [
'value' => $option,
'text' => $option,
];
}, Str::split($value));
}
],
'save' => function (array $value = null): string {
return A::join(
A::pluck($value, 'value'),
$this->separator() . ' '
);
},
'validations' => [
'min',
'max'
]
];

27
kirby/config/fields/tel.php Executable file
View File

@@ -0,0 +1,27 @@
<?php
return [
'extends' => 'text',
'props' => [
/**
* Unset inherited props
*/
'converter' => null,
'counter' => null,
'spellcheck' => null,
/**
* Sets the HTML5 autocomplete attribute
*/
'autocomplete' => function (string $autocomplete = 'tel') {
return $autocomplete;
},
/**
* Changes the phone icon
*/
'icon' => function (string $icon = 'phone') {
return $icon;
}
]
];

103
kirby/config/fields/text.php Executable file
View File

@@ -0,0 +1,103 @@
<?php
use Kirby\Exception\InvalidArgumentException;
use Kirby\Toolkit\I18n;
use Kirby\Toolkit\Str;
return [
'props' => [
/**
* The field value will be converted with the selected converter before the value gets saved. Available converters: lower, upper, ucfirst, slug
*/
'converter' => function ($value = null) {
if ($value !== null && in_array($value, array_keys($this->converters())) === false) {
throw new InvalidArgumentException([
'key' => 'field.converter.invalid',
'data' => ['converter' => $value]
]);
}
return $value;
},
/**
* Shows or hides the character counter in the top right corner
*/
'counter' => function (bool $counter = true) {
return $counter;
},
/**
* Maximum number of allowed characters
*/
'maxlength' => function (int $maxlength = null) {
return $maxlength;
},
/**
* Minimum number of required characters
*/
'minlength' => function (int $minlength = null) {
return $minlength;
},
/**
* A regular expression, which will be used to validate the input
*/
'pattern' => function (string $pattern = null) {
return $pattern;
},
/**
* If false, spellcheck will be switched off
*/
'spellcheck' => function (bool $spellcheck = false) {
return $spellcheck;
},
],
'computed' => [
'default' => function () {
return $this->convert($this->default);
},
'value' => function () {
return (string)$this->convert($this->value);
}
],
'methods' => [
'convert' => function ($value) {
if ($this->converter() === null) {
return $value;
}
$value = trim($value);
$converter = $this->converters()[$this->converter()];
if (is_array($value) === true) {
return array_map($converter, $value);
}
return call_user_func($converter, $value);
},
'converters' => function (): array {
return [
'lower' => function ($value) {
return Str::lower($value);
},
'slug' => function ($value) {
return Str::slug($value);
},
'ucfirst' => function ($value) {
return Str::ucfirst($value);
},
'upper' => function ($value) {
return Str::upper($value);
},
];
},
],
'validations' => [
'minlength',
'maxlength'
]
];

View File

@@ -0,0 +1,61 @@
<?php
return [
'props' => [
/**
* Unset inherited props
*/
'after' => null,
'before' => null,
/**
* Enables/disables the format buttons. Can either be true/false or a list of allowed buttons. Available buttons: headlines, italic, bold, link, email, list, code, ul, ol
*/
'buttons' => function ($buttons = true) {
return $buttons;
},
/**
* Enables/disables the character counter in the top right corner
*/
'counter' => function (bool $counter = true) {
return $counter;
},
/**
* Sets the default text when a new Page/File/User is created
*/
'default' => function (string $default = null) {
return trim($default);
},
/**
* Maximum number of allowed characters
*/
'maxlength' => function (int $maxlength = null) {
return $maxlength;
},
/**
* Minimum number of required characters
*/
'minlength' => function (int $minlength = null) {
return $minlength;
},
/**
* Changes the size of the textarea. Available sizes: small, medium, large, huge
*/
'size' => function (string $size = null) {
return $size;
},
'value' => function (string $value = null) {
return trim($value);
}
],
'validations' => [
'minlength',
'maxlength'
]
];

68
kirby/config/fields/time.php Executable file
View File

@@ -0,0 +1,68 @@
<?php
return [
'props' => [
/**
* Unset inherited props
*/
'placeholder' => null,
/**
* Sets the default time when a new Page/File/User is created
*/
'default' => function ($default = null) {
return $default;
},
/**
* Changes the clock icon
*/
'icon' => function (string $icon = 'clock') {
return $icon;
},
/**
* 12 or 24 hour notation. If 12, an AM/PM selector will be shown.
*/
'notation' => function (int $value = 24) {
return $value === 24 ? 24 : 12;
},
/**
* The interval between minutes in the minutes select dropdown.
*/
'step' => function (int $step = 5) {
return $step;
},
'value' => function ($value = null) {
return $value;
}
],
'computed' => [
'default' => function () {
return $this->toTime($this->default);
},
'format' => function () {
return $this->notation === 24 ? 'H:i' : 'h:i a';
},
'value' => function () {
return $this->toTime($this->value);
}
],
'methods' => [
'toTime' => function ($value) {
if ($timestamp = timestamp($value, $this->step)) {
return date('H:i', $timestamp);
}
return null;
}
],
'save' => function ($value): string {
if ($timestamp = strtotime($value)) {
return date($this->format, $timestamp);
}
return '';
},
'validations' => [
'time',
]
];

64
kirby/config/fields/toggle.php Executable file
View File

@@ -0,0 +1,64 @@
<?php
use Kirby\Exception\InvalidArgumentException;
return [
'props' => [
/**
* Unset inherited props
*/
'placeholder' => null,
/**
* Default value which will be saved when a new Page/User/File is created
*/
'default' => function ($value = null) {
return $this->toBool($value);
},
/**
* Sets the text next to the toggle. The text can be a string or an array of two options. The first one is the negative text and the second one the positive. The text will automatically switch when the toggle is triggered.
*/
'text' => function ($value = null) {
if (is_array($value) === true) {
if (A::isAssociative($value) === true) {
return I18n::translate($value, $value);
}
foreach ($value as $key => $val) {
$value[$key] = I18n::translate($val, $val);
}
return $value;
}
return I18n::translate($value, $value);
},
],
'computed' => [
'value' => function () {
if ($this->props['value'] === null) {
return $this->default();
} else {
return $this->toBool($this->props['value']);
}
}
],
'methods' => [
'toBool' => function ($value) {
return in_array($value, [true, 'true', 1, '1', 'on'], true) === true;
}
],
'save' => function (): string {
return $this->value() === true ? 'true' : 'false';
},
'validations' => [
'boolean',
'required' => function ($value) {
if ($this->isRequired() && ($value === false || $this->isEmpty($value))) {
throw new InvalidArgumentException([
'key' => 'form.field.required'
]);
}
},
]
];

39
kirby/config/fields/url.php Executable file
View File

@@ -0,0 +1,39 @@
<?php
return [
'extends' => 'text',
'props' => [
/**
* Unset inherited props
*/
'converter' => null,
'counter' => null,
'spellcheck' => null,
/**
* Sets the HTML5 autocomplete attribute
*/
'autocomplete' => function (string $autocomplete = 'url') {
return $autocomplete;
},
/**
* Changes the link icon
*/
'icon' => function (string $icon = 'url') {
return $icon;
},
/**
* Sets custom placeholder text, when the field is empty
*/
'placeholder' => function ($value = null) {
return I18n::translate($value, $value) ?? 'https://example.com';
}
],
'validations' => [
'minlength',
'maxlength',
'url'
],
];

95
kirby/config/fields/users.php Executable file
View File

@@ -0,0 +1,95 @@
<?php
return [
'props' => [
/**
* Unset inherited props
*/
'after' => null,
'autofocus' => null,
'before' => null,
'icon' => null,
'placeholder' => null,
/**
* Default selected user(s) when a new Page/File/User is created
*/
'default' => function ($default = null) {
if ($default === false) {
return [];
}
if ($default === null && $user = $this->kirby()->user()) {
return [
$this->userResponse($user)
];
}
return $this->toUsers($default);
},
/**
* The minimum number of required selected users
*/
'min' => function (int $min = null) {
return $min;
},
/**
* The maximum number of allowed selected users
*/
'max' => function (int $max = null) {
return $max;
},
/**
* If false, only a single user can be selected
*/
'multiple' => function (bool $multiple = true) {
return $multiple;
},
'value' => function ($value = null) {
return $this->toUsers($value);
},
],
'methods' => [
'userResponse' => function ($user) {
$avatar = function ($user) {
if ($avatar = $user->avatar()) {
return [
'url' => $avatar->crop(512)->url()
];
}
return null;
};
return [
'username' => $user->username(),
'id' => $user->id(),
'email' => $user->email(),
'avatar' => $avatar($user)
];
},
'toUsers' => function ($value = null) {
$users = [];
$kirby = kirby();
foreach (Yaml::decode($value) as $email) {
if (is_array($email) === true) {
$email = $email['email'] ?? null;
}
if ($email !== null && ($user = $kirby->user($email))) {
$users[] = $this->userResponse($user);
}
}
return $users;
}
],
'save' => function ($value = null) {
return A::pluck($value, 'email');
},
'validations' => [
'max',
'min'
]
];