Initial commit

This commit is contained in:
Paul Nicoué 2021-10-29 18:05:46 +02:00
commit 1ff19bf38f
830 changed files with 159212 additions and 0 deletions

View file

@ -0,0 +1,56 @@
<?php
use Kirby\Cms\Form;
return [
'props' => [
'fields' => function (array $fields = []) {
return $fields;
}
],
'computed' => [
'form' => function () {
$fields = $this->fields;
$disabled = $this->model->permissions()->update() === false;
$content = $this->model->content()->toArray();
if ($disabled === true) {
foreach ($fields as $key => $props) {
$fields[$key]['disabled'] = true;
}
}
return new Form([
'fields' => $fields,
'values' => $content,
'model' => $this->model,
'strict' => true
]);
},
'fields' => function () {
$fields = $this->form->fields()->toArray();
if (is_a($this->model, 'Kirby\Cms\Page') === true || is_a($this->model, 'Kirby\Cms\Site') === true) {
// the title should never be updated directly via
// fields section to avoid conflicts with the rename dialog
unset($fields['title']);
}
foreach ($fields as $index => $props) {
unset($fields[$index]['value']);
}
return $fields;
}
],
'methods' => [
'errors' => function () {
return $this->form->errors();
}
],
'toArray' => function () {
return [
'fields' => $this->fields,
];
}
];

View file

@ -0,0 +1,251 @@
<?php
use Kirby\Cms\File;
use Kirby\Toolkit\Escape;
use Kirby\Toolkit\I18n;
return [
'mixins' => [
'empty',
'headline',
'help',
'layout',
'min',
'max',
'pagination',
'parent',
],
'props' => [
/**
* Enables/disables reverse sorting
*/
'flip' => function (bool $flip = false) {
return $flip;
},
/**
* Image options to control the source and look of file previews
*/
'image' => function ($image = null) {
return $image ?? [];
},
/**
* Optional info text setup. Info text is shown on the right (lists) or below (cards) the filename.
*/
'info' => function ($info = null) {
return I18n::translate($info, $info);
},
/**
* The size option controls the size of cards. By default cards are auto-sized and the cards grid will always fill the full width. With a size you can disable auto-sizing. Available sizes: `tiny`, `small`, `medium`, `large`, `huge`
*/
'size' => function (string $size = 'auto') {
return $size;
},
/**
* Enables/disables manual sorting
*/
'sortable' => function (bool $sortable = true) {
return $sortable;
},
/**
* Overwrites manual sorting and sorts by the given field and sorting direction (i.e. `filename desc`)
*/
'sortBy' => function (string $sortBy = null) {
return $sortBy;
},
/**
* Filters all files by template and also sets the template, which will be used for all uploads
*/
'template' => function (string $template = null) {
return $template;
},
/**
* Setup for the main text in the list or cards. By default this will display the filename.
*/
'text' => function ($text = '{{ file.filename }}') {
return I18n::translate($text, $text);
}
],
'computed' => [
'accept' => function () {
if ($this->template) {
$file = new File([
'filename' => 'tmp',
'template' => $this->template
]);
return $file->blueprint()->acceptMime();
}
return null;
},
'parent' => function () {
return $this->parentModel();
},
'files' => function () {
$files = $this->parent->files()->template($this->template);
// filter out all protected files
$files = $files->filter('isReadable', true);
if ($this->sortBy) {
$files = $files->sort(...$files::sortArgs($this->sortBy));
} else {
$files = $files->sort('sort', 'asc', 'filename', 'asc');
}
// flip
if ($this->flip === true) {
$files = $files->flip();
}
// apply the default pagination
$files = $files->paginate([
'page' => $this->page,
'limit' => $this->limit,
'method' => 'none' // the page is manually provided
]);
return $files;
},
'data' => function () {
$data = [];
// the drag text needs to be absolute when the files come from
// a different parent model
$dragTextAbsolute = $this->model->is($this->parent) === false;
foreach ($this->files as $file) {
$image = $file->panelImage($this->image);
// escape the default text
// TODO: no longer needed in 3.6
$text = $file->toString($this->text);
if ($this->text === '{{ file.filename }}') {
$text = Escape::html($text);
}
$data[] = [
'dragText' => $file->dragText('auto', $dragTextAbsolute),
'extension' => $file->extension(),
'filename' => $file->filename(),
'id' => $file->id(),
'icon' => $file->panelIcon($image),
'image' => $image,
'info' => $file->toString($this->info ?? false),
'link' => $file->panelUrl(true),
'mime' => $file->mime(),
'parent' => $file->parent()->panelPath(),
'text' => $text,
'url' => $file->url(),
];
}
return $data;
},
'total' => function () {
return $this->files->pagination()->total();
},
'errors' => function () {
$errors = [];
if ($this->validateMax() === false) {
$errors['max'] = I18n::template('error.section.files.max.' . I18n::form($this->max), [
'max' => $this->max,
'section' => $this->headline
]);
}
if ($this->validateMin() === false) {
$errors['min'] = I18n::template('error.section.files.min.' . I18n::form($this->min), [
'min' => $this->min,
'section' => $this->headline
]);
}
if (empty($errors) === true) {
return [];
}
return [
$this->name => [
'label' => $this->headline,
'message' => $errors,
]
];
},
'link' => function () {
$modelLink = $this->model->panelUrl(true);
$parentLink = $this->parent->panelUrl(true);
if ($modelLink !== $parentLink) {
return $parentLink;
}
},
'pagination' => function () {
return $this->pagination();
},
'sortable' => function () {
if ($this->sortable === false) {
return false;
}
if ($this->sortBy !== null) {
return false;
}
if ($this->flip === true) {
return false;
}
return true;
},
'upload' => function () {
if ($this->isFull() === true) {
return false;
}
// count all uploaded files
$total = count($this->data);
$max = $this->max ? $this->max - $total : null;
if ($this->max && $total === $this->max - 1) {
$multiple = false;
} else {
$multiple = true;
}
$template = $this->template === 'default' ? null : $this->template;
return [
'accept' => $this->accept,
'multiple' => $multiple,
'max' => $max,
'api' => $this->parent->apiUrl(true) . '/files',
'attributes' => array_filter([
'template' => $template
])
];
}
],
'toArray' => function () {
return [
'data' => $this->data,
'errors' => $this->errors,
'options' => [
'accept' => $this->accept,
'apiUrl' => $this->parent->apiUrl(true),
'empty' => $this->empty,
'headline' => $this->headline,
'help' => $this->help,
'layout' => $this->layout,
'link' => $this->link,
'max' => $this->max,
'min' => $this->min,
'size' => $this->size,
'sortable' => $this->sortable,
'upload' => $this->upload
],
'pagination' => $this->pagination
];
}
];

