471 lines
10 KiB
PHP
Executable File
471 lines
10 KiB
PHP
Executable File
<?php
|
|
|
|
namespace Kirby\Panel;
|
|
|
|
use Kirby\Toolkit\I18n;
|
|
use Throwable;
|
|
|
|
/**
|
|
* Provides information about the file model for the Panel
|
|
* @since 3.6.0
|
|
*
|
|
* @package Kirby Panel
|
|
* @author Nico Hoffmann <nico@getkirby.com>
|
|
* @link https://getkirby.com
|
|
* @copyright Bastian Allgeier
|
|
* @license https://getkirby.com/license
|
|
*/
|
|
class File extends Model
|
|
{
|
|
/**
|
|
* @var \Kirby\Cms\File
|
|
*/
|
|
protected $model;
|
|
|
|
/**
|
|
* Breadcrumb array
|
|
*
|
|
* @return array
|
|
*/
|
|
public function breadcrumb(): array
|
|
{
|
|
$breadcrumb = [];
|
|
$parent = $this->model->parent();
|
|
|
|
switch ($parent::CLASS_ALIAS) {
|
|
case 'user':
|
|
// The breadcrumb is not necessary
|
|
// on the account view
|
|
if ($parent->isLoggedIn() === false) {
|
|
$breadcrumb[] = [
|
|
'label' => $parent->username(),
|
|
'link' => $parent->panel()->url(true)
|
|
];
|
|
}
|
|
break;
|
|
case 'page':
|
|
$breadcrumb = $this->model->parents()->flip()->values(fn ($parent) => [
|
|
'label' => $parent->title()->toString(),
|
|
'link' => $parent->panel()->url(true),
|
|
]);
|
|
}
|
|
|
|
// add the file
|
|
$breadcrumb[] = [
|
|
'label' => $this->model->filename(),
|
|
'link' => $this->url(true),
|
|
];
|
|
|
|
return $breadcrumb;
|
|
}
|
|
|
|
/**
|
|
* Provides a kirbytag or markdown
|
|
* tag for the file, which will be
|
|
* used in the panel, when the file
|
|
* gets dragged onto a textarea
|
|
*
|
|
* @internal
|
|
* @param string|null $type (`auto`|`kirbytext`|`markdown`)
|
|
* @param bool $absolute
|
|
* @return string
|
|
*/
|
|
public function dragText(string $type = null, bool $absolute = false): string
|
|
{
|
|
$type = $this->dragTextType($type);
|
|
$url = $absolute ? $this->model->id() : $this->model->filename();
|
|
|
|
if ($dragTextFromCallback = $this->dragTextFromCallback($type, $url)) {
|
|
return $dragTextFromCallback;
|
|
}
|
|
|
|
if ($type === 'markdown') {
|
|
if ($this->model->type() === 'image') {
|
|
return '';
|
|
}
|
|
|
|
return '[' . $this->model->filename() . '](' . $url . ')';
|
|
}
|
|
|
|
if ($this->model->type() === 'image') {
|
|
return '(image: ' . $url . ')';
|
|
}
|
|
if ($this->model->type() === 'video') {
|
|
return '(video: ' . $url . ')';
|
|
}
|
|
|
|
return '(file: ' . $url . ')';
|
|
}
|
|
|
|
/**
|
|
* Provides options for the file dropdown
|
|
*
|
|
* @param array $options
|
|
* @return array
|
|
*/
|
|
public function dropdown(array $options = []): array
|
|
{
|
|
$file = $this->model;
|
|
|
|
$defaults = $file->kirby()->request()->get(['view', 'update', 'delete']);
|
|
$options = array_merge($defaults, $options);
|
|
|
|
$permissions = $this->options(['preview']);
|
|
$view = $options['view'] ?? 'view';
|
|
$url = $this->url(true);
|
|
$result = [];
|
|
|
|
if ($view === 'list') {
|
|
$result[] = [
|
|
'link' => $file->previewUrl(),
|
|
'target' => '_blank',
|
|
'icon' => 'open',
|
|
'text' => I18n::translate('open')
|
|
];
|
|
$result[] = '-';
|
|
}
|
|
|
|
$result[] = [
|
|
'dialog' => $url . '/changeName',
|
|
'icon' => 'title',
|
|
'text' => I18n::translate('rename'),
|
|
'disabled' => $this->isDisabledDropdownOption('changeName', $options, $permissions)
|
|
];
|
|
|
|
$result[] = [
|
|
'click' => 'replace',
|
|
'icon' => 'upload',
|
|
'text' => I18n::translate('replace'),
|
|
'disabled' => $this->isDisabledDropdownOption('replace', $options, $permissions)
|
|
];
|
|
|
|
if ($view === 'list') {
|
|
$result[] = '-';
|
|
$result[] = [
|
|
'dialog' => $url . '/changeSort',
|
|
'icon' => 'sort',
|
|
'text' => I18n::translate('file.sort'),
|
|
'disabled' => $this->isDisabledDropdownOption('update', $options, $permissions)
|
|
];
|
|
}
|
|
|
|
$result[] = '-';
|
|
$result[] = [
|
|
'dialog' => $url . '/delete',
|
|
'icon' => 'trash',
|
|
'text' => I18n::translate('delete'),
|
|
'disabled' => $this->isDisabledDropdownOption('delete', $options, $permissions)
|
|
];
|
|
|
|
return $result;
|
|
}
|
|
|
|
/**
|
|
* Returns the setup for a dropdown option
|
|
* which is used in the changes dropdown
|
|
* for example.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function dropdownOption(): array
|
|
{
|
|
return [
|
|
'icon' => 'image',
|
|
'text' => $this->model->filename(),
|
|
] + parent::dropdownOption();
|
|
}
|
|
|
|
/**
|
|
* Returns the Panel icon color
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function imageColor(): string
|
|
{
|
|
$types = [
|
|
'image' => 'orange-400',
|
|
'video' => 'yellow-400',
|
|
'document' => 'red-400',
|
|
'audio' => 'aqua-400',
|
|
'code' => 'blue-400',
|
|
'archive' => 'gray-500'
|
|
];
|
|
|
|
$extensions = [
|
|
'indd' => 'purple-400',
|
|
'xls' => 'green-400',
|
|
'xlsx' => 'green-400',
|
|
'csv' => 'green-400',
|
|
'docx' => 'blue-400',
|
|
'doc' => 'blue-400',
|
|
'rtf' => 'blue-400'
|
|
];
|
|
|
|
return $extensions[$this->model->extension()] ??
|
|
$types[$this->model->type()] ??
|
|
parent::imageDefaults()['color'];
|
|
}
|
|
|
|
/**
|
|
* Default settings for the file's Panel image
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function imageDefaults(): array
|
|
{
|
|
return array_merge(parent::imageDefaults(), [
|
|
'color' => $this->imageColor(),
|
|
'icon' => $this->imageIcon(),
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Returns the Panel icon type
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function imageIcon(): string
|
|
{
|
|
$types = [
|
|
'image' => 'image',
|
|
'video' => 'video',
|
|
'document' => 'document',
|
|
'audio' => 'audio',
|
|
'code' => 'code',
|
|
'archive' => 'archive'
|
|
];
|
|
|
|
$extensions = [
|
|
'xls' => 'table',
|
|
'xlsx' => 'table',
|
|
'csv' => 'table',
|
|
'docx' => 'pen',
|
|
'doc' => 'pen',
|
|
'rtf' => 'pen',
|
|
'mdown' => 'markdown',
|
|
'md' => 'markdown'
|
|
];
|
|
|
|
return $extensions[$this->model->extension()] ??
|
|
$types[$this->model->type()] ??
|
|
'file';
|
|
}
|
|
|
|
/**
|
|
* Returns the image file object based on provided query
|
|
*
|
|
* @internal
|
|
* @param string|null $query
|
|
* @return \Kirby\Cms\File|\Kirby\Filesystem\Asset|null
|
|
*/
|
|
protected function imageSource(string $query = null)
|
|
{
|
|
if ($query === null && $this->model->isViewable()) {
|
|
return $this->model;
|
|
}
|
|
|
|
return parent::imageSource($query);
|
|
}
|
|
|
|
/**
|
|
* Returns an array of all actions
|
|
* that can be performed in the Panel
|
|
*
|
|
* @param array $unlock An array of options that will be force-unlocked
|
|
* @return array
|
|
*/
|
|
public function options(array $unlock = []): array
|
|
{
|
|
$options = parent::options($unlock);
|
|
|
|
try {
|
|
// check if the file type is allowed at all,
|
|
// otherwise it cannot be replaced
|
|
$this->model->match($this->model->blueprint()->accept());
|
|
} catch (Throwable $e) {
|
|
$options['replace'] = false;
|
|
}
|
|
|
|
return $options;
|
|
}
|
|
|
|
/**
|
|
* Returns the full path without leading slash
|
|
*
|
|
* @return string
|
|
*/
|
|
public function path(): string
|
|
{
|
|
return 'files/' . $this->model->filename();
|
|
}
|
|
|
|
/**
|
|
* Prepares the response data for file pickers
|
|
* and file fields
|
|
*
|
|
* @param array|null $params
|
|
* @return array
|
|
*/
|
|
public function pickerData(array $params = []): array
|
|
{
|
|
$id = $this->model->id();
|
|
$name = $this->model->filename();
|
|
|
|
if (empty($params['model']) === false) {
|
|
$parent = $this->model->parent();
|
|
$uuid = $parent === $params['model'] ? $name : $id;
|
|
$absolute = $parent !== $params['model'];
|
|
}
|
|
|
|
$params['text'] ??= '{{ file.filename }}';
|
|
|
|
return array_merge(parent::pickerData($params), [
|
|
'filename' => $name,
|
|
'dragText' => $this->dragText('auto', $absolute ?? false),
|
|
'type' => $this->model->type(),
|
|
'url' => $this->model->url(),
|
|
'uuid' => $uuid ?? $id,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* Returns the data array for the
|
|
* view's component props
|
|
*
|
|
* @internal
|
|
*
|
|
* @return array
|
|
*/
|
|
public function props(): array
|
|
{
|
|
$file = $this->model;
|
|
$dimensions = $file->dimensions();
|
|
$siblings = $file->templateSiblings()->sortBy(
|
|
'sort',
|
|
'asc',
|
|
'filename',
|
|
'asc'
|
|
);
|
|
|
|
|
|
return array_merge(
|
|
parent::props(),
|
|
$this->prevNext(),
|
|
[
|
|
'blueprint' => $this->model->template() ?? 'default',
|
|
'model' => [
|
|
'content' => $this->content(),
|
|
'dimensions' => $dimensions->toArray(),
|
|
'extension' => $file->extension(),
|
|
'filename' => $file->filename(),
|
|
'link' => $this->url(true),
|
|
'mime' => $file->mime(),
|
|
'niceSize' => $file->niceSize(),
|
|
'id' => $id = $file->id(),
|
|
'parent' => $file->parent()->panel()->path(),
|
|
'template' => $file->template(),
|
|
'type' => $file->type(),
|
|
'url' => $file->url(),
|
|
],
|
|
'preview' => [
|
|
'image' => $this->image([
|
|
'back' => 'transparent',
|
|
'ratio' => '1/1'
|
|
], 'cards'),
|
|
'url' => $url = $file->previewUrl(),
|
|
'details' => [
|
|
[
|
|
'title' => I18n::translate('template'),
|
|
'text' => $file->template() ?? '—'
|
|
],
|
|
[
|
|
'title' => I18n::translate('mime'),
|
|
'text' => $file->mime()
|
|
],
|
|
[
|
|
'title' => I18n::translate('url'),
|
|
'text' => $id,
|
|
'link' => $url
|
|
],
|
|
[
|
|
'title' => I18n::translate('size'),
|
|
'text' => $file->niceSize()
|
|
],
|
|
[
|
|
'title' => I18n::translate('dimensions'),
|
|
'text' => $file->type() === 'image' ? $file->dimensions() . ' ' . I18n::translate('pixel') : '—'
|
|
],
|
|
[
|
|
'title' => I18n::translate('orientation'),
|
|
'text' => $file->type() === 'image' ? I18n::translate('orientation.' . $dimensions->orientation()) : '—'
|
|
],
|
|
]
|
|
]
|
|
]
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Returns navigation array with
|
|
* previous and next file
|
|
*
|
|
* @internal
|
|
*
|
|
* @return array
|
|
*/
|
|
public function prevNext(): array
|
|
{
|
|
$file = $this->model;
|
|
$siblings = $file->templateSiblings()->sortBy(
|
|
'sort',
|
|
'asc',
|
|
'filename',
|
|
'asc'
|
|
);
|
|
|
|
return [
|
|
'next' => function () use ($file, $siblings): ?array {
|
|
$next = $siblings->nth($siblings->indexOf($file) + 1);
|
|
return $this->toPrevNextLink($next, 'filename');
|
|
},
|
|
'prev' => function () use ($file, $siblings): ?array {
|
|
$prev = $siblings->nth($siblings->indexOf($file) - 1);
|
|
return $this->toPrevNextLink($prev, 'filename');
|
|
}
|
|
];
|
|
}
|
|
/**
|
|
* Returns the url to the editing view
|
|
* in the panel
|
|
*
|
|
* @param bool $relative
|
|
* @return string
|
|
*/
|
|
public function url(bool $relative = false): string
|
|
{
|
|
$parent = $this->model->parent()->panel()->url($relative);
|
|
return $parent . '/' . $this->path();
|
|
}
|
|
|
|
/**
|
|
* Returns the data array for
|
|
* this model's Panel view
|
|
*
|
|
* @internal
|
|
*
|
|
* @return array
|
|
*/
|
|
public function view(): array
|
|
{
|
|
$file = $this->model;
|
|
|
|
return [
|
|
'breadcrumb' => fn (): array => $file->panel()->breadcrumb(),
|
|
'component' => 'k-file-view',
|
|
'props' => $this->props(),
|
|
'search' => 'files',
|
|
'title' => $file->filename(),
|
|
];
|
|
}
|
|
}
|