[TikiWiki-commits] [Git][tikiwiki/tiki][master] [FIX][UX] Tiki Tracker File Field: Improved file modal search refresh, filtering, and selection UX
"luci \(@luciash\) via TikiWiki-cvs" <[email protected]>
| Newsgroups | gmane.comp.cms.tiki.cvs |
|---|---|
| Message-ID | <68e6c12f5b921_2ce02cc808e5@gitlab-sidekiq-low-urgency-cpu-bound-v2-54547678f4-5mjkg.mail> |
luci pushed to branch master at Tiki Wiki CMS Groupware / Tiki
Commits:
90d496bf by Doddy MATABARO at 2025-10-08T19:45:10+00:00
[FIX][UX] Tiki Tracker File Field: Improved file modal search refresh, filtering, and selection UX
---
* [FIX][UX] File gallery list: remove UL left padding so divider aligns with container; add horizontal padding on rows
* [ENH][UX] Replaced 'Current Selection' UI with inline checkboxes and select all checkbox
* [FIX][UX] Tiki Tracker File Field: Improved file modal search refresh, filtering, and selection UX
See merge request tikiwiki/tiki!7613
- - - - -
4 changed files:
- lib/core/Services/File/Controller.php
- lib/jquery_tiki/files.js
- templates/file/browse.tpl
- templates/file/list_gallery.tpl
Changes:
=====================================
lib/core/Services/File/Controller.php
=====================================
@@ -410,7 +410,7 @@ class Services_File_Controller
]);
if ($search = $input->search->text()) {
- $query->filterContent($search);
+ $query->filterContent($search, 'title,filename');
}
if ($typeFilter = $input->type->text()) {
=====================================
lib/jquery_tiki/files.js
=====================================
@@ -520,65 +520,6 @@
});
}
- function browserRemoveFile(link)
- {
- var list = $(link).closest('ul');
- $(link).closest('li').remove();
-
- list.closest('.file-browser').trigger('selection-update');
- }
-
- function browserAddFile(link)
- {
- var content = $(link).closest('.media-body').clone(true),
- icon = $(link).closest('.media, .panel').find('.media-object, .panel-body a').children('img').clone(true).width('16px'),
- nav = $(link).closest('.file-browser').find('.selection ul'),
- item = $('<li>'),
- a = $('<a>').text($(link).text()),
- id = $(link).data('object'),
- limit = nav.closest('form').data('limit'),
- current = nav.find('input[type=hidden]').filter(function () {
- return parseInt($(this).val(), 10) === id;
- });
-
- if (current.length > 0) {
- // Already in the list
- browserRemoveFile(current[0]);
- return;
- }
-
- if (limit === 1) {
- nav.empty();
- } else if (limit && nav.children('li').length >= limit) {
- alert(nav.closest('form').data('limit-reached-message'));
- return;
- }
-
- a
- .prepend(' ')
- .prepend(icon);
- item.append(a);
- nav.append(item);
-
- item.append($('<input type="hidden" name="file[]">')
- .attr('value', id));
-
- nav.closest('.file-browser').trigger('selection-update');
- }
-
- $(document).on('selection-update', '.file-browser', function (e) {
- var selection = $('.selection input[type=hidden]', this).map(function () {
- return parseInt($(this).val(), 10);
- });
-
- $('.gallery-list .media-heading a, .gallery-list .panel-body a', this).each(function () {
- var id = $(this).data('object');
- $(this).closest('.media').toggleClass('bg-info', -1 !== $.inArray(id, selection));
- $(this).closest('.panel').toggleClass('panel-info', -1 !== $.inArray(id, selection));
- });
- $('.selection', this).toggleClass("invisible", selection.length === 0);
- });
-
$(document).on('click', '.file-browser .gallery-list .pagination a', function (e) {
e.preventDefault();
$(this).closest('.modal').animate({ scrollTop: 0 }, 'slow');
@@ -586,32 +527,27 @@
.tikiModal(tr('Loading...'))
.load($(this).attr('href'), function () {
$(this).tikiModal('');
- $(this).closest('.file-browser').trigger('selection-update');
});
});
- $(document).on('click', '.file-browser .gallery-list .media-heading a, .file-browser .gallery-list .panel-body a', function (e) {
- e.preventDefault();
- e.stopPropagation();
- browserAddFile(this);
- });
- $(document).on('click', '.file-browser .gallery-list .media, .file-browser .gallery-list .panel', function (e) {
- e.preventDefault();
- $('.media-heading a, .panel-body a', this).trigger("click");
- });
-
- $(document).on('click', '.file-browser .selection a', function (e) {
- e.preventDefault();
- browserRemoveFile(this);
- });
-
- $(document).on('submit', '.file-browser .form-inline', function (e) {
+ $(document).on('submit', '.file-browser form.no-ajax[method="get"]', function (e) {
e.preventDefault();
- $(this).closest('.file-browser').find('.gallery-list')
- .tikiModal(tr('Loading...'))
- .load($(this).attr('action'), $(this).serialize(), function () {
- $(this).tikiModal('');
- $(this).closest('.file-browser').trigger('selection-update');
+ const $form = $(this);
+ const $fileBrowser = $form.closest('.file-browser');
+ const $galleryList = $fileBrowser.find('.gallery-list');
+ const url = $form.attr('action');
+ const data = $form.serialize();
+
+ $galleryList.tikiModal(tr('Loading...'));
+
+ $.get(url, data)
+ .done(function (response) {
+ $galleryList.html(response);
+ $galleryList.tikiModal('');
+ })
+ .fail(function () {
+ $galleryList.html('<div class="alert alert-danger">' + tr('Error loading results.') + '</div>');
+ $galleryList.tikiModal('');
});
});
@@ -629,7 +565,6 @@
.attr('value', file.fileId))
.appendTo($list);
- $list.closest('.file-browser').trigger('selection-update');
});
$.closeModal();
}
@@ -678,6 +613,26 @@
});
});
+ $(document).on('click', '.file-browser .gallery-list .pagination a', function (e) {
+ e.preventDefault();
+ $('#select-all-files').prop('checked', false);
+ $(this).closest('.modal').animate({ scrollTop: 0 }, 'slow');
+ $(this).closest('.gallery-list')
+ .tikiModal(tr('Loading...'))
+ .load($(this).attr('href'), function () {
+ $(this).tikiModal('');
+ });
+ });
+
+ $(document).on('click', '.file-title-toggle', function (e) {
+ e.preventDefault();
+ const targetId = $(this).data('checkbox-id');
+ const checkbox = document.getElementById(targetId);
+ if (checkbox) {
+ checkbox.checked = !checkbox.checked;
+ }
+ });
+
})(jQuery);
function updateFileName(inputFile) {
=====================================
templates/file/browse.tpl
=====================================
@@ -6,48 +6,47 @@
{block name="content"}
<div class="row file-browser">
- <div class="col-md-9">
- <form class="d-flex flex-row flex-wrap align-items-center no-ajax" method="get" action="{service controller=file action=$list_view plain=1}">
- <div class="mb-3 row">
- <label class="form-label sr-only" for="search-field">{tr}Search{/tr}</label>
- <input class="form-control" name="search" type="search" id="search-field" placeholder="{tr}Search...{/tr}"/>
+ <div class="col-md-12">
+ <form class="row g-2 align-items-center no-ajax" method="get" action="{service controller=file action=$list_view plain=1}">
+ <div class="col">
+ <input class="form-control " name="search" type="search" id="search-field" placeholder="{tr}Search...{/tr}"/>
<input type="hidden" name="galleryId" value="{$galleryId|escape}"/>
+ <input type="hidden" name="limit" value="{$limit|default:20}">
<input type="hidden" name="type" value="{$typeFilter|escape}"/>
</div>
- <button class="btn btn-info">{tr}Search{/tr}</button>
+ <div class="col-auto">
+ <button class="btn btn-info" type="submit">{tr}Search{/tr}</button>
+ </div>
</form>
- <h4>{tr}Select files{/tr}</h4>
- <div class="gallery-list">
- {service_inline controller=file action=$list_view galleryId=$galleryId plain=1 type=$typeFilter}
+
+ <div class="d-flex justify-content-between align-items-center my-2">
+ <h4 class="mb-0">{tr}Select files{/tr}</h4>
+ <div>
+ <input type="checkbox" id="select-all-files" class="form-check-input me-2"/>
+ <label for="select-all-files" class="form-label mb-0">{tr}Select all{/tr}</label>
+ </div>
</div>
- </div>
- <div class="col-md-3 selection hidden">
- <form method="post" action="{service controller=file action=browse galleryId=$galleryId}" data-gallery-id="{$galleryId|escape}" data-limit="{$limit|escape}" data-limit-reached-message="{tr}Too many files selected. De-select some files before adding more.{/tr}">
- <h4>{tr}Current Selection{/tr}</h4>
- <ul class="nav nav-pills nav-stacked">
- {foreach $files as $file}
- <li>
- <a href="{$file.fileId|sefurl:'file'}" data-type="file" data-object="{$file.fileId|escape}">
- {$file.name|iconify:$file.type:$file.fileId}
- {$file.label|escape}
- </a>
- <input type="hidden" name="file[]" value="{$file.fileId|escape}"/>
- </li>
- {/foreach}
- </ul>
- <div class="form-text">
- {tr}Click to remove{/tr}
+
+ <form method="post" action="{service controller=file action=browse galleryId=$galleryId}">
+ <div class="gallery-list flex-grow-1 overflow-auto border" style="max-height: 60vh;">
+ {service_inline controller=file action=$list_view galleryId=$galleryId plain=1 type=$typeFilter limit=$limit}
</div>
- <div class="submit">
+
+ <div class="submit sticky-bottom bg-light py-3 mt-3">
{if $canUpload}
- <a class="btn btn-secondary upload-files custom-handling" href="{service controller=file action=uploader galleryId=$galleryId limit=$limit type=$typeFilter}">{tr}Upload Files{/tr}</a>
+ <a class="btn btn-secondary upload-files custom-handling me-2" href="{service controller=file action=uploader galleryId=$galleryId limit=$limit type=$typeFilter}">
+ {tr}Upload Files{/tr}
+ </a>
{/if}
- <input type="submit" class="btn btn-primary" value="{tr}Select{/tr}">
+ <input type="submit" class="btn btn-primary" value="{tr}Attach selected file(s){/tr}">
</div>
</form>
</div>
</div>
+
{jq}
- $('.file-browser').trigger('selection-update');
+ $('#select-all-files').on('change', function () {
+ $('.gallery-list .file-select').prop('checked', this.checked).trigger('change');
+ });
{/jq}
{/block}
=====================================
templates/file/list_gallery.tpl
=====================================
@@ -5,28 +5,32 @@
{/block}
{block name="content"}
- <ul class="media-list">
+ <ul class="media-list list-unstyled ps-0 mb-0">
{foreach from=$results item=row}
- <li class="d-flex">
+ <li class="d-flex align-items-start border-bottom py-2 px-2">
+ <div class="form-check mt-2 me-2">
+ <input class="form-check-input file-select" type="checkbox" name="file[]" value="{$row.object_id|escape}" id="file-{$row.object_id}">
+ </div>
+
<div class="flex-shrink-0">
{if $row.filetype|truncate:6:'' eq 'image/'}
- <img src="{$row.object_id|sefurl:'thumbnail'}"/>
+ <label for="file-{$row.object_id}">
+ <img src="{$row.object_id|sefurl:'thumbnail'}" class="img-thumbnail" style="width: 64px; height: auto;" />
+ </label>
{else}
{$row.filename|iconify:$row.filetype}
{/if}
</div>
- <div class="flex-grow-1 ms-3">
- <h4 class="media-heading">{object_link type=$row.object_type id=$row.object_id}</h4>
- <div>
- {$row.filename|escape}
- </div>
- <div>
- {$row.description|escape}
- </div>
- <div class="small">
+
+ <div class="flex-grow-1 ms-3 file-click-toggle" data-target="file-{$row.object_id}">
+ <h6 class="media-heading mb-1">{object_link type=$row.object_type id=$row.object_id}</h6>
+ <div class="mb-1">{$row.filename|escape}</div>
+ <div class="mb-1 text-muted small">{$row.description|escape}</div>
+ <div class="small text-muted">
{tr _0=$row.modification_date|tiki_short_datetime}Last modification: %0{/tr}
</div>
</div>
+
</li>
{foreachelse}
<li>
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/90d496bfa01f00e97f12e9d4b7301bb75125d507
--
View it on GitLab: https://gitlab.com/tikiwiki/tiki/-/commit/90d496bfa01f00e97f12e9d4b7301bb75125d507
You're receiving this email because of your account on gitlab.com.
_______________________________________________
TikiWiki-cvs mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/tikiwiki-cvs