Improve Pages and Files management in the panel

This commit is contained in:
Giuseppe Criscione 2024-05-12 19:36:30 +02:00
parent 024448f1af
commit d9a0f08203
39 changed files with 837 additions and 70 deletions

View File

@ -40,14 +40,7 @@ fields:
file: '${%SYSTEM_PATH%}/fields/dynamic/vars.php'
files:
allowedExtensions:
- .jpg
- .jpeg
- .png
- .gif
- .svg
- .webp
- .pdf
allowedExtensions: []
images:
jpegQuality: 85

View File

@ -3,6 +3,7 @@
use Formwork\App;
use Formwork\Languages\LanguageCodes;
use Formwork\Panel\Utils\DateFormats;
use Formwork\Utils\MimeType;
return function (App $app) {
return [
@ -19,5 +20,9 @@ return function (App $app) {
'languages' => [
'names' => LanguageCodes::names(),
],
'mimeTypes' => [
'extensionTypes' => MimeType::extensionTypes(),
],
];
};

View File

@ -80,6 +80,7 @@ fields:
type: tags
label: '{{panel.options.system.files.allowedExtensions}}'
pattern: '^\.[a-zA-Z0-9]+$'
options@: mimeTypes.extensionTypes
cache.enabled:
type: togglegroup

View File

@ -2,17 +2,18 @@
namespace Formwork\Files;
use Formwork\Config\Config;
use Formwork\Exceptions\TranslatedException;
use Formwork\Http\Files\UploadedFile;
use Formwork\Utils\Arr;
use Formwork\Utils\FileSystem;
use Formwork\Utils\MimeType;
use Formwork\Utils\Str;
class FileUploader
{
public function __construct(protected Config $config)
/**
* @param list<string> $allowedMimeTypes
*/
public function __construct(protected array $allowedMimeTypes)
{
}
@ -21,20 +22,20 @@ class FileUploader
*/
public function allowedMimeTypes(): array
{
return Arr::map($this->config->get('system.files.allowedExtensions'), fn (string $ext) => MimeType::fromExtension($ext));
return $this->allowedMimeTypes;
}
public function upload(UploadedFile $uploadedFile, string $destinationPath, ?string $name = null): File
public function upload(UploadedFile $uploadedFile, string $destinationPath, ?string $name = null, bool $overwrite = false): File
{
$mimeType = MimeType::fromFile($uploadedFile->tempPath());
if (!in_array($mimeType, $this->allowedMimeTypes(), true)) {
if (!in_array($mimeType, $this->allowedMimeTypes, true)) {
throw new TranslatedException(sprintf('Invalid mime type %s for file uploads', $mimeType), 'upload.error.mimeType');
}
$filename = Str::slug($name ?? pathinfo($uploadedFile->clientName(), PATHINFO_FILENAME)) . '.' . MimeType::toExtension($mimeType);
$uploadedFile->move($destinationPath, $filename);
$uploadedFile->move($destinationPath, $filename, $overwrite);
return new File(FileSystem::joinPaths($destinationPath, $filename));
}

View File

@ -3,6 +3,7 @@
namespace Formwork\Images\Exif;
use Formwork\Data\Contracts\Arrayable;
use Formwork\Utils\Str;
use Generator;
class ExifData implements Arrayable
@ -77,4 +78,114 @@ class ExifData implements Arrayable
? $this->tags[$key][1] ?? $this->tags[$key][0]
: $default;
}
public function hasPositionData(): bool
{
return $this->hasMultiple(['GPSLatitude', 'GPSLongitude']);
}
public function dateTimeOriginal(): ?ExifDateTime
{
/** @var ExifDateTime|null */
return $this->get('DateTimeOriginal');
}
public function makeAndModel(): ?string
{
$make = (string) $this->get('Make');
$model = (string) $this->get('Model');
if ($model === '') {
return $make ?: null;
}
return $make . ' ' . Str::after($model, $make . ' ');
}
public function lensModel(): ?string
{
return $this->get('LensModel') ? str_replace('f/', 'ƒ/', (string) $this->get('LensModel')) : null;
}
public function focalLength(): ?string
{
return $this->get('FocalLength') ? $this->get('FocalLength') . ' mm' : null;
}
public function exposureTime(): ?string
{
return $this->get('ExposureTime') ? $this->get('ExposureTime') . ' s' : null;
}
public function aperture(): ?string
{
return $this->get('FNumber') ? 'ƒ/' . $this->get('FNumber') : null;
}
public function photographicSensitivity(): ?string
{
return $this->get('PhotographicSensitivity') ? 'ISO ' . $this->get('PhotographicSensitivity') : null;
}
public function exposureCompensation(): ?string
{
/** @var float|null */
$compensation = $this->get('ExposureBiasValue');
return $compensation ? round($compensation, 2) . ' EV' : null;
}
public function exposureProgram(): ?string
{
/** @var int */
$exposureProgram = $this->getRaw('ExposureProgram', 0);
if ($exposureProgram < 0) {
return null;
}
return match ($exposureProgram) {
2 => 'P',
3 => 'A',
4 => 'S',
1 => 'M',
default => 'AUTO',
};
}
public function hasAutoWhiteBalance(): ?bool
{
return $this->has('WhiteBalance') ? $this->getRaw('WhiteBalance') === 0 : null;
}
public function hasFlashFired(): ?bool
{
return $this->has('Flash') ? (bool) ($this->getRaw('Flash') % 2) : null;
}
/**
* @return 'average'|'evaluative'|'partial'|'spot'|null
*/
public function meteringMode(): ?string
{
/** @var int|null */
$meteringMode = $this->getRaw('MeteringMode');
if ($meteringMode === null) {
return null;
}
if ($meteringMode <= 2 || $meteringMode > 6) {
return 'average';
}
if ($meteringMode === 3) {
return 'spot';
}
if ($meteringMode === 4 || $meteringMode == 5) {
return 'evaluative';
}
return 'partial';
}
public function colorSpace(): ?string
{
return $this->get('ColorSpace');
}
}

View File

@ -354,10 +354,8 @@ class Image extends File
{
return [
...parent::toArray(),
'imageInfo' => $this->info()->toArray(),
'exif' => $this->getExifData()?->toArray(),
'colorProfile' => $this->getColorProfile()?->name(),
'uri' => $this->uri(),
'imageInfo' => $this->info()->toArray(),
'uri' => $this->uri(),
];
}

View File

@ -587,8 +587,7 @@ class Page extends Model implements Stringable
'preferred' => $site->languages()->preferred(),
]);
$this->files ??= new FileCollection($files);
$this->files->sortBy('path');
$this->files ??= (new FileCollection($files))->sort();
$this->data = [...$this->defaults(), ...$this->data];
}

View File

