feat : barre de partage articles + déduplication images uploadées (v1.6.20)
- post_view.php : barre de partage (mail, X, LinkedIn, Mastodon, copier, Web Share) sur articles publiés (#47) - share.js : logique clipboard + navigator.share sans script tiers, compatible CSP (#47) - addFile() : hardlink vers fichier identique si même hash16-size.ext dans un autre article (#35) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,14 @@ Format : [Keep a Changelog](https://keepachangelog.com/fr/1.0.0/) — versionnag
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## [1.6.20] - 2026-05-16
|
||||||
|
|
||||||
|
### Ajouté
|
||||||
|
- Barre de partage sur les articles publiés : mail, X, LinkedIn, Mastodon, copie de lien, Web Share API mobile (#47)
|
||||||
|
- Déduplication des images uploadées par hardlink si même hash+taille existe déjà dans un autre article (#35)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## [1.6.19] - 2026-05-16
|
## [1.6.19] - 2026-05-16
|
||||||
|
|
||||||
### Ajouté
|
### Ajouté
|
||||||
|
|||||||
@@ -0,0 +1,40 @@
|
|||||||
|
(function () {
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var bar = document.getElementById('share-bar');
|
||||||
|
if (!bar) { return; }
|
||||||
|
|
||||||
|
var url = bar.getAttribute('data-url') || window.location.href;
|
||||||
|
var title = bar.getAttribute('data-title') || document.title;
|
||||||
|
|
||||||
|
var copyBtn = document.getElementById('share-copy');
|
||||||
|
if (copyBtn) {
|
||||||
|
copyBtn.addEventListener('click', function () {
|
||||||
|
if (!navigator.clipboard) {
|
||||||
|
var ta = document.createElement('textarea');
|
||||||
|
ta.value = url;
|
||||||
|
document.body.appendChild(ta);
|
||||||
|
ta.select();
|
||||||
|
document.execCommand('copy');
|
||||||
|
document.body.removeChild(ta);
|
||||||
|
copyBtn.textContent = 'Copié !';
|
||||||
|
setTimeout(function () { copyBtn.textContent = 'Copier le lien'; }, 2000);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
navigator.clipboard.writeText(url).then(function () {
|
||||||
|
copyBtn.textContent = 'Copié !';
|
||||||
|
setTimeout(function () { copyBtn.textContent = 'Copier le lien'; }, 2000);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
var nativeBtn = document.getElementById('share-native');
|
||||||
|
if (nativeBtn) {
|
||||||
|
if (navigator.share) {
|
||||||
|
nativeBtn.hidden = false;
|
||||||
|
nativeBtn.addEventListener('click', function () {
|
||||||
|
navigator.share({ title: title, url: url }).catch(function () {});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}());
|
||||||
+1
-1
@@ -1 +1 @@
|
|||||||
1.6.19
|
1.6.20
|
||||||
|
|||||||
+10
-1
@@ -1197,7 +1197,16 @@ class ArticleManager
|
|||||||
$size = filesize($uploadedFile['tmp_name']);
|
$size = filesize($uploadedFile['tmp_name']);
|
||||||
$name = "{$hash}-{$size}.{$ext}";
|
$name = "{$hash}-{$size}.{$ext}";
|
||||||
$dest = $dir . '/' . $name;
|
$dest = $dir . '/' . $name;
|
||||||
if (!rename($uploadedFile['tmp_name'], $dest) && !move_uploaded_file($uploadedFile['tmp_name'], $dest)) {
|
// Déduplication : si ce fichier identique existe déjà dans un autre article, crée un hardlink
|
||||||
|
if (!file_exists($dest)) {
|
||||||
|
$existing = glob($this->dataDir . '/*/files/' . $name);
|
||||||
|
if (!empty($existing) && is_file($existing[0])) {
|
||||||
|
link($existing[0], $dest) || copy($existing[0], $dest);
|
||||||
|
@unlink($uploadedFile['tmp_name']);
|
||||||
|
return $name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!file_exists($dest) && !rename($uploadedFile['tmp_name'], $dest) && !move_uploaded_file($uploadedFile['tmp_name'], $dest)) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return $name;
|
return $name;
|
||||||
|
|||||||
@@ -163,6 +163,9 @@ $_layoutCurrentCat = trim($_GET['cat'] ?? '');
|
|||||||
<?php if (isset($reactionStats)): ?>
|
<?php if (isset($reactionStats)): ?>
|
||||||
<script src="<?= _av($_pub, 'js/reactions.js') ?>"></script>
|
<script src="<?= _av($_pub, 'js/reactions.js') ?>"></script>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
<?php if (!empty($shareBar ?? false)): ?>
|
||||||
|
<script src="<?= _av($_pub, 'js/share.js') ?>" defer></script>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|||||||
@@ -261,6 +261,28 @@ $hasSources = (!empty($externalLinks) || !empty($files))
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<?php if ($article['published'] ?? false): ?>
|
||||||
|
<?php
|
||||||
|
$_shareUrl = rtrim(defined('APP_URL') ? APP_URL : '', '/') . '/post/' . rawurlencode($article['slug'] ?? '');
|
||||||
|
$_shareTitle = $article['title'] ?? '';
|
||||||
|
?>
|
||||||
|
<div class="d-flex flex-wrap align-items-center gap-2 my-3 py-2 border-top"
|
||||||
|
id="share-bar"
|
||||||
|
data-url="<?= htmlspecialchars($_shareUrl) ?>"
|
||||||
|
data-title="<?= htmlspecialchars($_shareTitle) ?>">
|
||||||
|
<span class="text-muted small me-1">Partager :</span>
|
||||||
|
<a href="mailto:?subject=<?= rawurlencode($_shareTitle) ?>&body=<?= rawurlencode($_shareUrl) ?>"
|
||||||
|
class="btn btn-outline-secondary btn-sm" title="Par e-mail">✉ Mail</a>
|
||||||
|
<a href="https://x.com/intent/tweet?text=<?= rawurlencode($_shareTitle) ?>&url=<?= rawurlencode($_shareUrl) ?>"
|
||||||
|
class="btn btn-outline-secondary btn-sm" target="_blank" rel="noopener noreferrer" title="X / Twitter">X</a>
|
||||||
|
<a href="https://www.linkedin.com/sharing/share-offsite/?url=<?= rawurlencode($_shareUrl) ?>"
|
||||||
|
class="btn btn-outline-secondary btn-sm" target="_blank" rel="noopener noreferrer" title="LinkedIn">in</a>
|
||||||
|
<a href="https://mastodon.social/share?text=<?= rawurlencode($_shareTitle . ' ' . $_shareUrl) ?>"
|
||||||
|
class="btn btn-outline-secondary btn-sm" target="_blank" rel="noopener noreferrer" title="Mastodon">🐘</a>
|
||||||
|
<button type="button" class="btn btn-outline-secondary btn-sm" id="share-copy">Copier le lien</button>
|
||||||
|
<button type="button" class="btn btn-outline-primary btn-sm" id="share-native" hidden>⬆ Partager</button>
|
||||||
|
</div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php include __DIR__ . '/comments_section.php'; ?>
|
<?php include __DIR__ . '/comments_section.php'; ?>
|
||||||
|
|
||||||
@@ -397,6 +419,7 @@ $hasSources = (!empty($externalLinks) || !empty($files))
|
|||||||
|
|
||||||
<?php
|
<?php
|
||||||
$content = ob_get_clean();
|
$content = ob_get_clean();
|
||||||
|
$shareBar = (bool)($article['published'] ?? false);
|
||||||
$title = htmlspecialchars($article['title']);
|
$title = htmlspecialchars($article['title']);
|
||||||
$seoTitle = ($article['seo_title'] ?? '') ?: $article['title'];
|
$seoTitle = ($article['seo_title'] ?? '') ?: $article['title'];
|
||||||
$ogType = 'article';
|
$ogType = 'article';
|
||||||
|
|||||||
Reference in New Issue
Block a user