View file

@ -0,0 +1,35 @@
<?php
use Kirby\Toolkit\I18n;
return [
'mixins' => [
'headline',
],
'props' => [
'text' => function ($text = null) {
return I18n::translate($text, $text);
},
'theme' => function (string $theme = null) {
return $theme;
}
],
'computed' => [
'text' => function () {
if ($this->text) {
$text = $this->model()->toString($this->text);
$text = $this->kirby()->kirbytext($text);
return $text;
}
},
],
'toArray' => function () {
return [
'options' => [
'headline' => $this->headline,
'text' => $this->text,
'theme' => $this->theme
]
];
}
];

View file

@ -0,0 +1,21 @@
<?php
use Kirby\Toolkit\I18n;
return [
'props' => [
/**
* Sets the text for the empty state box
*/
'empty' => function ($empty = null) {
return I18n::translate($empty, $empty);
}
],
'computed' => [
'empty' => function () {
if ($this->empty) {
return $this->model()->toString($this->empty);
}
}
]
];

View file

@ -0,0 +1,23 @@
<?php
use Kirby\Toolkit\I18n;
return [
'props' => [
/**
* The headline for the section. This can be a simple string or a template with additional info from the parent page.
*/
'headline' => function ($headline = null) {
return I18n::translate($headline, $headline);
}
],
'computed' => [
'headline' => function () {
if ($this->headline) {
return $this->model()->toString($this->headline);
}
return ucfirst($this->name);
}
]
];

View file

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

View file

@ -0,0 +1,12 @@
<?php
return [
'props' => [
/**
* Section layout. Available layout methods: `list`, `cards`.
*/
'layout' => function (string $layout = 'list') {
return $layout === 'cards' ? 'cards' : 'list';
}
]
];

View file

@ -0,0 +1,28 @@
<?php
return [
'props' => [
/**
* Sets the maximum number of allowed entries in the section
*/
'max' => function (int $max = null) {
return $max;
}
],
'methods' => [
'isFull' => function () {
if ($this->max) {
return $this->total >= $this->max;
}
return false;
},
'validateMax' => function () {
if ($this->max && $this->total > $this->max) {
return false;
}
return true;
}
]
];