@ -21,6 +21,7 @@ use Formwork\Router\RouteParams;
use Formwork\Utils\Arr;
use Formwork\Utils\Date;
use Formwork\Utils\FileSystem;
use Formwork\Utils\MimeType;
use Formwork\Utils\Str;
use Formwork\Utils\Uri;
use RuntimeException;
@ -191,12 +192,8 @@ class PagesController extends AbstractController
throw new UnexpectedValueException('Unexpected missing page route');
}
// Redirect if page route has changed
if ($routeParams->get('page') !== ($route = trim($page->route(), '/'))) {
return $this->redirect($this->generateRoute('panel.pages.edit', ['page' => $route]));
}
break;
// Redirect to avoid ERR_CACHE_MISS
return $this->redirect($this->generateRoute('panel.pages.edit', ['page' => $page->route()]));
}
$this->modal('changes');
@ -394,31 +391,97 @@ class PagesController extends AbstractController
if ($newName !== $previousName) {
if ($page->files()->has($newName)) {
$this->panel()->notify($this->translate('panel.pages.page.cannotRenameFile.fileAlreadyExists'), 'error');
return $this->redirect($this->generateRoute('panel.pages.edit', ['page' => $routeParams->get('page')]));
} else {
FileSystem::move($page->path() . $previousName, $page->path() . $newName);
$this->panel()->notify($this->translate('panel.pages.page.fileRenamed'), 'success');
}
}
FileSystem::move($page->path() . $previousName, $page->path() . $newName);
$this->panel()->notify($this->translate('panel.pages.page.fileRenamed'), 'success');
$previousFileRoute = $this->generateRoute('panel.pages.file', ['page' => $routeParams->get('page'), 'filename' => $previousName]);
if (Str::removeEnd((string) Uri::path($request->referer()), '/') === $this->site()->uri($previousFileRoute)) {
return $this->redirect($this->generateRoute('panel.pages.file', ['page' => $routeParams->get('page'), 'filename' => $newName]));
}
return $this->redirect($this->generateRoute('panel.pages.edit', ['page' => $routeParams->get('page')]));
}
public function getFileInfo(RouteParams $routeParams): JsonResponse
/**
* Pages@replaceFile action
*/
public function replaceFile(RouteParams $routeParams): RedirectResponse
{
$this->ensurePermission('pages.getFileInfo');
$this->ensurePermission('pages.replaceFiles');
$page = $this->site()->findPage($routeParams->get('page'));
$filename = $routeParams->get('filename');
if ($page === null) {
return JsonResponse::error($this->translate('panel.pages.page.cannotRenameFile.pageNotFound'));
$this->panel()->notify($this->translate('panel.pages.page.cannotReplaceFile.pageNotFound'), 'error');
return $this->redirectToReferer(default: '/pages/');
}
if (!$page->files()->has($routeParams->get('filename'))) {
return JsonResponse::error($this->translate('panel.pages.page.cannotRenameFile.fileNotFound'));
if (!$page->files()->has($filename)) {
$this->panel()->notify($this->translate('panel.pages.page.cannotReplaceFile.fileNotFound'), 'error');
return $this->redirectToReferer(default: '/pages/');
}
return JsonResponse::success('Yes!', data: $page->files()->get($routeParams->get('filename'))->toArray());
if (!$this->request->files()->isEmpty()) {
$files = $this->request->files()->getAll();
if (count($files) > 1) {
$this->panel()->notify($this->translate('panel.pages.page.cannotReplaceFile.multipleFiles'), 'error');
return $this->redirectToReferer(default: '/pages/');
}
try {
$this->processPageUploads($this->request->files()->getAll(), $page, [$page->files()->get($filename)->mimeType()], FileSystem::name($filename), true);
} catch (TranslatedException $e) {
$this->panel()->notify($this->translate('upload.error', $e->getTranslatedMessage()), 'error');
return $this->redirect($this->generateRoute('panel.pages.edit', ['page' => $routeParams->get('page')]));
}
}
$this->panel()->notify($this->translate('panel.uploader.uploaded'), 'success');
return $this->redirectToReferer(default: '/pages/');
}
/**
* Pages@file action
*/
public function file(RouteParams $routeParams): Response
{
$this->ensurePermission('pages.file');
$page = $this->site()->findPage($routeParams->get('page'));
$filename = $routeParams->get('filename');
if ($page === null) {
$this->panel()->notify($this->translate('panel.pages.page.cannotReplaceFile.pageNotFound'), 'error');
return $this->redirectToReferer(default: '/pages/');
}
if (!$page->files()->has($filename)) {
$this->panel()->notify($this->translate('panel.pages.page.cannotReplaceFile.fileNotFound'), 'error');
return $this->redirect($this->generateRoute('panel.pages.edit', ['page' => $routeParams->get('page')]));
}
$files = $page->files();
$file = $files->get($filename);
$fileIndex = $files->indexOf($file);
$this->modal('renameFile');
$this->modal('deleteFile');
return new Response($this->view('pages.file', [
'title' => $this->translate('panel.pages.editPage', $page->title()),
'page' => $page,
'file' => $file,
'previousFile' => $files->nth($fileIndex - 1),
'nextFile' => $files->nth($fileIndex + 1),
]));
}
/**
@ -616,10 +679,13 @@ class PagesController extends AbstractController
* Process page uploads
*
* @param array<UploadedFile> $files
* @param list<string> $mimeTypes
*/
protected function processPageUploads(array $files, Page $page): void
protected function processPageUploads(array $files, Page $page, ?array $mimeTypes = null, ?string $name = null, bool $overwrite = false): void
{
$fileUploader = new FileUploader($this->config);
$mimeTypes ??= Arr::map($this->config->get('system.files.allowedExtensions'), fn (string $ext) => MimeType::fromExtension($ext));
$fileUploader = new FileUploader($mimeTypes);
foreach ($files as $file) {
if (!$file->isUploaded()) {
@ -628,7 +694,7 @@ class PagesController extends AbstractController
if ($page->path() === null) {
throw new UnexpectedValueException('Unexpected missing page path');
}
$uploadedFile = $fileUploader->upload($file, $page->path());
$uploadedFile = $fileUploader->upload($file, $page->path(), $name, $overwrite);
// Process JPEG and PNG images according to system options (e.g. quality)
if ($this->config->get('system.uploads.processImages') && in_array($uploadedFile->mimeType(), ['image/jpeg', 'image/png'], true)) {
$image = new Image($uploadedFile->path(), $this->config->get('system.images'));

View File

@ -14,7 +14,9 @@ use Formwork\Panel\Security\Password;
use Formwork\Panel\Users\User;
use Formwork\Parsers\Yaml;
use Formwork\Router\RouteParams;
use Formwork\Utils\Arr;
use Formwork\Utils\FileSystem;
use Formwork\Utils\MimeType;
use RuntimeException;
class UsersController extends AbstractController
@ -205,7 +207,9 @@ class UsersController extends AbstractController
{
$imagesPath = FileSystem::joinPaths($this->config->get('system.panel.paths.assets'), '/images/users/');
$fileUploader = new FileUploader($this->config);
$mimeTypes = Arr::map($this->config->get('system.files.allowedExtensions'), fn (string $ext) => MimeType::fromExtension($ext));
$fileUploader = new FileUploader($mimeTypes);
$uploadedFile = $fileUploader->upload($file, $imagesPath, FileSystem::randomName());

View File

@ -179,4 +179,12 @@ class MimeType
{
return static::getAssociatedExtensions($mimeType)[0] ?? null;
}
/**
* @return array<string, string>
*/
public static function extensionTypes(): array
{
return Arr::mapKeys(Arr::map(self::MIME_TYPES, fn ($value, $key) => sprintf('.%s (%s)', $key, $value)), fn ($key) => '.' . $key);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
<svg class="icon" width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><g clip-path="url(#arrow-left-circle__a)"><path d="M6.146 4.854A.5.5 0 0 1 7 5.207v5.586a.5.5 0 0 1-.854.353L3.354 8.354a.5.5 0 0 1 0-.708l2.792-2.792Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M12.75 8a.75.75 0 0 0-.75-.75H7a.75.75 0 0 0 0 1.5h5a.75.75 0 0 0 .75-.75Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M8 1.5a6.5 6.5 0 1 1 0 13 6.5 6.5 0 0 1 0-13ZM16 8A8 8 0 1 0 0 8a8 8 0 0 0 16 0Z"/></g><defs><clipPath id="arrow-left-circle__a"><path d="M16 0H0v16h16z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 590 B

View File

@ -0,0 +1 @@
<svg class="icon" width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M8.75 9h2.043a.5.5 0 0 1 .353.854l-2.792 2.792a.5.5 0 0 1-.708 0L4.854 9.854A.5.5 0 0 1 5.207 9H7.25V5a.75.75 0 0 1 1.5 0v4Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M3.5 0A1.5 1.5 0 0 0 2 1.5v13A1.5 1.5 0 0 0 3.5 16h9a1.5 1.5 0 0 0 1.5-1.5v-13A1.5 1.5 0 0 0 12.5 0h-9Zm9 1.5h-9v13h9v-13Z"/></svg>

After

Width:  |  Height:  |  Size: 398 B

View File

@ -0,0 +1 @@
<svg class="icon" width="16" height="16" viewBox="0 0 16 16" fill="currentColor"><path d="M8.75 8h2.043a.5.5 0 0 0 .353-.854L8.354 4.354a.5.5 0 0 0-.708 0L4.854 7.146A.5.5 0 0 0 5.207 8H7.25v4a.75.75 0 0 0 1.5 0V8Z"/><path fill-rule="evenodd" clip-rule="evenodd" d="M3.5 0A1.5 1.5 0 0 0 2 1.5v13A1.5 1.5 0 0 0 3.5 16h9a1.5 1.5 0 0 0 1.5-1.5v-13A1.5 1.5 0 0 0 12.5 0h-9Zm9 1.5h-9v13h9v-13Z"/></svg>

After

Width:  |  Height:  |  Size: 398 B

View File

@ -0,0 +1 @@
<svg class="icon" xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16"><path fill-rule="evenodd" d="M9.328 2.625A9.395 9.395 0 0 1 9.22 3a8.082 8.082 0 0 1-1.127 2.33c-.547.766-1.207 1.356-1.934 1.728l-.926.475a.4.4 0 0 0-.17.181.643.643 0 0 0-.064.286c0 .101.022.201.064.285a.4.4 0 0 0 .17.181l.926.475c.727.372 1.387.962 1.934 1.727a8.08 8.08 0 0 1 1.127 2.33c.038.125.074.25.107.377l.339 1.297c.025.096.07.178.13.237s.13.09.203.09a.291.291 0 0 0 .204-.09.512.512 0 0 0 .13-.237l.339-1.296c.033-.128.069-.253.107-.377a8.08 8.08 0 0 1 1.127-2.33c.547-.766 1.207-1.356 1.933-1.728l.926-.475a.4.4 0 0 0 .17-.181A.643.643 0 0 0 15 8a.643.643 0 0 0-.064-.286.4.4 0 0 0-.17-.181l-.926-.475c-.726-.372-1.386-.962-1.933-1.727a8.08 8.08 0 0 1-1.127-2.33 9.378 9.378 0 0 1-.107-.377l-.34-1.298a.511.511 0 0 0-.129-.237A.291.291 0 0 0 10 1a.291.291 0 0 0-.203.09.511.511 0 0 0-.13.237l-.34 1.298ZM10 5.07c.203.398.432.778.686 1.133a7.28 7.28 0 0 0 1.809 1.798 7.279 7.279 0 0 0-1.809 1.797A8.874 8.874 0 0 0 10 10.93a8.89 8.89 0 0 0-.685-1.133A7.28 7.28 0 0 0 7.506 8a7.28 7.28 0 0 0 1.809-1.798A8.88 8.88 0 0 0 10 5.069Z" clip-rule="evenodd"/><path d="M2.867 2.13a.204.204 0 0 1 .052-.094A.116.116 0 0 1 3 2c.03 0 .058.013.082.036a.205.205 0 0 1 .052.095l.135.519a3.3 3.3 0 0 0 .494 1.083c.219.306.482.542.773.69l.37.19a.16.16 0 0 1 .068.073A.257.257 0 0 1 5 4.8c0 .041-.009.08-.026.114a.16.16 0 0 1-.067.073l-.37.19a2.19 2.19 0 0 0-.774.69 3.3 3.3 0 0 0-.494 1.084l-.135.518a.205.205 0 0 1-.052.095A.116.116 0 0 1 3 7.6a.116.116 0 0 1-.081-.036.204.204 0 0 1-.052-.095l-.136-.518a3.3 3.3 0 0 0-.493-1.083 2.196 2.196 0 0 0-.774-.691l-.37-.19a.16.16 0 0 1-.068-.073A.257.257 0 0 1 1 4.8c0-.04.009-.08.026-.114a.16.16 0 0 1 .067-.073l.371-.19c.29-.148.555-.384.774-.69A3.3 3.3 0 0 0 2.73 2.65l.136-.52Zm1.536 7.351a.205.205 0 0 1 .052-.094.116.116 0 0 1 .081-.036c.03 0 .058.012.082.036a.205.205 0 0 1 .052.094l.135.52a3.3 3.3 0 0 0 .494 1.082c.219.307.483.542.773.691l.37.19a.16.16 0 0 1 .068.073.257.257 0 0 1 .026.114c0 .04-.009.08-.026.114a.16.16 0 0 1-.067.072l-.37.19c-.291.15-.555.385-.774.691a3.299 3.299 0 0 0-.494 1.083l-.135.519a.204.204 0 0 1-.052.095.117.117 0 0 1-.082.036.117.117 0 0 1-.081-.036.204.204 0 0 1-.052-.095l-.136-.519a3.299 3.299 0 0 0-.493-1.083 2.195 2.195 0 0 0-.774-.69l-.37-.19a.16.16 0 0 1-.068-.073.257.257 0 0 1-.026-.114c0-.041.01-.08.026-.114a.16.16 0 0 1 .068-.073l.37-.19c.29-.149.555-.384.774-.69A3.3 3.3 0 0 0 4.267 10l.136-.519Z"/><path fill-rule="evenodd" d="M4.848 10.152c-.015-.05-.03-.1-.043-.152l-.135-.519a.205.205 0 0 0-.052-.094.116.116 0 0 0-.082-.036.116.116 0 0 0-.081.036.205.205 0 0 0-.052.094l-.136.52a3.783 3.783 0 0 1-.084.277 3.38 3.38 0 0 1-.193.451 2.938 2.938 0 0 1-.216.354 2.387 2.387 0 0 1-.485.508c-.093.071-.19.132-.289.183l-.37.19a.16.16 0 0 0-.068.073.257.257 0 0 0-.026.114c0 .04.01.08.026.114a.16.16 0 0 0 .068.072l.37.19a1.907 1.907 0 0 1 .32.207c.165.132.318.295.454.484.078.11.15.229.216.354a3.386 3.386 0 0 1 .277.73l.136.518c.01.038.028.071.052.095a.117.117 0 0 0 .081.036c.03 0 .058-.013.082-.036a.204.204 0 0 0 .052-.095l.135-.519a3.783 3.783 0 0 1 .085-.278 3.38 3.38 0 0 1 .193-.451c.065-.125.137-.243.216-.354a2.387 2.387 0 0 1 .485-.508c.092-.07.189-.132.288-.183l.37-.19a.16.16 0 0 0 .068-.072.257.257 0 0 0 .026-.114.255.255 0 0 0-.026-.114.16.16 0 0 0-.067-.073l-.37-.19a1.91 1.91 0 0 1-.32-.207 2.386 2.386 0 0 1-.454-.484 2.938 2.938 0 0 1-.216-.354 3.38 3.38 0 0 1-.235-.577Z" clip-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

File diff suppressed because one or more lines are too long

View File

@ -144,6 +144,18 @@ return [
'methods' => ['POST'],
],
'panel.pages.replaceFile' => [
'path' => '/pages/{page}/file/{filename}/replace/',
'action' => 'Formwork\Panel\Controllers\PagesController@replaceFile',
'methods' => ['POST'],
],
'panel.pages.file' => [
'path' => '/pages/{page}/file/{filename}/',
'action' => 'Formwork\Panel\Controllers\PagesController@file',
'methods' => ['GET'],
],
'panel.pages.delete' => [
'path' => '/pages/{page}/delete/',
'action' => 'Formwork\Panel\Controllers\PagesController@delete',

View File

@ -78,3 +78,11 @@ pre {
::placeholder {
color: $color-base-300;
}
.link-secondary {
color: $color-base-300;
&:hover {
color: $color-base-200;
}
}

View File

@ -116,3 +116,15 @@
}
}
}
@mixin checkbox-background($size, $color) {
$half: $size * 0.5;
background-image: linear-gradient(45deg, $color 25%, transparent 25%), linear-gradient(-45deg, $color 25%, transparent 25%), linear-gradient(45deg, transparent 75%, $color 75%), linear-gradient(-45deg, transparent 75%, $color 75%);
background-position:
0 0,
0 $half,
$half (-$half),
(-$half) 0;
background-size: $size $size;
}

View File

@ -106,3 +106,28 @@
.pages-tree.is-filtered .pages-tree-item .page-details {
padding-left: 0;
}
.page-file-preview-container {
display: flex;
justify-content: center;
background-color: $color-base-600;
}
.page-file-preview-link {
cursor: zoom-in;
line-height: 0;
}
.page-file-preview-image {
max-height: 40.5rem;
object-fit: contain;
@include checkbox-background(1.5rem, rgba($color-black, 0.125));
}
.page-file-info-entry-title {
font-weight: 600;
}
.page-file-info-entry-uri {
word-break: break-word;
}

View File

@ -22,10 +22,10 @@ export class Files {
});
}
$$("video.file-thumbnail", filesList).forEach((video: HTMLVideoElement) => {
video.addEventListener("click", () => {
if (!video.controls) {
video.controls = true;
$$(".files-item", filesList).forEach((item: HTMLElement) => {
item.addEventListener("click", (event) => {
if (!(event.target as HTMLElement).closest(".dropdown") && typeof item.dataset.href === "string") {
location.href = item.dataset.href;
}
});
});

View File

@ -224,6 +224,34 @@ export class Pages {
});
});
$$("[data-command=replaceFile]").forEach((element) => {
element.addEventListener("click", () => {
const form = document.createElement("form");
form.hidden = true;
form.action = element.dataset.action as string;
form.method = "post";
form.enctype = "multipart/form-data";
const fileInput = document.createElement("input");
fileInput.name = "file";
fileInput.type = "file";
fileInput.accept = element.dataset.extension as string;
form.appendChild(fileInput);
const csrfInput = document.createElement("input");
csrfInput.name = "csrf-token";
csrfInput.value = ($("meta[name=csrf-token]") as HTMLMetaElement).content;
form.appendChild(csrfInput);
fileInput.click();
fileInput.addEventListener("change", () => {
document.body.appendChild(form);
form.submit();
});
});
});
function expandAllPages() {
$$(".pages-tree-item").forEach((element) => {
element.classList.add("is-expanded");

View File

@ -135,6 +135,38 @@ panel.pages.editor.redo: Wiederholen
panel.pages.editor.summary: Zusammenfassung
panel.pages.editor.undo: Rückgängig
panel.pages.editPage: Seite bearbeiten %s
panel.pages.file.backToPage: Zurück zur Seite
panel.pages.file.exif: EXIF
panel.pages.file.info: Info
panel.pages.file.info.image.colorDepth: Farbtiefe
panel.pages.file.info.image.colorNumber: Anzahl der Farben
panel.pages.file.info.image.colorProfile: Farbprofil
panel.pages.file.info.image.colorSpace: Farbraum
panel.pages.file.info.image.dimensions: Abmessungen
panel.pages.file.info.image.dimensions.widthByHeightPixels: '%d × %d Pixel'
panel.pages.file.info.image.exif.aperture: Blende
panel.pages.file.info.image.exif.camera: Kamera
panel.pages.file.info.image.exif.creationDateAndTime: Erstellungsdatum und -zeit
panel.pages.file.info.image.exif.exposureCompensation: Belichtungskorrektur
panel.pages.file.info.image.exif.exposureProgram: Belichtungsprogramm
panel.pages.file.info.image.exif.exposureTime: Belichtungszeit
panel.pages.file.info.image.exif.flash: Blitz
panel.pages.file.info.image.exif.focalLength: Brennweite
panel.pages.file.info.image.exif.lensModel: Objektivmodell
panel.pages.file.info.image.exif.meteringMode: Belichtungsmessmethode
panel.pages.file.info.image.exif.sensitivity: Empfindlichkeit
panel.pages.file.info.image.exif.whiteBalance: Weißabgleich
panel.pages.file.info.image.frames: '%d Frames'
panel.pages.file.info.image.framesCount: Anzahl der Frames
panel.pages.file.info.image.repeats: '%d Wiederholungen'
panel.pages.file.info.image.repeatsCount: Anzahl der Wiederholungen
panel.pages.file.info.image.resolution: Auflösung
panel.pages.file.info.lastModifiedTime: Letzte Änderungszeit
panel.pages.file.info.mimeType: MIME-Typ
panel.pages.file.info.size: Größe
panel.pages.file.info.uri: URI
panel.pages.file.position: Position
panel.pages.file.preview: Vorschau
panel.pages.files: Dateien
panel.pages.languages: Sprachen
panel.pages.languages.addLanguage: "%s hinzufügen"
@ -146,6 +178,8 @@ panel.pages.newPage.slug: Seiten-Slug
panel.pages.newPage.slugSuggestion: Nur Buchstaben, Zahlen und Bindestriche
panel.pages.newPage.template: Vorlage
panel.pages.newPage.title: Titel
panel.pages.next: Nächste Seite
panel.pages.nextFile: Nächste Datei
panel.pages.options: Optionen
panel.pages.page: Seite
panel.pages.page.actions: Aktionen
@ -174,6 +208,9 @@ panel.pages.page.cannotMove: Seite kann nicht verschoben werden
panel.pages.page.cannotRenameFile.fileAlreadyExists: Datei kann nicht umbenannt werden, eine Datei mit demselben Namen existiert bereits
panel.pages.page.cannotRenameFile.fileNotFound: Datei kann nicht umbenannt werden, Datei nicht gefunden
panel.pages.page.cannotRenameFile.pageNotFound: Datei kann nicht umbenannt werden, Seite nicht gefunden
panel.pages.page.cannotReplaceFile.fileNotFound: Datei kann nicht ersetzt werden, Datei nicht gefunden
panel.pages.page.cannotReplaceFile.multipleFiles: Datei kann nicht ersetzt werden, mehrere Dateien angegeben
panel.pages.page.cannotReplaceFile.pageNotFound: Datei kann nicht ersetzt werden, Seite nicht gefunden
panel.pages.page.cannotUploadFile.pageNotFound: Datei kann nicht hochgeladen werden, Seite nicht gefunden
panel.pages.page.created: Seite erstellt!
panel.pages.page.deleted: Seite gelöscht
@ -202,8 +239,11 @@ panel.pages.pages.search: Seiten durchsuchen...
panel.pages.parent: Übergeordnete Seite
panel.pages.preview: Vorschau
panel.pages.previewFile: Vorschau
panel.pages.previous: Vorherige Seite
panel.pages.previousFile: Vorherige Datei
panel.pages.renameFile: Datei umbenennen
panel.pages.renameFile.name: Name
panel.pages.replaceFile: Datei ersetzen
panel.pages.save: Speichern
panel.pages.status.notPublished: Nicht veröffentlicht
panel.pages.status.notRoutable: Nicht routbar

View File

@ -135,6 +135,38 @@ panel.pages.editor.redo: Redo
panel.pages.editor.summary: Summary
panel.pages.editor.undo: Undo
panel.pages.editPage: Edit Page %s
panel.pages.file.backToPage: Back to Page
panel.pages.file.exif: EXIF
panel.pages.file.info: Info
panel.pages.file.info.image.colorDepth: Color Depth
panel.pages.file.info.image.colorNumber: Color Number
panel.pages.file.info.image.colorProfile: Color Profile
panel.pages.file.info.image.colorSpace: Color Space
panel.pages.file.info.image.dimensions: Dimensions
panel.pages.file.info.image.dimensions.widthByHeightPixels: '%d × %d pixels'
panel.pages.file.info.image.exif.aperture: Aperture
panel.pages.file.info.image.exif.camera: Camera
panel.pages.file.info.image.exif.creationDateAndTime: Creation Date and Time
panel.pages.file.info.image.exif.exposureCompensation: Exposure Compensation
panel.pages.file.info.image.exif.exposureProgram: Exposure Program
panel.pages.file.info.image.exif.exposureTime: Exposure Time
panel.pages.file.info.image.exif.flash: Flash
panel.pages.file.info.image.exif.focalLength: Focal Length
panel.pages.file.info.image.exif.lensModel: Lens Model
panel.pages.file.info.image.exif.meteringMode: Metering Mode
panel.pages.file.info.image.exif.sensitivity: Sensitivity
panel.pages.file.info.image.exif.whiteBalance: White Balance
panel.pages.file.info.image.frames: '%d frames'
panel.pages.file.info.image.framesCount: Frames Count
panel.pages.file.info.image.repeats: '%d repeats'
panel.pages.file.info.image.repeatsCount: Repeats Count
panel.pages.file.info.image.resolution: Resolution
panel.pages.file.info.lastModifiedTime: Last Modified Time
panel.pages.file.info.mimeType: MIME Type
panel.pages.file.info.size: Size
panel.pages.file.info.uri: URI
panel.pages.file.position: Position
panel.pages.file.preview: Preview
panel.pages.files: Files
panel.pages.languages: Languages
panel.pages.languages.addLanguage: Add %s
@ -146,6 +178,8 @@ panel.pages.newPage.slug: Page Slug
panel.pages.newPage.slugSuggestion: letters, numbers and dashes only
panel.pages.newPage.template: Template
panel.pages.newPage.title: Title
panel.pages.next: Next Page
panel.pages.nextFile: Next File
panel.pages.options: Options
panel.pages.page: Page
panel.pages.page.actions: Actions
@ -174,6 +208,9 @@ panel.pages.page.cannotMove: Cannot move page
panel.pages.page.cannotRenameFile.fileAlreadyExists: Cannot rename file, a file with the same name already exists
panel.pages.page.cannotRenameFile.fileNotFound: Cannot rename file, file not found
panel.pages.page.cannotRenameFile.pageNotFound: Cannot rename file, page not found
panel.pages.page.cannotReplaceFile.fileNotFound: Cannot replace file, file not found
panel.pages.page.cannotReplaceFile.multipleFiles: Cannot replace file, multiple file given
panel.pages.page.cannotReplaceFile.pageNotFound: Cannot replace file, page not found
panel.pages.page.cannotUploadFile.pageNotFound: Cannot upload file, page not found
panel.pages.page.created: Page created!
panel.pages.page.deleted: Page deleted
@ -202,8 +239,11 @@ panel.pages.pages.search: Search Pages...
panel.pages.parent: Parent Page
panel.pages.preview: Preview
panel.pages.previewFile: Preview
panel.pages.previous: Previous Page
panel.pages.previousFile: Previous File
panel.pages.renameFile: Rename File
panel.pages.renameFile.name: Name
panel.pages.replaceFile: Replace File
panel.pages.save: Save
panel.pages.status.notPublished: Not Published
panel.pages.status.notRoutable: Not Routable

View File

@ -135,6 +135,38 @@ panel.pages.editor.redo: Rehacer
panel.pages.editor.summary: Resumen
panel.pages.editor.undo: Deshacer
panel.pages.editPage: Editar página %s
panel.pages.file.backToPage: Volver a la página
panel.pages.file.exif: EXIF
panel.pages.file.info: Información
panel.pages.file.info.image.colorDepth: Profundidad de color
panel.pages.file.info.image.colorNumber: Número de colores
panel.pages.file.info.image.colorProfile: Perfil de color
panel.pages.file.info.image.colorSpace: Espacio de color
panel.pages.file.info.image.dimensions: Dimensiones
panel.pages.file.info.image.dimensions.widthByHeightPixels: '%d × %d píxeles'
panel.pages.file.info.image.exif.aperture: Apertura
panel.pages.file.info.image.exif.camera: Cámara
panel.pages.file.info.image.exif.creationDateAndTime: Fecha y hora de creación
panel.pages.file.info.image.exif.exposureCompensation: Compensación de exposición
panel.pages.file.info.image.exif.exposureProgram: Programa de exposición
panel.pages.file.info.image.exif.exposureTime: Tiempo de exposición
panel.pages.file.info.image.exif.flash: Flash
panel.pages.file.info.image.exif.focalLength: Longitud focal
panel.pages.file.info.image.exif.lensModel: Modelo de lente
panel.pages.file.info.image.exif.meteringMode: Modo de medición
panel.pages.file.info.image.exif.sensitivity: Sensibilidad
panel.pages.file.info.image.exif.whiteBalance: Balance de blancos
panel.pages.file.info.image.frames: '%d frames'
panel.pages.file.info.image.framesCount: Cantidad de frames
panel.pages.file.info.image.repeats: '%d repeticiones'
panel.pages.file.info.image.repeatsCount: Cantidad de repeticiones
panel.pages.file.info.image.resolution: Resolución
panel.pages.file.info.lastModifiedTime: Última modificación
panel.pages.file.info.mimeType: Tipo MIME
panel.pages.file.info.size: Tamaño
panel.pages.file.info.uri: URI
panel.pages.file.position: Posición
panel.pages.file.preview: Vista previa
panel.pages.files: Archivos
panel.pages.languages: Idiomas
panel.pages.languages.addLanguage: Añadir %s
@ -146,6 +178,8 @@ panel.pages.newPage.slug: Slug de la página
panel.pages.newPage.slugSuggestion: solo letras, números y guiones
panel.pages.newPage.template: Plantilla
panel.pages.newPage.title: Título
panel.pages.next: Página siguiente
panel.pages.nextFile: Archivo siguiente
panel.pages.options: Opciones
panel.pages.page: Página
panel.pages.page.actions: Acciones
@ -174,6 +208,9 @@ panel.pages.page.cannotMove: No se puede mover la página
panel.pages.page.cannotRenameFile.fileAlreadyExists: No se puede renombrar el archivo, ya existe un archivo con el mismo nombre
panel.pages.page.cannotRenameFile.fileNotFound: No se puede renombrar el archivo, archivo no encontrado
panel.pages.page.cannotRenameFile.pageNotFound: No se puede renombrar el archivo, página no encontrada
panel.pages.page.cannotReplaceFile.fileNotFound: No se puede reemplazar el archivo, archivo no encontrado
panel.pages.page.cannotReplaceFile.multipleFiles: No se puede reemplazar el archivo, se proporcionaron varios archivos
panel.pages.page.cannotReplaceFile.pageNotFound: No se puede reemplazar el archivo, página no encontrada
panel.pages.page.cannotUploadFile.pageNotFound: No se puede subir el archivo, página no encontrada
panel.pages.page.created: ¡Página creada!
panel.pages.page.deleted: Página eliminada
@ -202,8 +239,11 @@ panel.pages.pages.search: Buscar páginas...
panel.pages.parent: Página principal
panel.pages.preview: Vista previa
panel.pages.previewFile: Vista previa
panel.pages.previous: Página anterior
panel.pages.previousFile: Archivo anterior
panel.pages.renameFile: Renombrar archivo
panel.pages.renameFile.name: Nombre
panel.pages.replaceFile: Reemplazar archivo
panel.pages.save: Guardar
panel.pages.status.notPublished: No publicado
panel.pages.status.notRoutable: No enrutable

View File

@ -135,6 +135,38 @@ panel.pages.editor.redo: Refaire
panel.pages.editor.summary: Résumé
panel.pages.editor.undo: Annuler
panel.pages.editPage: Modifier la page %s
panel.pages.file.backToPage: Retour à la page
panel.pages.file.exif: EXIF
panel.pages.file.info: Info
panel.pages.file.info.image.colorDepth: Profondeur de couleur
panel.pages.file.info.image.colorNumber: Nombre de couleurs
panel.pages.file.info.image.colorProfile: Profil de couleur
panel.pages.file.info.image.colorSpace: Espace de couleur
panel.pages.file.info.image.dimensions: Dimensions
panel.pages.file.info.image.dimensions.widthByHeightPixels: '%d × %d pixels'
panel.pages.file.info.image.exif.aperture: Ouverture
panel.pages.file.info.image.exif.camera: Appareil photo
panel.pages.file.info.image.exif.creationDateAndTime: Date et heure de création
panel.pages.file.info.image.exif.exposureCompensation: Compensation d'exposition
panel.pages.file.info.image.exif.exposureProgram: Programme d'exposition
panel.pages.file.info.image.exif.exposureTime: Temps d'exposition
panel.pages.file.info.image.exif.flash: Flash
panel.pages.file.info.image.exif.focalLength: Longueur focale
panel.pages.file.info.image.exif.lensModel: Modèle d'objectif
panel.pages.file.info.image.exif.meteringMode: Mode de mesure
panel.pages.file.info.image.exif.sensitivity: Sensibilité
panel.pages.file.info.image.exif.whiteBalance: Balance des blancs
panel.pages.file.info.image.frames: '%d trames'
panel.pages.file.info.image.framesCount: Nombre de trames
panel.pages.file.info.image.repeats: '%d répétitions'
panel.pages.file.info.image.repeatsCount: Nombre de répétitions
panel.pages.file.info.image.resolution: Résolution
panel.pages.file.info.lastModifiedTime: Dernière modification
panel.pages.file.info.mimeType: Type MIME
panel.pages.file.info.size: Taille
panel.pages.file.info.uri: URI
panel.pages.file.position: Position
panel.pages.file.preview: Aperçu
panel.pages.files: Fichiers
panel.pages.languages: Langues
panel.pages.languages.addLanguage: Ajouter %s
@ -146,6 +178,8 @@ panel.pages.newPage.slug: Permalien
panel.pages.newPage.slugSuggestion: lettres, chiffres et tirets seulement
panel.pages.newPage.template: Modèle (Template)
panel.pages.newPage.title: Titre
panel.pages.next: Page suivante
panel.pages.nextFile: Fichier suivant
panel.pages.options: Options
panel.pages.page: Page
panel.pages.page.actions: Actions
@ -174,6 +208,9 @@ panel.pages.page.cannotMove: Impossible de déplacer la page
panel.pages.page.cannotRenameFile.fileAlreadyExists: Impossible de renommer le fichier, un fichier portant le même nom existe déjà
panel.pages.page.cannotRenameFile.fileNotFound: Impossible de renommer le fichier, fichier introuvable
panel.pages.page.cannotRenameFile.pageNotFound: Impossible de renommer le fichier, page introuvable
panel.pages.page.cannotReplaceFile.fileNotFound: Impossible de remplacer le fichier, fichier non trouvé
panel.pages.page.cannotReplaceFile.multipleFiles: Impossible de remplacer le fichier, plusieurs fichiers spécifiés
panel.pages.page.cannotReplaceFile.pageNotFound: Impossible de remplacer le fichier, page non trouvée
panel.pages.page.cannotUploadFile.pageNotFound: Impossible de téléverser le fichier, page introuvable
panel.pages.page.created: Page créée !
panel.pages.page.deleted: Page supprimée
@ -202,8 +239,11 @@ panel.pages.pages.search: Rechercher dans les Pages…
panel.pages.parent: Parent
panel.pages.preview: Aperçu
panel.pages.previewFile: Aperçu
panel.pages.previous: Page précédente
panel.pages.previousFile: Fichier précédent
panel.pages.renameFile: Renommer le fichier
panel.pages.renameFile.name: Nom
panel.pages.replaceFile: Remplacer le fichier
panel.pages.save: Enregistrer
panel.pages.status.notPublished: Brouillon
panel.pages.status.notRoutable: Inaccessible

View File

@ -135,6 +135,38 @@ panel.pages.editor.redo: Ripeti
panel.pages.editor.summary: Sommario
panel.pages.editor.undo: Annulla
panel.pages.editPage: Modifica pagina %s
panel.pages.file.backToPage: Torna alla pagina
panel.pages.file.exif: EXIF
panel.pages.file.info: Informazioni
panel.pages.file.info.image.colorDepth: Profondità colore
panel.pages.file.info.image.colorNumber: Numero di colori
panel.pages.file.info.image.colorProfile: Profilo colore
panel.pages.file.info.image.colorSpace: Spazio colore
panel.pages.file.info.image.dimensions: Misure
panel.pages.file.info.image.dimensions.widthByHeightPixels: '%d × %d pixel'
panel.pages.file.info.image.exif.aperture: Apertura
panel.pages.file.info.image.exif.camera: Fotocamera
panel.pages.file.info.image.exif.creationDateAndTime: Data e ora di creazione
panel.pages.file.info.image.exif.exposureCompensation: Compensazione esposizione
panel.pages.file.info.image.exif.exposureProgram: Programma di esposizione
panel.pages.file.info.image.exif.exposureTime: Tempo di esposizione
panel.pages.file.info.image.exif.flash: Flash
panel.pages.file.info.image.exif.focalLength: Lunghezza focale
panel.pages.file.info.image.exif.lensModel: Obiettivo
panel.pages.file.info.image.exif.meteringMode: Modalità di misurazione
panel.pages.file.info.image.exif.sensitivity: Sensibilità
panel.pages.file.info.image.exif.whiteBalance: Bilanciamento del bianco
panel.pages.file.info.image.frames: '%d fotogrammi'
panel.pages.file.info.image.framesCount: Numero di fotogrammi
panel.pages.file.info.image.repeats: '%d ripetizioni'
panel.pages.file.info.image.repeatsCount: Numero di ripetizioni
panel.pages.file.info.image.resolution: Risoluzione
panel.pages.file.info.lastModifiedTime: Ultime modifiche
panel.pages.file.info.mimeType: Tipo MIME
panel.pages.file.info.size: Dimensioni file
panel.pages.file.info.uri: URI
panel.pages.file.position: Posizione
panel.pages.file.preview: Anteprima
panel.pages.files: File
panel.pages.languages: Lingue
panel.pages.languages.addLanguage: Aggiungi %s
@ -146,6 +178,8 @@ panel.pages.newPage.slug: Indirizzo pagina
panel.pages.newPage.slugSuggestion: solo lettere, numeri e trattini
panel.pages.newPage.template: Template
panel.pages.newPage.title: Titolo
panel.pages.next: Pagina successiva
panel.pages.nextFile: File successivo
panel.pages.options: Opzioni
panel.pages.page: Pagina
panel.pages.page.actions: Azioni
@ -174,6 +208,9 @@ panel.pages.page.cannotMove: Impossibile spostare la pagina
panel.pages.page.cannotRenameFile.fileAlreadyExists: Impossibile rinominare il file, un file con lo stesso nome esiste già
panel.pages.page.cannotRenameFile.fileNotFound: Impossibile rinominare il file, file non trovato
panel.pages.page.cannotRenameFile.pageNotFound: Impossibile rinominare il file, pagina non trovata
panel.pages.page.cannotReplaceFile.fileNotFound: Impossibile sostituire il file, file non trovato
panel.pages.page.cannotReplaceFile.multipleFiles: Impossibile sostituire il file, forniti più file
panel.pages.page.cannotReplaceFile.pageNotFound: Impossibile sostituire il file, pagina non trovata
panel.pages.page.cannotUploadFile.pageNotFound: Impossibile caricare il file, pagina non trovata
panel.pages.page.created: Pagina creata!
panel.pages.page.deleted: Pagina eliminata
@ -202,8 +239,11 @@ panel.pages.pages.search: Cerca pagine...
panel.pages.parent: Pagina superiore
panel.pages.preview: Anteprima
panel.pages.previewFile: Anteprima
panel.pages.previous: Pagina precedente
panel.pages.previousFile: File precedente
panel.pages.renameFile: Rinomina file
panel.pages.renameFile.name: Nome
panel.pages.replaceFile: Sostituisci file
panel.pages.save: Salva
panel.pages.status.notPublished: Non pubblicato
panel.pages.status.notRoutable: Non raggiungibile

View File

@ -135,6 +135,38 @@ panel.pages.editor.redo: Refazer
panel.pages.editor.summary: Sumário
panel.pages.editor.undo: Desfazer
panel.pages.editPage: Editar Página %s
panel.pages.file.backToPage: Voltar à Página
panel.pages.file.exif: EXIF
panel.pages.file.info: Informações
panel.pages.file.info.image.colorDepth: Profundidade de Cor
panel.pages.file.info.image.colorNumber: Número de Cores
panel.pages.file.info.image.colorProfile: Perfil de Cor
panel.pages.file.info.image.colorSpace: Espaço de Cor
panel.pages.file.info.image.dimensions: Dimensões
panel.pages.file.info.image.dimensions.widthByHeightPixels: '%d × %d píxeis'
panel.pages.file.info.image.exif.aperture: Abertura
panel.pages.file.info.image.exif.camera: Câmara
panel.pages.file.info.image.exif.creationDateAndTime: Data e Hora de Criação
panel.pages.file.info.image.exif.exposureCompensation: Compensação de Exposição
panel.pages.file.info.image.exif.exposureProgram: Programa de Exposição
panel.pages.file.info.image.exif.exposureTime: Tempo de Exposição
panel.pages.file.info.image.exif.flash: Flash
panel.pages.file.info.image.exif.focalLength: Distância Focal
panel.pages.file.info.image.exif.lensModel: Modelo da Lente
panel.pages.file.info.image.exif.meteringMode: Modo de Medição
panel.pages.file.info.image.exif.sensitivity: Sensibilidade
panel.pages.file.info.image.exif.whiteBalance: Balanço de Branco
panel.pages.file.info.image.frames: '%d frames'
panel.pages.file.info.image.framesCount: Contagem de Frames
panel.pages.file.info.image.repeats: '%d repetições'
panel.pages.file.info.image.repeatsCount: Contagem de Repetições
panel.pages.file.info.image.resolution: Resolução
panel.pages.file.info.lastModifiedTime: Última Modificação
panel.pages.file.info.mimeType: Tipo MIME
panel.pages.file.info.size: Tamanho
panel.pages.file.info.uri: URI
panel.pages.file.position: Posição
panel.pages.file.preview: Pré-visualização
panel.pages.files: Ficheiros
panel.pages.languages: Idiomas
panel.pages.languages.addLanguage: Criar %s
@ -146,6 +178,8 @@ panel.pages.newPage.slug: Slug da Página
panel.pages.newPage.slugSuggestion: letras, números e hifens apenas
panel.pages.newPage.template: Template
panel.pages.newPage.title: Título
panel.pages.next: Próxima Página
panel.pages.nextFile: Próximo Ficheiro
panel.pages.options: Opções
panel.pages.page: Página
panel.pages.page.actions: Acções
@ -174,6 +208,9 @@ panel.pages.page.cannotMove: Não é possível mover a página
panel.pages.page.cannotRenameFile.fileAlreadyExists: Não é possível renomear o arquivo, um arquivo com o mesmo nome já existe
panel.pages.page.cannotRenameFile.fileNotFound: Não é possível renomear o arquivo, arquivo não encontrado
panel.pages.page.cannotRenameFile.pageNotFound: Não é possível renomear o arquivo, página não encontrada
panel.pages.page.cannotReplaceFile.fileNotFound: Não é possível substituir o ficheiro, ficheiro não encontrado
panel.pages.page.cannotReplaceFile.multipleFiles: Não é possível substituir o ficheiro, vários ficheiros fornecidos
panel.pages.page.cannotReplaceFile.pageNotFound: Não é possível substituir o ficheiro, página não encontrada
panel.pages.page.cannotUploadFile.pageNotFound: Não é possível efectuar envio do ficheiro, página não encontrada
panel.pages.page.created: Página criada!
panel.pages.page.deleted: Página removida
@ -202,8 +239,11 @@ panel.pages.pages.search: Procurar Páginas...
panel.pages.parent: Página Parente
panel.pages.preview: Preview
panel.pages.previewFile: Preview
panel.pages.previous: Página Anterior
panel.pages.previousFile: Ficheiro Anterior
panel.pages.renameFile: Renomear Arquivo
panel.pages.renameFile.name: Nome
panel.pages.replaceFile: Substituir Ficheiro
panel.pages.save: Guardar
panel.pages.status.notPublished: Não Publicado
panel.pages.status.notRoutable: Não Roteável

View File

@ -135,6 +135,38 @@ panel.pages.editor.redo: Выбор
panel.pages.editor.summary: Краткий
panel.pages.editor.undo: Открыть
panel.pages.editPage: Отредактировать страницу %s
panel.pages.file.backToPage: Назад к странице
panel.pages.file.exif: EXIF
panel.pages.file.info: Информация
panel.pages.file.info.image.colorDepth: Глубина цвета
panel.pages.file.info.image.colorNumber: Количество цветов
panel.pages.file.info.image.colorProfile: Профиль цвета
panel.pages.file.info.image.colorSpace: Цветовое пространство
panel.pages.file.info.image.dimensions: Размеры
panel.pages.file.info.image.dimensions.widthByHeightPixels: '%d × %d пикселей'
panel.pages.file.info.image.exif.aperture: Диафрагма
panel.pages.file.info.image.exif.camera: Камера
panel.pages.file.info.image.exif.creationDateAndTime: Дата и время создания
panel.pages.file.info.image.exif.exposureCompensation: Компенсация экспозиции
panel.pages.file.info.image.exif.exposureProgram: Программа экспозиции
panel.pages.file.info.image.exif.exposureTime: Время экспозиции
panel.pages.file.info.image.exif.flash: Вспышка
panel.pages.file.info.image.exif.focalLength: Фокусное расстояние
panel.pages.file.info.image.exif.lensModel: Модель объектива
panel.pages.file.info.image.exif.meteringMode: Режим измерения
panel.pages.file.info.image.exif.sensitivity: Чувствительность
panel.pages.file.info.image.exif.whiteBalance: Баланс белого
panel.pages.file.info.image.frames: '%d кадров'
panel.pages.file.info.image.framesCount: Количество кадров
panel.pages.file.info.image.repeats: '%d повторов'
panel.pages.file.info.image.repeatsCount: Количество повторений
panel.pages.file.info.image.resolution: Разрешение
panel.pages.file.info.lastModifiedTime: Последнее изменение
panel.pages.file.info.mimeType: Тип MIME
panel.pages.file.info.size: Размер
panel.pages.file.info.uri: URI
panel.pages.file.position: Позиция
panel.pages.file.preview: Просмотр
panel.pages.files: Файлы
panel.pages.languages: Языки
panel.pages.languages.addLanguage: Добавлять %s
@ -146,6 +178,8 @@ panel.pages.newPage.slug: Страница Slug
panel.pages.newPage.slugSuggestion: буквы, цифры и дефис только
panel.pages.newPage.template: Шаблон
panel.pages.newPage.title: Заглавие
panel.pages.next: Следующая страница
panel.pages.nextFile: Следующий файл
panel.pages.options: Параметры
panel.pages.page: Страница
panel.pages.page.actions: Действия
@ -174,6 +208,9 @@ panel.pages.page.cannotMove: Невозможно переместить стр
panel.pages.page.cannotRenameFile.fileAlreadyExists: Невозможно переименовать файл, файл с таким именем уже существует
panel.pages.page.cannotRenameFile.fileNotFound: Невозможно переименовать файл, файл не найден
panel.pages.page.cannotRenameFile.pageNotFound: Невозможно переименовать файл, страница не найдена
panel.pages.page.cannotReplaceFile.fileNotFound: Невозможно заменить файл, файл не найден
panel.pages.page.cannotReplaceFile.multipleFiles: Невозможно заменить файл, указаны несколько файлов
panel.pages.page.cannotReplaceFile.pageNotFound: Невозможно заменить файл, страница не найдена
panel.pages.page.cannotUploadFile.pageNotFound: Невозможно загрузить файл, страница не найдена
panel.pages.page.created: Страница сгенерирована!
panel.pages.page.deleted: Страница удалена
@ -202,8 +239,11 @@ panel.pages.pages.search: Поиск Страницы ...
panel.pages.parent: Родитель страницы
panel.pages.preview: Предварительный просмотр
panel.pages.previewFile: Предварительный просмотр
panel.pages.previous: Предыдущая страница
panel.pages.previousFile: Предыдущий файл
panel.pages.renameFile: Переименовать файл
panel.pages.renameFile.name: Имя
panel.pages.replaceFile: Заменить файл
panel.pages.save: Сохранить
panel.pages.status.notPublished: Не Опубликовано
panel.pages.status.notRoutable: Не маршрутизируемый

View File

@ -7,8 +7,8 @@
</div>
<div class="files-items">
<?php foreach ($page->files()->sort() as $file) : ?>
<div class="files-item">
<?php foreach ($page->files() as $file) : ?>
<div class="files-item" data-href="<?= $panel->uri('/pages/' . trim($page->route(), '/') . '/file/' . $file->name() . '/') ?>">
<?php if ($file->type() === 'image') : ?>
<div class="file-thumbnail" style="background-image:url('<?= $file->square(300, 'contain')->uri() ?>');"></div>
<?php endif ?>
@ -22,10 +22,14 @@
<div class="dropdown">
<button type="button" class="button button-link dropdown-button" title="<?= $this->translate('panel.files.actions') ?>" data-dropdown="dropdown-<?= $file->hash() ?>"><?= $this->icon('ellipsis-v') ?></button>
<div class="dropdown-menu" id="dropdown-<?= $file->hash() ?>">
<a class="dropdown-item" href="<?= $panel->uri('/pages/' . trim($page->route(), '/') . '/file/' . $file->name() . '/') ?>"><?= $this->icon('info-circle') ?> <?= $this->translate('panel.pages.file.info') ?></a>
<a class="dropdown-item" href="<?= $page->uri($file->name(), includeLanguage: false) ?>" target="formwork-preview-file-<?= $file->hash() ?>"><?= $this->icon('eye') ?> <?= $this->translate('panel.pages.previewFile') ?></a>
<?php if ($panel->user()->permissions()->has('pages.renameFiles')) : ?>
<a class="dropdown-item" data-modal="renameFileModal" data-modal-action="<?= $panel->uri('/pages/' . trim($page->route(), '/') . '/file/' . $file->name() . '/rename/') ?>" data-filename="<?= $file->name() ?>"><?= $this->icon('pencil') ?> <?= $this->translate('panel.pages.renameFile') ?></a>
<?php endif ?>
<?php if ($panel->user()->permissions()->has('pages.replaceFiles')) : ?>
<a class="dropdown-item" data-command="replaceFile" data-action="<?= $panel->uri('/pages/' . trim($page->route(), '/') . '/file/' . $file->name() . '/replace/') ?>" data-extension=".<?= $file->extension() ?>"><?= $this->icon('cloud-upload') ?> <?= $this->translate('panel.pages.replaceFile') ?></a>
<?php endif ?>
<?php if ($panel->user()->permissions()->has('pages.deleteFiles')) : ?>
<a class="dropdown-item" data-modal="deleteFileModal" data-modal-action="<?= $panel->uri('/pages/' . trim($page->route(), '/') . '/file/' . $file->name() . '/delete/') ?>"><?= $this->icon('trash') ?> <?= $this->translate('panel.pages.deleteFile') ?></a>
<?php endif ?>

View File

@ -11,7 +11,7 @@
<div class="modal-footer">
<button type="button" class="button button-secondary" data-dismiss="slugModal"><?= $this->icon('times-circle') ?> <?= $this->translate('panel.modal.action.cancel') ?></button>
<button type="button" class="button button-accent button-right" data-command="continue"><?= $this->icon('check-circle') ?> <?= $this->translate('panel.modal.action.continue') ?></button>
<button type="button" class="button button-link button-right" data-command="generate-slug" title="<?= $this->translate('panel.pages.changeSlug.generate') ?>"><?= $this->icon('bolt') ?></button>
<button type="button" class="button button-link button-right" data-command="generate-slug" title="<?= $this->translate('panel.pages.changeSlug.generate') ?>"><?= $this->icon('sparks') ?></button>
</div>
</div>
</div>

View File

@ -19,6 +19,8 @@
<input type="hidden" id="language" name="language" value="<?= $currentLanguage ?>">
<?php endif ?>
<div>
<a class="<?= $this->classes(['button', 'button-link', 'show-from-md', 'disabled' => !$page->previousSibling()]) ?>" role="button" <?php if ($page->previousSibling()) : ?>href="<?= $panel->uri('/pages/' . trim($page->previousSibling()->route(), '/') . '/edit/') ?>" <?php endif ?> title="<?= $this->translate('panel.pages.previous') ?>" aria-label="<?= $this->translate('panel.pages.previous') ?>"><?= $this->icon('chevron-left') ?></a>
<a class="<?= $this->classes(['button', 'button-link', 'show-from-md', 'disabled' => !$page->nextSibling()]) ?>" role="button" <?php if ($page->nextSibling()) : ?>href="<?= $panel->uri('/pages/' . trim($page->nextSibling()->route(), '/') . '/edit/') ?>" <?php endif ?> title="<?= $this->translate('panel.pages.next') ?>" aria-label="<?= $this->translate('panel.pages.next') ?>"><?= $this->icon('chevron-right') ?></a>
<a class="<?= $this->classes(['button', 'button-link', 'disabled' => !$page->published() || !$page->routable()]) ?>" role="button" <?php if ($page->published() && $page->routable()) : ?>href="<?= $page->uri(includeLanguage: $currentLanguage ?: true) ?>" <?php endif ?> target="formwork-preview-<?= $page->uid() ?>" title="<?= $this->translate('panel.pages.preview') ?>" aria-label="<?= $this->translate('panel.pages.preview') ?>"><?= $this->icon('eye') ?></a>
<?php if ($panel->user()->permissions()->has('pages.delete')) : ?>
<button type="button" class="button button-link" data-modal="deletePageModal" data-modal-action="<?= $panel->uri('/pages/' . trim($page->route(), '/') . '/delete/' . ($currentLanguage ? 'language/' . $currentLanguage . '/' : '')) ?>" title="<?= $this->translate('panel.pages.deletePage') ?>" aria-label="<?= $this->translate('panel.pages.deletePage') ?>" <?php if (!$page->isDeletable()) : ?> disabled<?php endif ?>><?= $this->icon('trash') ?></button>

View File

@ -0,0 +1,94 @@
<?php $this->layout('panel') ?>
<div class="header">
<div class="min-w-0 flex-grow-1">
<div class="header-title"><?= $this->icon(is_null($file->type()) ? 'file' : 'file-' . $file->type()) ?> <?= $file->name() ?></div>
<div><a class="link-secondary text-size-sm" href="<?= $panel->uri('/pages/' . trim($page->route(), '/') . '/edit/') ?>"><span class="mr-2"><?= $this->icon('arrow-left-circle') ?></span><?= $this->translate('panel.pages.file.backToPage') ?></a></div>
</div>
<a class="<?= $this->classes(['button', 'button-link', 'show-from-md', 'disabled' => !$previousFile]) ?>" role="button" <?php if ($previousFile) : ?>href="<?= $panel->uri('/pages/' . trim($page->route(), '/') . '/file/' . ($previousFile->name()) . '/') ?>" <?php endif ?> title="<?= $this->translate('panel.pages.previousFile') ?>" aria-label="<?= $this->translate('panel.pages.previousFile') ?>"><?= $this->icon('chevron-left') ?></a>
<a class="<?= $this->classes(['button', 'button-link', 'show-from-md', 'disabled' => !$nextFile]) ?>" role="button" <?php if ($nextFile) : ?>href="<?= $panel->uri('/pages/' . trim($page->route(), '/') . '/file/' . ($nextFile->name()) . '/') ?>" <?php endif ?> title="<?= $this->translate('panel.pages.nextFile') ?>" aria-label="<?= $this->translate('panel.pages.nextFile') ?>"><?= $this->icon('chevron-right') ?></a>
<?php if ($panel->user()->permissions()->has('pages.renameFiles')) : ?>
<button type="button" class="button button-link" data-modal="renameFileModal" data-modal-action="<?= $panel->uri('/pages/' . trim($page->route(), '/') . '/file/' . $file->name() . '/rename/') ?>" data-filename="<?= $file->name() ?>" title="<?= $this->translate('panel.pages.renameFile') ?>" aria-label="<?= $this->translate('panel.pages.renameFile') ?>"><?= $this->icon('pencil') ?></button>
<?php endif ?>
<?php if ($panel->user()->permissions()->has('pages.replaceFiles')) : ?>
<button type="button" class="button button-link" data-command="replaceFile" data-action="<?= $panel->uri('/pages/' . trim($page->route(), '/') . '/file/' . $file->name() . '/replace/') ?>" data-extension=".<?= $file->extension() ?>" title="<?= $this->translate('panel.pages.replaceFile') ?>" aria-label="<?= $this->translate('panel.pages.replaceFile') ?>"><?= $this->icon('cloud-upload') ?></button>
<?php endif ?>
<?php if ($panel->user()->permissions()->has('pages.deleteFiles')) : ?>
<button type="button" class="button button-link" data-modal="deleteFileModal" data-modal-action="<?= $panel->uri('/pages/' . trim($page->route(), '/') . '/file/' . $file->name() . '/delete/') ?>" title="<?= $this->translate('panel.pages.deleteFile') ?>" aria-label="<?= $this->translate('panel.pages.deleteFile') ?>"><?= $this->icon('trash') ?></button>
<?php endif ?>
</div>
<?php if ($file->type() === 'image') : ?>
<div class="sections">
<section class="section">
<div class="section-header">
<span class="caption"><?= $this->translate('panel.pages.file.preview') ?></span>
</div>
<div class="section-content page-file-preview-container">
<a class="page-file-preview-link" href="<?= $file->uri() ?>"><img class="page-file-preview-image"" src=" <?= $file->uri() ?>"></a>
</div>
</section>
</div>
<?php endif ?>
<?php if ($file->type() === 'video') : ?>
<section class="section">
<div class="section-header">
<span class="caption"><?= $this->translate('panel.pages.file.preview') ?></span>
</div>
<div class="section-content page-file-preview-container">
<video style="width: 100%" controls playsinline>
<source src="<?= $file->uri() ?>" type="<?= $file->mimeType() ?>" />
</video>
</div>
</section>
<?php endif ?>
<section class="section">
<div class="section-header">
<span class="caption"><?= $this->translate('panel.pages.file.info') ?></span>
</div>
<div class="section-content">
<div class="row">
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.mimeType') ?>:</div>
<?= $file->mimeType() ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.size') ?>:</div>
<?= $file->size() ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.lastModifiedTime') ?>:</div>
<?= $this->datetime($file->lastModifiedTime()) ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.uri') ?>:</div>
<a class="page-file-info-entry-uri" href="<?= $file->uri() ?>"><?= $file->uri() ?></a>
</div>
<?php if ($file->type() === 'image') : ?>
<?php $this->insert('_files/images/info/info', ['file' => $file]) ?>
<?php endif ?>
</div>
</div>
</section>
<?php if ($file->type() === 'image') : ?>
<?php if ($file->hasExifData() && $file->getExifData()->hasPositionData()) : ?>
<section class="section collapsible">
<div class="section-header">
<button type="button" class="button section-toggle mr-2" title="<?= $this->translate('panel.sections.toggle') ?>" aria-label="<?= $this->translate('panel.sections.toggle') ?>"><?= $this->icon('chevron-up') ?></button>
<span class="caption"><?= $this->translate('panel.pages.file.position') ?></span>
</div>
<div class="section-content">
<?php $this->insert('_files/images/position/map', ['exif' => $file->getExifData()]) ?>
</div>
</section>
<?php endif ?>
<?php if ($file->hasExifData()) : ?>
<section class="section collapsible collapsed">
<div class="section-header">
<button type="button" class="button section-toggle mr-2" title="<?= $this->translate('panel.sections.toggle') ?>" aria-label="<?= $this->translate('panel.sections.toggle') ?>"><?= $this->icon('chevron-up') ?></button>
<span class="caption"><?= $this->translate('panel.pages.file.exif') ?></span>
</div>
<div class="section-content">
<?php $this->insert('_files/images/exif/data', ['exif' => $file->getExifData()]) ?>
</div>
</section>
<?php endif ?>
<?php endif ?>

View File

@ -0,0 +1,8 @@
<table class="table table-bordered table-striped table-hoverable text-size-sm">
<?php foreach ($exif->parsedTags() as $key => $value) : ?>
<tr>
<td class="table-cell truncate page-file-info-entry-title" style="width: 25%;"><?= $key ?></td>
<td class="table-cell"><?= $this->escape(is_array($value) ? implode(', ', $value) : (string) $value) ?></td>
</tr>
<?php endforeach ?>
</table>

View File

@ -0,0 +1,48 @@
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.exif.creationDateAndTime') ?>:</div>
<?= $exif->dateTimeOriginal() ?? '-' ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.exif.camera') ?>:</div>
<?= $exif->makeAndModel() ?? '' ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.exif.lensModel') ?>:</div>
<?= $exif->lensModel() ?? '' ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.exif.focalLength') ?>:</div>
<?= $exif->focalLength() ?? '' ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.exif.exposureTime') ?>:</div>
<?= $exif->exposureTime() ?? '' ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.exif.aperture') ?>:</div>
<?= $exif->aperture() ?? '' ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.exif.sensitivity') ?>:</div>
<?= $exif->photographicSensitivity() ?? '' ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.exif.exposureCompensation') ?>:</div>
<?= $exif->exposureCompensation() ?? '' ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.exif.exposureProgram') ?>:</div>
<?= $exif->exposureProgram() ?? '' ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.exif.whiteBalance') ?>:</div>
<?php if ($exif->hasAutoWhiteBalance() === true) : ?>AWB<?php else : ?><?php endif ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.exif.flash') ?>:</div>
<?php if ($exif->hasFlashFired() !== null) : ?> <?= $exif->hasFlashFired() ? $this->icon('camera-flash') : $this->icon('camera-no-flash') ?><?php else : ?><?php endif ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.exif.meteringMode') ?>:</div>
<?php if ($exif->meteringMode() !== null) : ?><?= $this->icon('camera-metering-' . $exif->meteringMode()) ?><?php else : ?><?php endif ?>
</div>

View File

@ -0,0 +1,45 @@
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.dimensions') ?>:</div>
<?= $this->translate('panel.pages.file.info.image.dimensions.widthByHeightPixels', $file->info()->width(), $file->info()->height()) ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.resolution') ?>:</div>
<?= round(max($file->info()->width() * $file->info()->height() / 1e6, 0.1), 1) ?> MP
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.colorSpace') ?>:</div>
<?= $file->info()->colorSpace()->value ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.colorDepth') ?>:</div>
<?= $file->info()->colorDepth() ?> bit
</div>
<?php if ($file->info()->colorSpace()->value === 'PALETTE') : ?>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.colorNumber') ?>:</div>
<?= $file->info()->colorNumber() ?>
</div>
<?php endif ?>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.colorProfile') ?>:</div>
<?php if ($file->hasColorProfile() && $file->getColorProfile()->name()) : ?>
<?= $file->getColorProfile()->name() ?>
<?php elseif ($file->hasExifData() && $file->getExifData()->colorSpace()) : ?>
<?= $file->getExifData()->colorSpace() ?> (EXIF)
<?php else : ?>
<?php endif ?>
</div>
<?php if ($file->info()->isAnimation()) : ?>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.framesCount') ?>:</div>
<?= $this->translate('panel.pages.file.info.image.frames', $file->info()->animationFrames()) ?>
</div>
<div class="col-sm-1-2 col-md-1-4 mb-4">
<div class="page-file-info-entry-title"><?= $this->translate('panel.pages.file.info.image.repeatsCount') ?>:</div>
<?php if ($file->info()->animationRepeatCount() > 0) : ?><?= $this->translate('panel.pages.file.info.image.repeats', $file->info()->animationRepeatCount()) ?><?php else : ?>∞<?php endif ?>
</div>
<?php endif ?>
<?php if ($file->hasExifData()) : ?>
<?php $this->insert('_files/images/info/exif', ['exif' => $file->getExifData()]) ?>
<?php endif ?>

View File

@ -0,0 +1 @@
<iframe style="width: 100%; height: 20rem;" frameborder="0" scrolling="no" marginheight="0" marginwidth="0" src="https://www.openstreetmap.org/export/embed.html?bbox=<?= $exif->get('GPSLongitude') - 0.025 ?>,<?= $exif->get('GPSLatitude') - 0.025 ?>,<?= $exif->get('GPSLongitude') + 0.025 ?>,<?= $exif->get('GPSLatitude') + 0.025 ?>&amp;marker=<?= $exif->get('GPSLatitude') ?>,<?= $exif->get('GPSLongitude') ?>"></iframe>

View File

@ -0,0 +1,10 @@
files:
allowedExtensions:
- .jpg
- .jpeg
- .png
- .gif
- .svg
- .webp
- .mp4
- .webm