shaarli_themes/morgan/editlink.html

406 lines
24 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!-- editlink.html -->
{$batchId=isset($batchId) ? $batchId : ''}
{if="empty($batch_mode)"}
<!DOCTYPE html>
<html{if="$language !== 'auto'"} lang="{$language}"{/if}>
<head>
{include="includes"}
<link rel="stylesheet" href='https://unpkg.com/@yaireo/tagify@4.35.0/dist/tagify.css'/>
<style>
.tag-suggestions-container {
margin-top: 0.5em;
}
.tag-suggestions-container .suggested-tag {
display: inline-block;
margin: .2em;
padding: .3em .5em;
border-radius: 3px;
border: 1px solid #ccc;
background: #f3f3f3;
font-size: .85em;
cursor: pointer;
user-select: none;
}
</style>
</head>
<body>
{include="page.header"}
{else}
{ignore}Lil hack: when included in a loop in batch mode, `$value` is assigned by RainTPL with template vars.{/ignore}
{function="extract($value) ? '' : ''"}
{/if}
<div id="editlinkform{$batchId}" class="edit-link-container" class="pure-g">
<div class="pure-u-lg-1-5 pure-u-1-24"></div>
<form method="post"
name="linkform"
action="{$base_path}/admin/shaare"
class="page-form pure-u-lg-3-5 pure-u-22-24 page-form page-form-light"
>
{$asyncLoadClass=$link_is_new && $async_metadata && empty($link.title) ? 'loading-input' : ''}
<h2 class="window-title">
{if="!$link_is_new"}{'Edit Shaare'|t}{else}{'New Shaare'|t}{/if}
</h2>
{if="isset($link.id)"}
<input type="hidden" name="lf_id" value="{$link.id}">
{/if}
{if="!$link_is_new"}<div class="created-date">{'Created:'|t} {$link.created|format_date}</div>{/if}
<div>
<label for="lf_url{$batchId}">{'URL'|t}</label>
</div>
<div>
<input type="text" name="lf_url" id="lf_url{$batchId}" value="{$link.url}" class="lf_input">
</div>
<div>
<label for="lf_title{$batchId}">{'Title'|t}</label>
</div>
<div class="{$asyncLoadClass}">
<input type="text" name="lf_title" id="lf_title{$batchId}" value="{$link.title}"
class="lf_input {if="!$async_metadata"}autofocus{/if}"
>
<div class="icon-container">
<i class="loader"></i>
</div>
</div>
<div>
<label for="lf_description{$batchId}">{'Description'|t}</label>
</div>
<div class="{if="$retrieve_description"}{$asyncLoadClass}{/if}">
<textarea name="lf_description" id="lf_description{$batchId}" class="autofocus">{$link.description}</textarea>
<div class="icon-container">
<i class="loader"></i>
</div>
</div>
<div>
<label for="lf_tags{$batchId}">{'Tags'|t}</label>
</div>
<div class="{if="$retrieve_description"}{$asyncLoadClass}{/if}">
<input type="text"
name="lf_tags"
id="lf_tags{$batchId}"
value="{$link.tags}"
class="lf_input tagify--custom-dropdown"
data-list="{loop="$tags"}{$key}, {/loop}"
data-multiple
data-autofirst
autocomplete="off"
>
<div class="icon-container">
<i class="loader"></i>
</div>
</div>
<div id="tag-suggestions{$batchId}" class="tag-suggestions-container"></div>
<div>
<input type="checkbox" name="lf_private" id="lf_private{$batchId}"
{if="$link.private === true"}
checked="checked"
{/if}>
&nbsp;<label for="lf_private{$batchId}">{'Private'|t}</label>
</div>
{if="$formatter==='markdown'"}
<div class="md_help">
{'Description will be rendered with'|t}
<a href="http://daringfireball.net/projects/markdown/syntax" title="{'Markdown syntax documentation'|t}">
{'Markdown syntax'|t}
</a>.
</div>
{/if}
<div id="editlink-plugins">
{loop="$edit_link_plugin"}
{$value}
{/loop}
</div>
<div class="submit-buttons center">
{if="!empty($batch_mode)"}
<a href="#" class="button button-grey" name="cancel-batch-link"
title="{'Remove this bookmark from batch creation/modification.'}"
>
{'Cancel'|t}
</a>
{/if}
<input type="submit" name="save_edit" class="" id="button-save-edit"
value="{if="$link_is_new"}{'Save'|t}{else}{'Apply Changes'|t}{/if}">
{if="!$link_is_new"}
<a href="{$base_path}/admin/shaare/delete?id={$link.id}&amp;token={$token}"
title="" name="delete_link" class="button button-red confirm-delete">
{'Delete'|t}
</a>
{/if}
</div>
<input type="hidden" name="token" value="{$token}">
<input type="hidden" name="source" value="{$source}">
{if="$http_referer"}
<input type="hidden" name="returnurl" value="{$http_referer}">
{/if}
</form>
</div>
{if="empty($batch_mode)"}
{include="page.footer"}
<script src='https://unpkg.com/@yaireo/tagify@4.35.0/dist/tagify.min.js'></script>
<script>
document.addEventListener('DOMContentLoaded', function() {
var input = document.getElementById("lf_tags{$batchId}");
var suggestionsContainer = document.getElementById("tag-suggestions{$batchId}");
// liste complète des tags depuis data-list
var allTags = input.getAttribute('data-list').split(/,\s*/);
var mapping = [
{ keys: ['accessibility','accessibilité','web development','web design','html','css','websites'], tags: ['web'] },
{ keys: ['accounting','comptabilité'], tags: ['accounting'] },
{ keys: ['addict','addiction','addicted','drugs','drogues','cigarettes','bonbons','dopamine','sucre','nicotine','hooked'], tags: ['addiction'] },
{ keys: ['adhd','tdah'], tags: ['adhd'] },
{ keys: ['alternative','alternatives','compatible','compatibles','migrated','migration'], tags: ['alternatives'] },
{ keys: ['ads','advertisements','publicités','spam'], tags: ['ads'] },
{ keys: ['anxiété','anxieux','anxieuse','burnout','méditation','cardio','santé','health','healthy'], tags: ['health-and-wellness'] },
{ keys: ['architecture','architectures'], tags: ['architecture'] },
{ keys: ['archive','archiving','archives','archivage'], tags: ['archiving','archives'] },
{ keys: ['art','arts','folklore'], tags: ['culture'] },
{ keys: ['ask hn','news.ycombinator.com/item','reddit.com/r/'], tags: ['debate'] },
{ keys: ['autism','autisme','autist','autiste'], tags: ['autism'] },
{ keys: ['belgian','belgium','belge','belgique'], tags: ['belgium'] },
{ keys: ['board game','board games','boardgame','jeu de société','jeux de société'], tags: ['board-games','geek'] },
{ keys: ['bookmarks','favoris','signets'], tags: ['bookmarks-management'] },
{ keys: ['browsers','navigateurs','web browsers'], tags: ['web-browsers'] },
{ keys: ['books','livre','livres','quatrième de couverture','roman','novel','reading-list'], tags: ['reading-and-literature','inspiration','culture'] },
{ keys: ['robots.txt','bots','spam','crawling','ddos'], tags: ['spam'] },
{ keys: ['bruxelles','brussels'], tags: ['brussels'] },
{ keys: ['calm tech','calmness','calm','technologie calme'], tags: ['calm-tech'] },
{ keys: ['cars','car bloat','vehicles','véhicule','véhicules','vehicle','automobile','automotive'], tags: ['transport'] },
{ keys: ['cheatsheet','cheat sheet','cheat-sheet','antisèche'], tags: ['guides-and-tips'] },
{ keys: ['cleaning','nettoyage','deep clean','cleanse','deep cleans'], tags: ['cleaning'] },
{ keys: ['cloud','aws','amazon','cloudron'], tags: ['cloud'] },
{ keys: ['cloudron'], tags: ['cloudron','hosting'] },
{ keys: ['(comic)','-comic-','comics','bandes dessinées'], tags: ['comics','reading-and-literature','culture','humor'] },
{ keys: ['comparison','comparer',' vs ','versus','comparatif','comparaison'], tags: ['comparison'] },
{ keys: ['communicate','communication','messaging','messenger','gmail','communiquer','écriture inclusive','la langue','académie française','language'], tags: ['communication'] },
{ keys: ['complex','impossible to solve','complicated','very difficult','complexe','compliqué','complexity'], tags: ['complexity','its-complicated'] },
{ keys: ['computers','personal computer','the pc'], tags: ['pc'] },
{ keys: ['configure','configuration','paramétrer','paramétrage'], tags: ['configuration'] },
{ keys: ['database','databases','RDS','base de données'], tags: ['databases'] },
{ keys: ['data collection','collecte de données'], tags: ['data-collection'] },
{ keys: ['data transfer','transfert de données'], tags: ['data-portability'] },
{ keys: ['debug','troubleshoot','diagnose','résoudre','diagnostiquer','troubleshooting','find a solution','fix bugs'], tags: ['problem-solving','guides-and-tips','debugging'] },
{ keys: ['design','designs'], tags: ['design'] },
{ keys: ['development workflow','devex','flux de développement'], tags: ['devex'] },
{ keys: ['digital garden'], tags: ['digital-garden'] },
{ keys: ['disk','disque','disques'], tags: ['storage'] },
{ keys: ['distraction','procrastination','procrastine','procrastiner','glander'], tags: ['procrastination'] },
{ keys: ['diy','self-host','héberger soi-même','my personal','fait maison'], tags: ['diy'] },
{ keys: ['dns','network','tcp','wireshark','réseau'], tags: ['network'] },
{ keys: ['docker','docker-compose','docker compose','container','containers','k8s','eks','kubernetes','minikube','k3s','helm','openshift'], tags: ['container-technology','devops'] },
{ keys: ['documentation','docs','document','documentation technique'], tags: ['documentation'] },
{ keys: ['drawing'], tags: ['drawing'] },
{ keys: ['drinks','soda','beer','coffee'], tags: ['drinks'] },
{ keys: ['ses droits','legally','legalement','légal'], tags: ['legal'] },
{ keys: ['elixir','python','pip','php','rust','golang','programming','developer','software engineer','software development','developers','développeurs'], tags: ['software-development'] },
{ keys: ['emulator','emulation','émulateur','émulation'], tags: ['emulation'] },
{ keys: ['entrepreneurship','entrepreneurs','entrepreneuriat'], tags: ['business'] },
{ keys: ['espresso','coffee','café'], tags: ['coffee','drinks'] },
{ keys: ['ethic','ethique','ethics'], tags: ['ethics'] },
{ keys: ['explor','going deep','exploration'], tags: ['discovery'] },
{ keys: ['en sécurité','enfin libre','libéré','unsafe','liberté'], tags: ['privacy-and-security','freedom'] },
{ keys: ['libre','free','liberté','degoogling','degoogle','dégooglisation'], tags: ['freedom'] },
{ keys: ['logiciel libre','free software','logiciel gratuit','free to use'], tags: ['free-software'] },
{ keys: ['from home','remote work','work remote','travail à distance','télétravail'], tags: ['remote-work'] },
{ keys: ['frustrated','frustration','am pissed','I hate'], tags: ['rant'] },
{ keys: ['big-tech','gafam','degoogling','google','degoogle','géants américains','grandes entreprises technologiques','meta quest','meta ai'], tags: ['big-tech'] },
{ keys: ['game','jeu vidéo','game dev','jeux','jeux vidéo','games','gameplay'], tags: ['games','geek','culture'] },
{ keys: ['gamedev','building game','game programming','game engine','moteur de jeu','game development','développement de jeux'], tags: ['gamedev','games','geek','culture'] },
{ keys: ['gratuit','free'], tags: ['free'] },
{ keys: ['gitops','gitlab','github actions','devops','SRE','ci/cd','platform-engineering','ci pipeline','application deployment','dagger','renovatebot','dependabot','continuous integration','site reliability eng'], tags: ['devops'] },
{ keys: ['git','gitlab','jujutsu','pijul','mercurial','svn','version control','contrôle de version'], tags: ['version-control'] },
{ keys: ['gpt','chatgpt','llm','llms','artificial intelligence','code generation','genai','vibe code','vibe coding','intelligence artificielle','IA','l\'ia','ai','ai model','an ai','metal ai','auto-coder','autonomous AI'], tags: ['ai'] },
{ keys: ['hacking','piratage'], tags: ['hacking'] },
{ keys: ['nutrition','food','alimentation','nourriture','recette','recette de cuisine','recettes de cuisine','ingrédients','cette recette','beurre','cuisine'], tags: ['food'] },
{ keys: ['history','histoire','documentaire','documentary'], tags: ['history'] },
{ keys: ['humans','humains'], tags: ['humans'] },
{ keys: ['humor','humour'], tags: ['humor'] },
{ keys: ['idiocracy'], tags: ['idiocracy'] },
{ keys: ['réduire sa dépendance'], tags: ['independence','freedom'] },
{ keys: ['inspiration','creativity','creative','inspiration','créativité'], tags: ['inspiration'] },
{ keys: ['leadership','staff engineering','gestion'], tags: ['leadership'] },
{ keys: ['lambic','gueuze','beer','bière','bières'], tags: ['beer-and-brewing','drinks'] },
{ keys: ['linux','ubuntu','debian','linux windows macos','sur mac','sur windows'], tags: ['os'] },
{ keys: ['list','index of','awesome','installation','GitHub - ','liste'], tags: ['discovery'] },
{ keys: ['low-tech','low tech','technologie simple'], tags: ['low-tech'] },
{ keys: ['merdification','enshittif','AI-generated','crapification','decline in quality','déclin de qualité'], tags: ['enshittification'] },
{ keys: ['misinformation','fact-checking','fact checking'], tags: ['misinformation'] },
{ keys: ['monitoring','metrics','to monitor','surveillance','métriques'], tags: ['monitoring','metrics'] },
{ keys: ['movie','cinéma','cinema','film','films'], tags: ['movies','culture','geek'] },
{ keys: ['music','spotify','radios','webradios','soundtrack','bande originale','musique'], tags: ['music'] },
{ keys: ['newsletter','news'], tags: ['newsletter','news'] },
{ keys: ['nostalgia','nostalgie','things used to be better','internet archive'], tags: ['nostalgia'] },
{ keys: ['obsidian','note taking','note-taking','taking notes','note-geek','capturing knowledge','knowledge management','prise de notes','gestion de connaissances','knowledge transfer','transferring knowledge','your notes','my notes'], tags: ['knowledge-management','note-taking'] },
{ keys: ['ocr'], tags: ['ocr'] },
{ keys: ['open-source','open source','code source libre'], tags: ['open-source','free'] },
{ keys: ['optimize','optimization','speed up','an efficient','optimiser','optimisation'], tags: ['optimization'] },
{ keys: ['philosophe','philosophia','philosophy','lifestyle','philosophie'], tags: ['philosophy'] },
{ keys: ['photography','photos','photographie'], tags: ['photos'] },
{ keys: ['podcast','podcasts'], tags: ['podcast'] },
{ keys: ['ego','narcissism','narcissist','narcissisme','psycholog','psychologie'], tags: ['psychology'] },
{ keys: ['voting','politic','politique','vote','multiculturalism','culturalism','cultural integration','political'], tags: ['politics'] },
{ keys: ['python','logiciels en python'], tags: ['python','software-development','code'] },
{ keys: ['principles'], tags: ['principles'] },
{ keys: ['privatebin'], tags: ['secrets'] },
{ keys: ['productivity','time management','timetracker'], tags: ['productivity-and-management'] },
{ keys: ['programming languages','langages de programmation'], tags: ['code','computer-languages'] },
{ keys: ['publishing','publier','publication'], tags: ['publishing'] },
{ keys: ['quality','qualité'], tags: ['quality'] },
{ keys: ['recommandations','recommendation','conseils'], tags: ['recommendations'] },
{ keys: ['recycling','sustainable','green web','climate','recyclage','web écologique','climat','ai emissions','water use','emissions produced','amount of co2','global co2','co2 emissions','car bloat','environnement','environment','environmental','environmentally','plastic waste'], tags: ['ecology'] },
{ keys: ['relationship','relationships','de rencontre','meaningful connections'], tags: ['relationships'] },
{ keys: ['religion','chretiens','bible','coran','islam','musulmans','croyants','athée','la foi','église'], tags: ['philosophy'] },
{ keys: ['reviews','critique','avis'], tags: ['reviews'] },
{ keys: ['rss','rss feed','miniflux','web reader','lecteur web'], tags: ['content-aggregation','content-curation'] },
{ keys: ['ruby','rails app','applications ruby'], tags: ['ruby','software-development','code'] },
{ keys: ['science','sciences','scientifique','scientist'], tags: ['science'] },
{ keys: ['scripting','jq','curl','wget','script','bash','terminal','bash script','#!/bin/bash','script python','python script','lua','script shell','script bash','shell script'], tags: ['scripting'] },
{ keys: ['search engine','moteur de recherche'], tags: ['search-engines'] },
{ keys: ['security','permission','sécurité','securing','anti vol','anti-vol','secure','data privacy','privacy','private','degoogl','gdpr','data protection','online tracking','user profiling','anonymo','anonymi','surveillance','malware','spyware','decentrali','secrets','privacy matters','vpn','passkey','protéger','password manager','vie privée'], tags: ['privacy-and-security'] },
{ keys: ['simplicity','minimal','declutter','stopped using','simple','simplification','simplifier','reduction in','no longer needed','minimalisme','simplicité','réduction'], tags: ['minimalism'] },
{ keys: ['small web','indie web','indieweb','petit web','small-web'], tags: ['small-web'] },
{ keys: ['smartphone','android','mobile','phone','téléphone','sms'], tags: ['mobile'] },
{ keys: ['snippet','extrait de code'], tags: ['code'] },
{ keys: ['static site','static-site','site statique'], tags: ['static-site'] },
{ keys: ['social media','réseau social','fediverse','fédiverse','réseaux sociaux','social networks','social network','meta quest'], tags: ['social-media'] },
{ keys: ['society','societies'], tags: ['society'] },
{ keys: ['teamwork','collaborat','équipe','cooperat','coordinat','travail équipe'], tags: ['collaboration'] },
{ keys: ['technology','technologie'], tags: ['technology'] },
{ keys: ['template','modèle'], tags: ['template'] },
{ keys: ['terminal','terminaltrove'], tags: ['terminal','tools-and-resources'] },
{ keys: ['test','tester'], tags: ['testing'] },
{ keys: ['markdown','text files','fichiers texte','formats','text-based','plaintext','markup language','markdown','plain text','basé sur du texte','langage balisé'], tags: ['plaintext','formats','text-files'] },
{ keys: ['time to update','maintainers','tech-debt','legacy code','long term software','temps pour mettre à jour'], tags: ['maintenance','tech-debt'] },
{ keys: ['to do','to-do','à faire'], tags: ['todo'] },
{ keys: ['tool','tools-and-resources','resources','a script','outil','a collection','a catalog','awesome list','links','outils','ressources','password manager','logiciels'], tags: ['tools-and-resources'] },
{ keys: ['training','course','conference talk','learning','homeschool','expert','specializ','tacit knowledge','tribal knowledge','formation','cours','conférence','apprentissage'], tags: ['education'] },
{ keys: ['.txt','text-based','fichiers txt'], tags: ['text-files'] },
{ keys: ['ui','interfaces utilisateur'], tags: ['ui'] },
{ keys: ['ux','the experience of','usable','uxer','user experience','expérience utilisateur'], tags: ['ux'] },
{ keys: ['vps','serveur privé virtuel'], tags: ['cloud','privacy-and-security','hosting'] },
{ keys: ['web archive','web archiving','save any website','bookmarks','wayback machine','archive.org','archivebox','archive web'], tags: ['web-archiving'] },
{ keys: ['webring'], tags: ['discovery','small-web','webring'] },
{ keys: ['wordpress','personal website','personal websites','blog roll','blogroll','blogosphere','webring','digital garden','to blog','blogs'], tags: ['blogging','writing','discovery','small-web'] },
{ keys: ['work','travail','contract work','previous job','my work','coworkers','coworker','the job','workgroup'], tags: ['work'] },
{ keys: ['of writing'], tags: ['writing'] },
{ keys: ['youtube.com','invidious','peertube','watch?v'], tags: ['video'] },
{ keys: ['zoemp','zoemp.be'], tags: ['zoemp'] }
];
var matchCounts = {};
var tagify = new Tagify(input, {
delimiters: ",| ",
pattern: /^.{1,50}$/,
trim: true,
keepInvalidTags: false,
whitelist: [], // sera mis à jour dynamiquement
dropdown: {
enabled: 1, // activation du dropdown à la frappe
fuzzySearch: true,
position: 'all',
maxItems: 50,
closeOnSelect: false
},
maxTags: 50,
duplicates: false,
originalInputValueFormat: function(valuesArr) {
return valuesArr.map(function(item) { return item.value; }).join(' ');
}
});
var descriptionEl = document.getElementById("lf_description{$batchId}");
function escapeRegExp(string) {
return string.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
}
function updateSuggestionList() {
// Supprime les liens archive pour ne pas matcher "archive.org" ou similaires
var rawDesc = descriptionEl.value
.replace(/https?:\/\/web\.archive\.org\S*/gi, '')
.replace(/Archive:/gi, '')
.replace(/voir aussi https:\/\/shaarli\.zoemp/gi, '');
var desc = rawDesc.toLowerCase();
var existing = tagify.value.map(function(item){ return item.value; });
matchCounts = {};
var suggested = {};
mapping.forEach(function(entry) {
entry.keys.forEach(function(key) {
// crée un motif regex pour mot entier (ou pluriel)
var pattern = new RegExp('\\b' + escapeRegExp(key.toLowerCase()) + '(?:s)?\\b', 'i');
if (pattern.test(desc)) {
entry.tags.forEach(function(t) {
matchCounts[t] = (matchCounts[t] || 0) + 1;
suggested[t] = (suggested[t] || 0) + 1;
});
}
});
});
var highPriority = [], medPriority = [], lowPriority = [];
Object.keys(suggested).forEach(function(t) {
if (existing.indexOf(t) !== -1) return;
if (suggested[t] > 1) highPriority.push(t);
else if (suggested[t] === 1) medPriority.push(t);
else lowPriority.push(t);
});
// Tronquer à 5 lowPriority
lowPriority = lowPriority.slice(0, 5);
var ordered = highPriority.concat(medPriority).concat(lowPriority);
// Complète la whitelist avec le reste des tags non déjà listés
var fallback = allTags.filter(function(t) {
return ordered.indexOf(t) === -1 && existing.indexOf(t) === -1;
});
var finalList = ordered.concat(fallback);
tagify.settings.whitelist = finalList;
tagify.dropdown.show.call(tagify, finalList);
// Met à jour les suggestions affichées sous linput
suggestionsContainer.innerHTML = '';
ordered.forEach(function(tag) {
var el = document.createElement('span');
el.textContent = tag;
var count = matchCounts[tag] || 0;
if (count > 1) {
el.style.backgroundColor = '#d0f0d0';
el.style.borderColor = '#5cac5c';
el.style.color = '#2d662d';
} else if (count === 1) {
el.style.backgroundColor = '#f0f8e0';
el.style.borderColor = '#8cbf8c';
el.style.color = '#2d662d';
} else {
el.style.backgroundColor = '#f8e0e0';
el.style.borderColor = '#c88c8c';
el.style.color = '#662d2d';
}
el.className = 'suggested-tag';
el.addEventListener('click', function() {
tagify.addTags([tag]);
updateSuggestionList();
});
suggestionsContainer.appendChild(el);
});
}
descriptionEl.addEventListener('input', updateSuggestionList);
tagify.on('add', updateSuggestionList);
tagify.on('remove', updateSuggestionList);
updateSuggestionList();
});
</script>
</body>
</html>
{/if}