View file

@ -0,0 +1,21 @@
<?php
return [
'props' => [
/**
* Sets the minimum number of required entries in the section
*/
'min' => function (int $min = null) {
return $min;
}
],
'methods' => [
'validateMin' => function () {
if ($this->min && $this->min > $this->total) {
return false;
}
return true;
}
]
];

View file

@ -0,0 +1,36 @@
<?php
use Kirby\Toolkit\Pagination;
return [
'props' => [
/**
* Sets the number of items per page. If there are more items the pagination navigation will be shown at the bottom of the section.
*/
'limit' => function (int $limit = 20) {
return $limit;
},
/**
* Sets the default page for the pagination. This will overwrite default pagination.
*/
'page' => function (int $page = null) {
return get('page', $page);
},
],
'methods' => [
'pagination' => function () {
$pagination = new Pagination([
'limit' => $this->limit,
'page' => $this->page,
'total' => $this->total
]);
return [
'limit' => $pagination->limit(),
'offset' => $pagination->offset(),
'page' => $pagination->page(),
'total' => $pagination->total(),
];
},
]
];

View file

@ -0,0 +1,43 @@
<?php
use Kirby\Exception\Exception;
return [
'props' => [
/**
* Sets the query to a parent to find items for the list
*/
'parent' => function (string $parent = null) {
return $parent;
}
],
'methods' => [
'parentModel' => function () {
$parent = $this->parent;
if (is_string($parent) === true) {
$query = $parent;
$parent = $this->model->query($query);
if (!$parent) {
throw new Exception('The parent for the query "' . $query . '" cannot be found in the section "' . $this->name() . '"');
}
if (
is_a($parent, 'Kirby\Cms\Page') === false &&
is_a($parent, 'Kirby\Cms\Site') === false &&
is_a($parent, 'Kirby\Cms\File') === false &&
is_a($parent, 'Kirby\Cms\User') === false
) {
throw new Exception('The parent for the section "' . $this->name() . '" has to be a page, site or user object');
}
}
if ($parent === null) {
return $this->model;
}
return $parent;
}
]
];

View file

