feat: ajouter la fonctionnalité de saisie automatique pour les tags dans les formulaires d'ajout et d'édition de liens

This commit is contained in:
Bruno Charest 2026-02-13 11:48:33 -05:00
parent f3072c3eb6
commit eee850909a
6 changed files with 149 additions and 2 deletions

View File

@ -40,7 +40,7 @@
<div class="form-group"> <div class="form-group">
<label class="form-label" for="tags">{'Tags'|t}</label> <label class="form-label" for="tags">{'Tags'|t}</label>
<input type="text" name="tags" id="tags" class="form-control lf_input" data-list="{loop="$tags"}{$key}, {/loop}" data-multiple data-autofirst autocomplete="off" placeholder="tags, separated, by, commas"> <input type="text" name="tags" id="tags" class="form-control lf_input" data-list="{loop="$tags"}{$key}, {/loop}" data-multiple data-autofirst autocomplete="off" placeholder="tags separated by space">
</div> </div>
<input type="hidden" name="private" value="0"> <input type="hidden" name="private" value="0">

View File

@ -0,0 +1,118 @@
/* Awesomplete Base Styles */
.awesomplete [hidden] {
display: none;
}
.awesomplete .visually-hidden {
position: absolute;
clip: rect(0, 0, 0, 0);
}
.awesomplete {
display: block;
/* Changed from inline-block to match input width */
position: relative;
width: 100%;
}
.awesomplete>input {
display: block;
width: 100%;
/* Ensure input takes full width */
}
.awesomplete>ul {
position: absolute;
left: 0;
z-index: 1000;
/* Increased Z-Index */
min-width: 100%;
box-sizing: border-box;
list-style: none;
padding: 0;
margin: 0.25rem 0 0;
background: var(--bg-card);
/* Theme Variable */
border: 1px solid var(--border);
/* Theme Variable */
border-radius: 0.5rem;
box-shadow: var(--shadow-lg);
/* Theme Variable */
text-shadow: none;
overflow: hidden;
color: var(--text-main);
/* Theme Variable */
animation: slideDown 0.2s ease;
}
.awesomplete>ul:empty {
display: none;
}
.awesomplete>ul>li {
position: relative;
padding: 0.75rem 1rem;
cursor: pointer;
font-size: 0.95rem;
color: var(--text-main);
transition: background 0.1s ease;
border-bottom: 1px solid var(--border-light);
}
.awesomplete>ul>li:last-child {
border-bottom: none;
}
/* Hover State */
.awesomplete>ul>li:hover {
background: var(--bg-card-hover);
color: var(--primary);
}
/* Selected State */
.awesomplete>ul>li[aria-selected="true"] {
background: var(--primary);
color: white;
}
/* Highlighted Match */
.awesomplete mark {
background: rgba(255, 255, 0, 0.3);
color: inherit;
padding: 0;
font-weight: bold;
}
.awesomplete li[aria-selected="true"] mark {
background: rgba(255, 255, 255, 0.3);
color: inherit;
}
/* Dark Mode Adjustments */
[data-theme="dark"] .awesomplete>ul {
background: var(--bg-card);
border-color: var(--border);
}
[data-theme="dark"] .awesomplete>ul>li:hover {
background: var(--bg-card-hover);
}
/* Fix for Card Overflow affecting dropdown visibility */
.card,
.form-add .card,
.page-edit .card {
overflow: visible !important;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-8px);
}
to {
opacity: 1;
transform: translateY(0);
}
}

View File

@ -58,7 +58,7 @@
<label class="form-label" for="lf_tags{$index}">{'Tags'|t}</label> <label class="form-label" for="lf_tags{$index}">{'Tags'|t}</label>
<div class="{$asyncLoadClass}"> <div class="{$asyncLoadClass}">
<input type="text" class="form-control" id="lf_tags{$index}" name="lf_tags" {if="empty($batch_mode)"}class="autofocus form-control"{/if} value="{$link.tags}" <input type="text" class="form-control" id="lf_tags{$index}" name="lf_tags" {if="empty($batch_mode)"}class="autofocus form-control"{/if} value="{$link.tags}"
data-list="{loop="$tags"}{$key}, {/loop}" data-multiple autocomplete="off" placeholder="tags, separated, by, commas" /> data-list="{loop="$tags"}{$key}, {/loop}" data-multiple autocomplete="off" placeholder="tags separated by space" />
</div> </div>
</div> </div>

View File

@ -23,6 +23,10 @@
<!-- Professional Theme CSS --> <!-- Professional Theme CSS -->
<link type="text/css" rel="stylesheet" href="{$asset_path}/css/style.css#" /> <link type="text/css" rel="stylesheet" href="{$asset_path}/css/style.css#" />
{if="$pageName=='editlink' || $pageName=='addlink' || $pageName=='editlinkbatch'"}
<link type="text/css" rel="stylesheet" href="{$asset_path}/css/awesomplete.css#" />
<script src="{$asset_path}/js/awesomplete.min.js#" defer></script>
{/if}
<!-- Icons (Material Design Icons) --> <!-- Icons (Material Design Icons) -->

2
shaarli-pro/js/awesomplete.min.js vendored Normal file

File diff suppressed because one or more lines are too long

View File

@ -20,6 +20,29 @@
{loop="$plugins_footer.js"} {loop="$plugins_footer.js"}
<script src="{$root_path}/{$value}"></script> <script src="{$root_path}/{$value}"></script>
{/loop} {/loop}
{if="$pageName=='editlink' || $pageName=='addlink' || $pageName=='editlinkbatch'"}
<script>
document.addEventListener('DOMContentLoaded', function() {
var inputs = document.querySelectorAll('input[data-list]');
Array.prototype.forEach.call(inputs, function(input) {
new Awesomplete(input, {
minChars: 1,
maxItems: 15,
filter: function(text, input) {
return Awesomplete.FILTER_CONTAINS(text, input.match(/[^ ]*$/)[0]);
},
item: function(text, input) {
return Awesomplete.ITEM(text, input.match(/[^ ]*$/)[0]);
},
replace: function(text) {
var before = this.input.value.match(/.* /);
this.input.value = (before ? before[0] : "") + text + " ";
}
});
});
});
</script>
{/if}
</footer> </footer>
</div> </div>
<!-- Bulk Actions Bar (for multi-select) --> <!-- Bulk Actions Bar (for multi-select) -->