261 lines
8.3 KiB
PHP
261 lines
8.3 KiB
PHP
<?php
|
|
|
|
namespace skin\files;
|
|
|
|
use BookFileType;
|
|
use BookItem;
|
|
use FilesCollection;
|
|
use FilesItemInterface;
|
|
use SkinContext;
|
|
use SkinString;
|
|
use function svg;
|
|
|
|
function index($ctx,
|
|
array $collections,
|
|
array $books,
|
|
array $misc) {
|
|
return <<<HTML
|
|
{$ctx->bc([
|
|
['text' => $ctx->lang('files_archives')]
|
|
])}
|
|
|
|
<div class="files-list">
|
|
{$ctx->for_each($collections,
|
|
fn(FilesItemInterface $file) => $ctx->file(
|
|
file: $file,
|
|
disabled: !$file->isAvailable()))}
|
|
</div>
|
|
|
|
{$ctx->bc([
|
|
['text' => $ctx->lang('files_books')]
|
|
], mt: true)}
|
|
|
|
<div class="files-list">
|
|
{$ctx->for_each($books, fn(FilesItemInterface $file) => $ctx->file(file: $file))}
|
|
</div>
|
|
|
|
{$ctx->bc([
|
|
['text' => $ctx->lang('files_misc')]
|
|
], mt: true)}
|
|
|
|
<div class="files-list">
|
|
{$ctx->for_each($misc, fn(FilesItemInterface $file) => $ctx->file(file: $file))}
|
|
</div>
|
|
HTML;
|
|
}
|
|
|
|
function folder($ctx, BookItem $folder, array $files, ?array $parents) {
|
|
$svg = svg();
|
|
$svg->folder_20(preload_symbol: true);
|
|
$svg->file_20(preload_symbol: true);
|
|
|
|
$bc = [
|
|
['text' => $ctx->lang('files'), 'url' => '/files/'],
|
|
];
|
|
|
|
if ($parents) {
|
|
for ($i = 0; $i < count($parents)-1; $i++) {
|
|
$parent = $parents[$i];
|
|
$bc_item = ['text' => $parent->getTitle()];
|
|
if ($i < count($parents)-1)
|
|
$bc_item['url'] = $parent->getUrl();
|
|
$bc[] = $bc_item;
|
|
}
|
|
}
|
|
$bc[] = ['text' => $folder->title];
|
|
|
|
return <<<HTML
|
|
{$ctx->bc($bc)}
|
|
<div class="files-list">
|
|
<div id="files_list">
|
|
{$ctx->collection_files($files)}
|
|
</div>
|
|
</div>
|
|
HTML;
|
|
|
|
}
|
|
|
|
function collection(SkinContext $ctx,
|
|
FilesCollection $collection,
|
|
array $files,
|
|
?array $parents,
|
|
int $search_results_per_page,
|
|
int $search_min_query_length,
|
|
?string $search_query = null,
|
|
?int $search_count = null,
|
|
?array $text_excerpts = null) {
|
|
$widgets = skin('widgets');
|
|
|
|
$svg = svg();
|
|
$svg->folder_20(preload_symbol: true);
|
|
$svg->file_20(preload_symbol: true);
|
|
|
|
$bc = [
|
|
['text' => $ctx->lang('files'), 'url' => '/files/'],
|
|
];
|
|
if ($parents) {
|
|
$bc[] = ['text' => $ctx->lang('files_'.$collection->value.'_collection_short'), 'url' => "/files/{$collection->value}/"];
|
|
for ($i = 0; $i < count($parents); $i++) {
|
|
$parent = $parents[$i];
|
|
$bc_item = ['text' => $parent->getTitle()];
|
|
if ($i < count($parents)-1)
|
|
$bc_item['url'] = $parent->getUrl();
|
|
$bc[] = $bc_item;
|
|
}
|
|
} else {
|
|
$bc[] = ['text' => $ctx->lang('files_'.$collection->value.'_collection')];
|
|
}
|
|
|
|
$do_show_search = empty($parents);
|
|
$do_show_more = $search_count > 0 && count($files) < $search_count;
|
|
|
|
$html = <<<HTML
|
|
{$ctx->bc($bc)}
|
|
{$ctx->if_true($do_show_search, fn() => $ctx->collection_search($search_count, $search_query, $ctx->lang('files_'.$collection->value.'_search_ph')))}
|
|
|
|
<div class="files-list">
|
|
<div id="files_list">
|
|
{$ctx->collection_files($files, $search_query, $text_excerpts)}
|
|
</div>
|
|
<div class="files-list-show-more no-select" id="files_show_more"{$ctx->if_not($do_show_more, ' style="display: none"')}>
|
|
<span class="files-list-show-more-label">{$ctx->lang('files_show_more')}</span>
|
|
{$widgets->spinner('files_show_more_spinner')}
|
|
</div>
|
|
</div>
|
|
<div id="files_list_hidden" style="display: none"></div>
|
|
HTML;
|
|
|
|
if ($do_show_search) {
|
|
$opts = [
|
|
'container' => 'files_list',
|
|
'per_page' => $search_results_per_page,
|
|
'min_query_length' => $search_min_query_length,
|
|
'base_url' => "/files/{$collection->value}/",
|
|
'query' => $search_query,
|
|
'count' => $search_count,
|
|
'collection_name' => $collection->value,
|
|
'inited_with_search' => !!$search_query
|
|
];
|
|
$opts = jsonEncode($opts);
|
|
|
|
$js = <<<JAVASCRIPT
|
|
cur.search = new FileSearch({$opts});
|
|
JAVASCRIPT;
|
|
|
|
return [$html, $js];
|
|
} else {
|
|
return $html;
|
|
}
|
|
}
|
|
|
|
function collection_files($ctx,
|
|
array $files,
|
|
?string $search_query = null,
|
|
?array $text_excerpts = null) {
|
|
return $ctx->for_each($files, fn(FilesItemInterface $f) => $ctx->file(
|
|
file: $f,
|
|
unsafe_query: $search_query,
|
|
text_excerpts: $text_excerpts));
|
|
}
|
|
|
|
function collection_search(SkinContext $ctx, $count, $query, ?string $placeholder = null) {
|
|
$icons = svg();
|
|
$widgets = skin('widgets');
|
|
$clear_dsp = $query ? 'block' : 'none';
|
|
|
|
return <<<HTML
|
|
<div class="files-search-wrap">
|
|
<div class="files-search" id="files_search">
|
|
<div class="files-search-icon">{$icons->search_20()}</div>
|
|
<input type="text" value="{$query}" placeholder="{$ctx->if_then_else($placeholder !== null, $placeholder, 'Enter your request..')}" id="files_search_input">
|
|
<div class="files-search-clear-icon" id="files_search_clear_icon" style="display: {$clear_dsp}">{$icons->clear_16()}</div>
|
|
</div>
|
|
|
|
<div class="files-search-results-info" id="files_search_info" style="display: {$clear_dsp}">
|
|
<div class="files-search-results-info-inner">
|
|
<div class="files-search-results-info-spinner">{$widgets->spinner()}</div>
|
|
<span id="files_search_info_text">{$ctx->if_then_else($query, fn() => $ctx->lang_num('files_search_results_count', $count), ' ')}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
HTML;
|
|
}
|
|
|
|
|
|
function file(SkinContext $ctx,
|
|
FilesItemInterface $file,
|
|
?SkinString $unsafe_query = null,
|
|
bool $disabled = false,
|
|
?array $text_excerpts = null) {
|
|
$icons = svg();
|
|
if ($file instanceof BookItem && $file->fileType == BookFileType::BOOK)
|
|
$icon = $icons->book_20();
|
|
else
|
|
$icon = $file->isFile() ? $icons->file_20() : $icons->folder_20();
|
|
|
|
$class = 'files-list-item clearfix';
|
|
if ($disabled)
|
|
$class .= ' is-disabled';
|
|
|
|
$mapper = function($s) use ($unsafe_query) {
|
|
if ($unsafe_query !== null) {
|
|
return hl_matched($s, $unsafe_query);
|
|
} else {
|
|
return htmlescape($s);
|
|
}
|
|
};
|
|
|
|
$title = $file->getTitleHtml();
|
|
if ($title === null) {
|
|
// we don't apply $mapper to already htmlescaped string
|
|
$title = $mapper($file->getTitle());
|
|
}
|
|
|
|
$meta = $file->getMeta($unsafe_query);
|
|
$meta_is_inline = $meta['inline'] ?? false;
|
|
$meta_items = $meta['items'] ?? [];
|
|
$url = htmlescape($file->getUrl());
|
|
|
|
$subtitle = $file->getSubtitle();
|
|
|
|
return <<<HTML
|
|
<a href="{$url}" class="{$class}" data-id="{$file->getId()}"{$ctx->if_true($file->isTargetBlank(), ' target="_blank"')}>
|
|
<div class="files-list-item-icon">{$icon}</div>
|
|
<div class="files-list-item-info">
|
|
<div class="files-list-item-title">
|
|
<span class="files-list-item-title-label">{$title}</span>
|
|
{$ctx->if_true($file->isFolder() && $file->isTargetBlank(), fn() => '<span class="files-list-item-title-label-external-icon">'.$icons->arrow_up_right_out_square_outline_12().'</span>')}
|
|
{$ctx->if_true($subtitle, fn() => '<span class="files-list-item-subtitle">'.htmlescape($subtitle).'</span>')}
|
|
{$ctx->if_true($meta_is_inline, $ctx->for_each($meta_items, fn($s) => '<div class="files-list-item-meta-item">'.$s.'</div>'))}
|
|
</div>
|
|
{$ctx->if_true($meta_items && !$meta_is_inline, $ctx->meta($meta_items))}
|
|
{$ctx->if_true(is_array($text_excerpts) && isset($text_excerpts[$file->getId()]),
|
|
fn() => $ctx->text_excerpt($text_excerpts[$file->getId()]['excerpt'], $text_excerpts[$file->getId()]['index'], $unsafe_query))}
|
|
</div>
|
|
</a>
|
|
HTML;
|
|
}
|
|
|
|
/**
|
|
* @param SkinContext $ctx
|
|
* @param string[] $meta strings are already html-safe
|
|
* @return string
|
|
*/
|
|
function meta($ctx, array $meta) {
|
|
return <<<HTML
|
|
<div class="files-list-item-meta">
|
|
{$ctx->for_each($meta, fn($s) => '<div class="files-list-item-meta-item">'.$s.'</div>')}
|
|
</div>
|
|
HTML;
|
|
}
|
|
|
|
|
|
function text_excerpt($ctx, $unsafe_excerpt, $index, $unsafe_query) {
|
|
if ($index > 0)
|
|
$unsafe_excerpt = '...'.$unsafe_excerpt;
|
|
$unsafe_excerpt .= '...';
|
|
$text = hl_matched($unsafe_excerpt, $unsafe_query);
|
|
return <<<HTML
|
|
<div class="files-list-item-text-excerpt">{$text}</div>
|
|
HTML;
|
|
} |