@ -0,0 +1,308 @@
<?php
use Kirby\Cms\Blueprint;
use Kirby\Toolkit\A;
use Kirby\Toolkit\Escape;
use Kirby\Toolkit\I18n;
return [
'mixins' => [
'empty',
'headline',
'help',
'layout',
'min',
'max',
'pagination',
'parent'
],
'props' => [
/**
* Optional array of templates that should only be allowed to add
* or `false` to completely disable page creation
*/
'create' => function ($create = null) {
return $create;
},
/**
* Enables/disables reverse sorting
*/
'flip' => function (bool $flip = false) {
return $flip;
},
/**
* Image options to control the source and look of page previews
*/
'image' => function ($image = null) {
return $image ?? [];
},
/**
* Optional info text setup. Info text is shown on the right (lists) or below (cards) the page title.
*/
'info' => function ($info = null) {
return I18n::translate($info, $info);
},
/**
* The size option controls the size of cards. By default cards are auto-sized and the cards grid will always fill the full width. With a size you can disable auto-sizing. Available sizes: `tiny`, `small`, `medium`, `large`, `huge`
*/
'size' => function (string $size = 'auto') {
return $size;
},
/**
* Enables/disables manual sorting
*/
'sortable' => function (bool $sortable = true) {
return $sortable;
},
/**
* Overwrites manual sorting and sorts by the given field and sorting direction (i.e. `date desc`)
*/
'sortBy' => function (string $sortBy = null) {
return $sortBy;
},
/**
* Filters pages by their status. Available status settings: `draft`, `unlisted`, `listed`, `published`, `all`.
*/
'status' => function (string $status = '') {
if ($status === 'drafts') {
$status = 'draft';
}
if (in_array($status, ['all', 'draft', 'published', 'listed', 'unlisted']) === false) {
$status = 'all';
}
return $status;
},
/**
* Filters the list by templates and sets template options when adding new pages to the section.
*/
'templates' => function ($templates = null) {
return A::wrap($templates ?? $this->template);
},
/**
* Setup for the main text in the list or cards. By default this will display the page title.
*/
'text' => function ($text = '{{ page.title }}') {
return I18n::translate($text, $text);
}
],
'computed' => [
'parent' => function () {
return $this->parentModel();
},
'pages' => function () {
switch ($this->status) {
case 'draft':
$pages = $this->parent->drafts();
break;
case 'listed':
$pages = $this->parent->children()->listed();
break;
case 'published':
$pages = $this->parent->children();
break;
case 'unlisted':
$pages = $this->parent->children()->unlisted();
break;
default:
$pages = $this->parent->childrenAndDrafts();
}
// loop for the best performance
foreach ($pages->data as $id => $page) {
// remove all protected pages
if ($page->isReadable() === false) {
unset($pages->data[$id]);
continue;
}
// filter by all set templates
if ($this->templates && in_array($page->intendedTemplate()->name(), $this->templates) === false) {
unset($pages->data[$id]);
continue;
}
}
// sort
if ($this->sortBy) {
$pages = $pages->sort(...$pages::sortArgs($this->sortBy));
}
// flip
if ($this->flip === true) {
$pages = $pages->flip();
}
// pagination
$pages = $pages->paginate([
'page' => $this->page,
'limit' => $this->limit,
'method' => 'none' // the page is manually provided
]);
return $pages;
},
'total' => function () {
return $this->pages->pagination()->total();
},
'data' => function () {
$data = [];
foreach ($this->pages as $item) {
$permissions = $item->permissions();
$image = $item->panelImage($this->image);
// escape the default text
// TODO: no longer needed in 3.6
$text = $item->toString($this->text);
if ($this->text === '{{ page.title }}') {
$text = Escape::html($text);
}
$data[] = [
'id' => $item->id(),
'dragText' => $item->dragText(),
'text' => $text,
'info' => $item->toString($this->info ?? false),
'parent' => $item->parentId(),
'icon' => $item->panelIcon($image),
'image' => $image,
'link' => $item->panelUrl(true),
'status' => $item->status(),
'permissions' => [
'sort' => $permissions->can('sort'),
'changeSlug' => $permissions->can('changeSlug'),
'changeStatus' => $permissions->can('changeStatus'),
'changeTitle' => $permissions->can('changeTitle')
]
];
}
return $data;
},
'errors' => function () {
$errors = [];
if ($this->validateMax() === false) {
$errors['max'] = I18n::template('error.section.pages.max.' . I18n::form($this->max), [
'max' => $this->max,
'section' => $this->headline
]);
}
if ($this->validateMin() === false) {
$errors['min'] = I18n::template('error.section.pages.min.' . I18n::form($this->min), [
'min' => $this->min,
'section' => $this->headline
]);
}
if (empty($errors) === true) {
return [];
}
return [
$this->name => [
'label' => $this->headline,
'message' => $errors,
]
];
},
'add' => function () {
if ($this->create === false) {
return false;
}
if (in_array($this->status, ['draft', 'all']) === false) {
return false;
}
if ($this->isFull() === true) {
return false;
}
return true;
},
'link' => function () {
$modelLink = $this->model->panelUrl(true);
$parentLink = $this->parent->panelUrl(true);
if ($modelLink !== $parentLink) {
return $parentLink;
}
},
'pagination' => function () {
return $this->pagination();
},
'sortable' => function () {
if (in_array($this->status, ['listed', 'published', 'all']) === false) {
return false;
}
if ($this->sortable === false) {
return false;
}
if ($this->sortBy !== null) {
return false;
}
if ($this->flip === true) {
return false;
}
return true;
}
],
'methods' => [
'blueprints' => function () {
$blueprints = [];
$templates = empty($this->create) === false ? A::wrap($this->create) : $this->templates;
if (empty($templates) === true) {
$templates = $this->kirby()->blueprints();
}
// convert every template to a usable option array
// for the template select box
foreach ($templates as $template) {
try {
$props = Blueprint::load('pages/' . $template);
$blueprints[] = [
'name' => basename($props['name']),
'title' => $props['title'],
];
} catch (Throwable $e) {
$blueprints[] = [
'name' => basename($template),
'title' => ucfirst($template),
];
}
}
return $blueprints;
}
],
'toArray' => function () {
return [
'data' => $this->data,
'errors' => $this->errors,
'options' => [
'add' => $this->add,
'empty' => $this->empty,
'headline' => $this->headline,
'help' => $this->help,
'layout' => $this->layout,
'link' => $this->link,
'max' => $this->max,
'min' => $this->min,
'size' => $this->size,
'sortable' => $this->sortable
],
'pagination' => $this->pagination,
];
}
];