@bebranded/bb-contents 1.0.84-beta → 1.0.84
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bb-contents.js +329 -329
- package/package.json +1 -1
package/bb-contents.js
CHANGED
|
@@ -589,259 +589,259 @@
|
|
|
589
589
|
|
|
590
590
|
// Module Share (Partage Social)
|
|
591
591
|
share: {
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
},
|
|
599
|
-
facebook: function(data) {
|
|
600
|
-
return 'https://facebook.com/sharer/sharer.php?u=' +
|
|
601
|
-
encodeURIComponent(data.url);
|
|
602
|
-
},
|
|
603
|
-
linkedin: function(data) {
|
|
604
|
-
// LinkedIn - URL de partage officielle (2024+)
|
|
605
|
-
return 'https://www.linkedin.com/sharing/share-offsite/?url=' + encodeURIComponent(data.url);
|
|
606
|
-
},
|
|
607
|
-
whatsapp: function(data) {
|
|
608
|
-
return 'https://wa.me/?text=' +
|
|
609
|
-
encodeURIComponent(data.text + ' ' + data.url);
|
|
610
|
-
},
|
|
611
|
-
telegram: function(data) {
|
|
612
|
-
return 'https://t.me/share/url?url=' +
|
|
613
|
-
encodeURIComponent(data.url) +
|
|
614
|
-
'&text=' + encodeURIComponent(data.text);
|
|
615
|
-
},
|
|
616
|
-
email: function(data) {
|
|
617
|
-
return 'mailto:?subject=' +
|
|
618
|
-
encodeURIComponent(data.text) +
|
|
619
|
-
'&body=' + encodeURIComponent(data.text + ' ' + data.url);
|
|
620
|
-
},
|
|
621
|
-
copy: function(data) {
|
|
622
|
-
return 'copy:' + data.url;
|
|
623
|
-
},
|
|
624
|
-
native: function(data) {
|
|
625
|
-
return 'native:' + JSON.stringify(data);
|
|
626
|
-
}
|
|
592
|
+
// Configuration des réseaux
|
|
593
|
+
networks: {
|
|
594
|
+
twitter: function(data) {
|
|
595
|
+
return 'https://twitter.com/intent/tweet?url=' +
|
|
596
|
+
encodeURIComponent(data.url) +
|
|
597
|
+
'&text=' + encodeURIComponent(data.text);
|
|
627
598
|
},
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
const s = scope || document;
|
|
632
|
-
return s.querySelector(bbContents._attrSelector('share')) !== null;
|
|
599
|
+
facebook: function(data) {
|
|
600
|
+
return 'https://facebook.com/sharer/sharer.php?u=' +
|
|
601
|
+
encodeURIComponent(data.url);
|
|
633
602
|
},
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
// Récupérer les données
|
|
647
|
-
const network = bbContents._getAttr(element, 'bb-share');
|
|
648
|
-
const customUrl = bbContents._getAttr(element, 'bb-url');
|
|
649
|
-
const customText = bbContents._getAttr(element, 'bb-text');
|
|
650
|
-
|
|
651
|
-
// Valeurs par défaut sécurisées
|
|
652
|
-
const data = {
|
|
653
|
-
url: bbContents.utils.isValidUrl(customUrl) ? customUrl : window.location.href,
|
|
654
|
-
text: bbContents.utils.sanitize(customText || document.title || 'Découvrez ce site')
|
|
655
|
-
};
|
|
656
|
-
|
|
657
|
-
// Gestionnaire de clic
|
|
658
|
-
element.addEventListener('click', function(e) {
|
|
659
|
-
e.preventDefault();
|
|
660
|
-
bbContents.modules.share.share(network, data, element);
|
|
661
|
-
});
|
|
662
|
-
|
|
663
|
-
// Accessibilité
|
|
664
|
-
if (element.tagName !== 'BUTTON' && element.tagName !== 'A') {
|
|
665
|
-
element.setAttribute('role', 'button');
|
|
666
|
-
element.setAttribute('tabindex', '0');
|
|
667
|
-
|
|
668
|
-
// Support clavier
|
|
669
|
-
element.addEventListener('keydown', function(e) {
|
|
670
|
-
if (e.key === 'Enter' || e.key === ' ') {
|
|
671
|
-
e.preventDefault();
|
|
672
|
-
bbContents.modules.share.share(network, data, element);
|
|
673
|
-
}
|
|
674
|
-
});
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
element.style.cursor = 'pointer';
|
|
678
|
-
});
|
|
679
|
-
|
|
680
|
-
bbContents.utils.log('Module Share initialisé:', elements.length, 'éléments');
|
|
603
|
+
linkedin: function(data) {
|
|
604
|
+
// LinkedIn - URL de partage officielle (2024+)
|
|
605
|
+
return 'https://www.linkedin.com/sharing/share-offsite/?url=' + encodeURIComponent(data.url);
|
|
606
|
+
},
|
|
607
|
+
whatsapp: function(data) {
|
|
608
|
+
return 'https://wa.me/?text=' +
|
|
609
|
+
encodeURIComponent(data.text + ' ' + data.url);
|
|
610
|
+
},
|
|
611
|
+
telegram: function(data) {
|
|
612
|
+
return 'https://t.me/share/url?url=' +
|
|
613
|
+
encodeURIComponent(data.url) +
|
|
614
|
+
'&text=' + encodeURIComponent(data.text);
|
|
681
615
|
},
|
|
616
|
+
email: function(data) {
|
|
617
|
+
return 'mailto:?subject=' +
|
|
618
|
+
encodeURIComponent(data.text) +
|
|
619
|
+
'&body=' + encodeURIComponent(data.text + ' ' + data.url);
|
|
620
|
+
},
|
|
621
|
+
copy: function(data) {
|
|
622
|
+
return 'copy:' + data.url;
|
|
623
|
+
},
|
|
624
|
+
native: function(data) {
|
|
625
|
+
return 'native:' + JSON.stringify(data);
|
|
626
|
+
}
|
|
627
|
+
},
|
|
628
|
+
|
|
629
|
+
// Détection
|
|
630
|
+
detect: function(scope) {
|
|
631
|
+
const s = scope || document;
|
|
632
|
+
return s.querySelector(bbContents._attrSelector('share')) !== null;
|
|
633
|
+
},
|
|
634
|
+
|
|
635
|
+
// Initialisation
|
|
636
|
+
init: function(root) {
|
|
637
|
+
const scope = root || document;
|
|
638
|
+
if (scope.closest && scope.closest('[data-bb-disable]')) return;
|
|
639
|
+
const elements = scope.querySelectorAll(bbContents._attrSelector('share'));
|
|
682
640
|
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
if (!networkFunc) {
|
|
688
|
-
return;
|
|
689
|
-
}
|
|
690
|
-
|
|
691
|
-
const shareUrl = networkFunc(data);
|
|
641
|
+
elements.forEach(function(element) {
|
|
642
|
+
// Vérifier si déjà traité
|
|
643
|
+
if (element.bbProcessed) return;
|
|
644
|
+
element.bbProcessed = true;
|
|
692
645
|
|
|
693
|
-
//
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
this.copyToClipboard(url, element, true);
|
|
698
|
-
return;
|
|
699
|
-
}
|
|
646
|
+
// Récupérer les données
|
|
647
|
+
const network = bbContents._getAttr(element, 'bb-share');
|
|
648
|
+
const customUrl = bbContents._getAttr(element, 'bb-url');
|
|
649
|
+
const customText = bbContents._getAttr(element, 'bb-text');
|
|
700
650
|
|
|
701
|
-
//
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
}
|
|
707
|
-
|
|
708
|
-
// Ouvrir popup de partage
|
|
709
|
-
const width = 600;
|
|
710
|
-
const height = 400;
|
|
711
|
-
const left = (window.innerWidth - width) / 2;
|
|
712
|
-
const top = (window.innerHeight - height) / 2;
|
|
651
|
+
// Valeurs par défaut sécurisées
|
|
652
|
+
const data = {
|
|
653
|
+
url: bbContents.utils.isValidUrl(customUrl) ? customUrl : window.location.href,
|
|
654
|
+
text: bbContents.utils.sanitize(customText || document.title || 'Découvrez ce site')
|
|
655
|
+
};
|
|
713
656
|
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
);
|
|
657
|
+
// Gestionnaire de clic
|
|
658
|
+
element.addEventListener('click', function(e) {
|
|
659
|
+
e.preventDefault();
|
|
660
|
+
bbContents.modules.share.share(network, data, element);
|
|
661
|
+
});
|
|
719
662
|
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
bbContents.modules.share.showFeedback(element, '✓ ' + (bbContents.config.i18n.copied || 'Lien copié !'));
|
|
663
|
+
// Accessibilité
|
|
664
|
+
if (element.tagName !== 'BUTTON' && element.tagName !== 'A') {
|
|
665
|
+
element.setAttribute('role', 'button');
|
|
666
|
+
element.setAttribute('tabindex', '0');
|
|
667
|
+
|
|
668
|
+
// Support clavier
|
|
669
|
+
element.addEventListener('keydown', function(e) {
|
|
670
|
+
if (e.key === 'Enter' || e.key === ' ') {
|
|
671
|
+
e.preventDefault();
|
|
672
|
+
bbContents.modules.share.share(network, data, element);
|
|
731
673
|
}
|
|
732
|
-
}).catch(function() {
|
|
733
|
-
bbContents.modules.share.fallbackCopy(text, element, isSilent);
|
|
734
674
|
});
|
|
735
|
-
} else {
|
|
736
|
-
// Fallback pour environnements sans Clipboard API
|
|
737
|
-
this.fallbackCopy(text, element, isSilent);
|
|
738
675
|
}
|
|
739
|
-
|
|
676
|
+
|
|
677
|
+
element.style.cursor = 'pointer';
|
|
678
|
+
});
|
|
740
679
|
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
// Afficher un prompt natif pour permettre à l'utilisateur de copier manuellement
|
|
748
|
-
// (solution universelle sans execCommand)
|
|
749
|
-
window.prompt('Copiez le lien ci-dessous (Ctrl/Cmd+C) :', text);
|
|
750
|
-
} catch (err) {
|
|
751
|
-
// Dernier recours: ne rien faire
|
|
752
|
-
}
|
|
753
|
-
},
|
|
680
|
+
bbContents.utils.log('Module Share initialisé:', elements.length, 'éléments');
|
|
681
|
+
},
|
|
682
|
+
|
|
683
|
+
// Fonction de partage
|
|
684
|
+
share: function(network, data, element) {
|
|
685
|
+
const networkFunc = this.networks[network];
|
|
754
686
|
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
if (navigator.share) {
|
|
759
|
-
navigator.share({
|
|
760
|
-
title: data.text,
|
|
761
|
-
url: data.url
|
|
762
|
-
}).then(function() {
|
|
763
|
-
bbContents.utils.log('Partage natif réussi');
|
|
764
|
-
}).catch(function(error) {
|
|
765
|
-
if (error.name !== 'AbortError') {
|
|
766
|
-
// Fallback vers copie si échec
|
|
767
|
-
bbContents.modules.share.copyToClipboard(data.url, element, false);
|
|
768
|
-
}
|
|
769
|
-
});
|
|
770
|
-
} else {
|
|
771
|
-
// Fallback si Web Share API non disponible
|
|
772
|
-
bbContents.utils.log('Web Share API non disponible, fallback vers copie');
|
|
773
|
-
this.copyToClipboard(data.url, element, false);
|
|
774
|
-
}
|
|
775
|
-
},
|
|
687
|
+
if (!networkFunc) {
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
776
690
|
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
691
|
+
const shareUrl = networkFunc(data);
|
|
692
|
+
|
|
693
|
+
// Cas spécial : copier le lien
|
|
694
|
+
if (shareUrl.startsWith('copy:')) {
|
|
695
|
+
const url = shareUrl.substring(5);
|
|
696
|
+
// Copie silencieuse (pas de feedback visuel)
|
|
697
|
+
this.copyToClipboard(url, element, true);
|
|
698
|
+
return;
|
|
699
|
+
}
|
|
700
|
+
|
|
701
|
+
// Cas spécial : partage natif (Web Share API)
|
|
702
|
+
if (shareUrl.startsWith('native:')) {
|
|
703
|
+
const shareData = JSON.parse(shareUrl.substring(7));
|
|
704
|
+
this.nativeShare(shareData, element);
|
|
705
|
+
return;
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
// Ouvrir popup de partage
|
|
709
|
+
const width = 600;
|
|
710
|
+
const height = 400;
|
|
711
|
+
const left = (window.innerWidth - width) / 2;
|
|
712
|
+
const top = (window.innerHeight - height) / 2;
|
|
713
|
+
|
|
714
|
+
window.open(
|
|
715
|
+
shareUrl,
|
|
716
|
+
'bbshare',
|
|
717
|
+
'width=' + width + ',height=' + height + ',left=' + left + ',top=' + top + ',noopener,noreferrer'
|
|
718
|
+
);
|
|
719
|
+
|
|
720
|
+
bbContents.utils.log('Partage sur', network, data);
|
|
721
|
+
},
|
|
722
|
+
|
|
723
|
+
// Copier dans le presse-papier
|
|
724
|
+
copyToClipboard: function(text, element, silent) {
|
|
725
|
+
const isSilent = !!silent;
|
|
726
|
+
// Méthode moderne
|
|
727
|
+
if (navigator.clipboard && navigator.clipboard.writeText) {
|
|
728
|
+
navigator.clipboard.writeText(text).then(function() {
|
|
729
|
+
if (!isSilent) {
|
|
730
|
+
bbContents.modules.share.showFeedback(element, '✓ ' + (bbContents.config.i18n.copied || 'Lien copié !'));
|
|
731
|
+
}
|
|
732
|
+
}).catch(function() {
|
|
733
|
+
bbContents.modules.share.fallbackCopy(text, element, isSilent);
|
|
734
|
+
});
|
|
735
|
+
} else {
|
|
736
|
+
// Fallback pour environnements sans Clipboard API
|
|
737
|
+
this.fallbackCopy(text, element, isSilent);
|
|
738
|
+
}
|
|
739
|
+
},
|
|
740
|
+
|
|
741
|
+
// Fallback copie
|
|
742
|
+
fallbackCopy: function(text, element, silent) {
|
|
743
|
+
const isSilent = !!silent;
|
|
744
|
+
// Pas de UI si silencieux (exigence produit)
|
|
745
|
+
if (isSilent) return;
|
|
746
|
+
try {
|
|
747
|
+
// Afficher un prompt natif pour permettre à l'utilisateur de copier manuellement
|
|
748
|
+
// (solution universelle sans execCommand)
|
|
749
|
+
window.prompt('Copiez le lien ci-dessous (Ctrl/Cmd+C) :', text);
|
|
750
|
+
} catch (err) {
|
|
751
|
+
// Dernier recours: ne rien faire
|
|
752
|
+
}
|
|
753
|
+
},
|
|
754
|
+
|
|
755
|
+
// Partage natif (Web Share API)
|
|
756
|
+
nativeShare: function(data, element) {
|
|
757
|
+
// Vérifier si Web Share API est disponible
|
|
758
|
+
if (navigator.share) {
|
|
759
|
+
navigator.share({
|
|
760
|
+
title: data.text,
|
|
761
|
+
url: data.url
|
|
762
|
+
}).then(function() {
|
|
763
|
+
bbContents.utils.log('Partage natif réussi');
|
|
764
|
+
}).catch(function(error) {
|
|
765
|
+
if (error.name !== 'AbortError') {
|
|
766
|
+
// Fallback vers copie si échec
|
|
767
|
+
bbContents.modules.share.copyToClipboard(data.url, element, false);
|
|
768
|
+
}
|
|
769
|
+
});
|
|
770
|
+
} else {
|
|
771
|
+
// Fallback si Web Share API non disponible
|
|
772
|
+
bbContents.utils.log('Web Share API non disponible, fallback vers copie');
|
|
773
|
+
this.copyToClipboard(data.url, element, false);
|
|
787
774
|
}
|
|
788
775
|
},
|
|
776
|
+
|
|
777
|
+
// Feedback visuel
|
|
778
|
+
showFeedback: function(element, message) {
|
|
779
|
+
const originalText = element.textContent;
|
|
780
|
+
element.textContent = message;
|
|
781
|
+
element.style.pointerEvents = 'none';
|
|
782
|
+
|
|
783
|
+
setTimeout(function() {
|
|
784
|
+
element.textContent = originalText;
|
|
785
|
+
element.style.pointerEvents = '';
|
|
786
|
+
}, 2000);
|
|
787
|
+
}
|
|
788
|
+
},
|
|
789
789
|
|
|
790
790
|
// Module Current Year (Année courante)
|
|
791
791
|
currentYear: {
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
792
|
+
detect: function(scope) {
|
|
793
|
+
const s = scope || document;
|
|
794
|
+
return s.querySelector(bbContents._attrSelector('current-year')) !== null;
|
|
795
|
+
},
|
|
796
|
+
init: function(root) {
|
|
797
|
+
const scope = root || document;
|
|
798
|
+
if (scope.closest && scope.closest('[data-bb-disable]')) return;
|
|
799
|
+
const elements = scope.querySelectorAll(bbContents._attrSelector('current-year'));
|
|
800
800
|
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
801
|
+
const year = String(new Date().getFullYear());
|
|
802
|
+
elements.forEach(function(element) {
|
|
803
|
+
if (element.bbProcessed) return;
|
|
804
|
+
element.bbProcessed = true;
|
|
805
805
|
|
|
806
806
|
const customFormat = bbContents._getAttr(element, 'bb-current-year-format');
|
|
807
807
|
const prefix = bbContents._getAttr(element, 'bb-current-year-prefix');
|
|
808
808
|
const suffix = bbContents._getAttr(element, 'bb-current-year-suffix');
|
|
809
809
|
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
810
|
+
if (customFormat && customFormat.includes('{year}')) {
|
|
811
|
+
element.textContent = customFormat.replace('{year}', year);
|
|
812
|
+
} else if (prefix || suffix) {
|
|
813
|
+
element.textContent = prefix + year + suffix;
|
|
814
|
+
} else {
|
|
815
|
+
element.textContent = year;
|
|
816
|
+
}
|
|
817
|
+
});
|
|
818
818
|
|
|
819
|
-
|
|
820
|
-
|
|
819
|
+
bbContents.utils.log('Module CurrentYear initialisé:', elements.length, 'éléments');
|
|
820
|
+
}
|
|
821
821
|
},
|
|
822
822
|
|
|
823
823
|
// Module Reading Time (Temps de lecture)
|
|
824
824
|
readingTime: {
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
825
|
+
detect: function(scope) {
|
|
826
|
+
const s = scope || document;
|
|
827
|
+
return s.querySelector(bbContents._attrSelector('reading-time')) !== null;
|
|
828
|
+
},
|
|
829
|
+
init: function(root) {
|
|
830
|
+
const scope = root || document;
|
|
831
|
+
if (scope.closest && scope.closest('[data-bb-disable]')) return;
|
|
832
|
+
const elements = scope.querySelectorAll(bbContents._attrSelector('reading-time'));
|
|
833
833
|
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
834
|
+
elements.forEach(function(element) {
|
|
835
|
+
if (element.bbProcessed) return;
|
|
836
|
+
element.bbProcessed = true;
|
|
837
837
|
|
|
838
838
|
const targetSelector = bbContents._getAttr(element, 'bb-reading-time-target');
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
839
|
+
const speedAttr = bbContents._getAttr(element, 'bb-reading-time-speed');
|
|
840
|
+
const imageSpeedAttr = bbContents._getAttr(element, 'bb-reading-time-image-speed');
|
|
841
|
+
const format = bbContents._getAttr(element, 'bb-reading-time-format') || '{minutes} min';
|
|
842
842
|
|
|
843
|
-
|
|
844
|
-
|
|
843
|
+
const wordsPerMinute = Number(speedAttr) > 0 ? Number(speedAttr) : 230;
|
|
844
|
+
const secondsPerImage = Number(imageSpeedAttr) > 0 ? Number(imageSpeedAttr) : 12;
|
|
845
845
|
|
|
846
846
|
// Validation des valeurs
|
|
847
847
|
if (isNaN(wordsPerMinute) || wordsPerMinute <= 0) {
|
|
@@ -851,125 +851,125 @@
|
|
|
851
851
|
bbContents.utils.log('Temps par image invalide, utilisation de la valeur par défaut (12)');
|
|
852
852
|
}
|
|
853
853
|
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
854
|
+
let sourceNode = element;
|
|
855
|
+
if (targetSelector) {
|
|
856
|
+
const found = document.querySelector(targetSelector);
|
|
857
|
+
if (found) sourceNode = found;
|
|
858
|
+
}
|
|
859
859
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
860
|
+
const text = (sourceNode.textContent || '').trim();
|
|
861
|
+
const wordCount = text ? (text.match(/\b\w+\b/g) || []).length : 0;
|
|
862
|
+
|
|
863
|
+
// Compter les images dans le contenu ciblé
|
|
864
|
+
const images = sourceNode.querySelectorAll('img');
|
|
865
|
+
const imageCount = images.length;
|
|
866
|
+
const imageTimeInMinutes = (imageCount * secondsPerImage) / 60;
|
|
867
|
+
|
|
868
|
+
let minutesFloat = (wordCount / wordsPerMinute) + imageTimeInMinutes;
|
|
869
|
+
let minutes = Math.ceil(minutesFloat);
|
|
870
870
|
|
|
871
|
-
|
|
872
|
-
|
|
871
|
+
if ((wordCount > 0 || imageCount > 0) && minutes < 1) minutes = 1; // affichage minimal 1 min si contenu non vide
|
|
872
|
+
if (wordCount === 0 && imageCount === 0) minutes = 0;
|
|
873
873
|
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
874
|
+
const output = format.replace('{minutes}', String(minutes));
|
|
875
|
+
element.textContent = output;
|
|
876
|
+
});
|
|
877
877
|
|
|
878
|
-
|
|
879
|
-
|
|
878
|
+
bbContents.utils.log('Module ReadingTime initialisé:', elements.length, 'éléments');
|
|
879
|
+
}
|
|
880
880
|
},
|
|
881
881
|
|
|
882
882
|
// Module Favicon (Favicon Dynamique)
|
|
883
883
|
favicon: {
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
884
|
+
originalFavicon: null,
|
|
885
|
+
|
|
886
|
+
// Détection
|
|
887
|
+
detect: function(scope) {
|
|
888
|
+
const s = scope || document;
|
|
889
|
+
return s.querySelector(bbContents._attrSelector('favicon')) !== null;
|
|
890
|
+
},
|
|
891
|
+
|
|
892
|
+
// Initialisation
|
|
893
|
+
init: function(root) {
|
|
894
|
+
const scope = root || document;
|
|
895
|
+
if (scope.closest && scope.closest('[data-bb-disable]')) return;
|
|
891
896
|
|
|
892
|
-
//
|
|
893
|
-
init: function(root) {
|
|
894
|
-
const scope = root || document;
|
|
895
|
-
if (scope.closest && scope.closest('[data-bb-disable]')) return;
|
|
896
|
-
|
|
897
|
-
// Chercher les éléments avec bb-favicon ou bb-favicon-dark
|
|
897
|
+
// Chercher les éléments avec bb-favicon ou bb-favicon-dark
|
|
898
898
|
const elements = scope.querySelectorAll(bbContents._attrSelector('favicon') + ', ' + bbContents._attrSelector('favicon-dark'));
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
// Sauvegarder le favicon original
|
|
902
|
-
const existingLink = document.querySelector("link[rel*='icon']");
|
|
903
|
-
if (existingLink) {
|
|
904
|
-
this.originalFavicon = existingLink.href;
|
|
905
|
-
}
|
|
906
|
-
|
|
907
|
-
// Collecter les URLs depuis tous les éléments
|
|
908
|
-
let faviconUrl = null;
|
|
909
|
-
let darkUrl = null;
|
|
910
|
-
|
|
911
|
-
elements.forEach(function(element) {
|
|
912
|
-
const light = bbContents._getAttr(element, 'bb-favicon') || bbContents._getAttr(element, 'favicon');
|
|
913
|
-
const dark = bbContents._getAttr(element, 'bb-favicon-dark') || bbContents._getAttr(element, 'favicon-dark');
|
|
914
|
-
|
|
915
|
-
if (light) faviconUrl = light;
|
|
916
|
-
if (dark) darkUrl = dark;
|
|
917
|
-
});
|
|
918
|
-
|
|
919
|
-
// Appliquer la logique
|
|
920
|
-
if (faviconUrl && darkUrl) {
|
|
921
|
-
this.setupDarkMode(faviconUrl, darkUrl);
|
|
922
|
-
} else if (faviconUrl) {
|
|
923
|
-
this.setFavicon(faviconUrl);
|
|
924
|
-
bbContents.utils.log('Favicon changé:', faviconUrl);
|
|
925
|
-
}
|
|
926
|
-
},
|
|
899
|
+
if (elements.length === 0) return;
|
|
927
900
|
|
|
928
|
-
//
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
favicon = document.createElement('link');
|
|
934
|
-
favicon.rel = 'icon';
|
|
935
|
-
document.head.appendChild(favicon);
|
|
936
|
-
}
|
|
937
|
-
return favicon;
|
|
938
|
-
},
|
|
901
|
+
// Sauvegarder le favicon original
|
|
902
|
+
const existingLink = document.querySelector("link[rel*='icon']");
|
|
903
|
+
if (existingLink) {
|
|
904
|
+
this.originalFavicon = existingLink.href;
|
|
905
|
+
}
|
|
939
906
|
|
|
940
|
-
//
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
// Ajouter un timestamp pour forcer le rafraîchissement du cache
|
|
945
|
-
const cacheBuster = '?v=' + Date.now();
|
|
946
|
-
const urlWithCacheBuster = url + cacheBuster;
|
|
947
|
-
|
|
948
|
-
const favicon = this.getFaviconElement();
|
|
949
|
-
favicon.href = urlWithCacheBuster;
|
|
950
|
-
},
|
|
907
|
+
// Collecter les URLs depuis tous les éléments
|
|
908
|
+
let faviconUrl = null;
|
|
909
|
+
let darkUrl = null;
|
|
951
910
|
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
955
|
-
const updateFavicon = function(e) {
|
|
956
|
-
const darkModeOn = e ? e.matches : window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
957
|
-
const selectedUrl = darkModeOn ? darkUrl : lightUrl;
|
|
958
|
-
bbContents.modules.favicon.setFavicon(selectedUrl);
|
|
959
|
-
};
|
|
960
|
-
|
|
961
|
-
// Initialiser le favicon au chargement de la page
|
|
962
|
-
updateFavicon();
|
|
911
|
+
elements.forEach(function(element) {
|
|
912
|
+
const light = bbContents._getAttr(element, 'bb-favicon') || bbContents._getAttr(element, 'favicon');
|
|
913
|
+
const dark = bbContents._getAttr(element, 'bb-favicon-dark') || bbContents._getAttr(element, 'favicon-dark');
|
|
963
914
|
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
915
|
+
if (light) faviconUrl = light;
|
|
916
|
+
if (dark) darkUrl = dark;
|
|
917
|
+
});
|
|
918
|
+
|
|
919
|
+
// Appliquer la logique
|
|
920
|
+
if (faviconUrl && darkUrl) {
|
|
921
|
+
this.setupDarkMode(faviconUrl, darkUrl);
|
|
922
|
+
} else if (faviconUrl) {
|
|
923
|
+
this.setFavicon(faviconUrl);
|
|
924
|
+
bbContents.utils.log('Favicon changé:', faviconUrl);
|
|
971
925
|
}
|
|
972
926
|
},
|
|
927
|
+
|
|
928
|
+
// Helper: Récupérer ou créer un élément favicon
|
|
929
|
+
getFaviconElement: function() {
|
|
930
|
+
let favicon = document.querySelector('link[rel="icon"]') ||
|
|
931
|
+
document.querySelector('link[rel="shortcut icon"]');
|
|
932
|
+
if (!favicon) {
|
|
933
|
+
favicon = document.createElement('link');
|
|
934
|
+
favicon.rel = 'icon';
|
|
935
|
+
document.head.appendChild(favicon);
|
|
936
|
+
}
|
|
937
|
+
return favicon;
|
|
938
|
+
},
|
|
939
|
+
|
|
940
|
+
// Changer le favicon
|
|
941
|
+
setFavicon: function(url) {
|
|
942
|
+
if (!url) return;
|
|
943
|
+
|
|
944
|
+
// Ajouter un timestamp pour forcer le rafraîchissement du cache
|
|
945
|
+
const cacheBuster = '?v=' + Date.now();
|
|
946
|
+
const urlWithCacheBuster = url + cacheBuster;
|
|
947
|
+
|
|
948
|
+
const favicon = this.getFaviconElement();
|
|
949
|
+
favicon.href = urlWithCacheBuster;
|
|
950
|
+
},
|
|
951
|
+
|
|
952
|
+
// Support dark mode (méthode simplifiée et directe)
|
|
953
|
+
setupDarkMode: function(lightUrl, darkUrl) {
|
|
954
|
+
// Fonction pour mettre à jour le favicon selon le mode sombre
|
|
955
|
+
const updateFavicon = function(e) {
|
|
956
|
+
const darkModeOn = e ? e.matches : window.matchMedia('(prefers-color-scheme: dark)').matches;
|
|
957
|
+
const selectedUrl = darkModeOn ? darkUrl : lightUrl;
|
|
958
|
+
bbContents.modules.favicon.setFavicon(selectedUrl);
|
|
959
|
+
};
|
|
960
|
+
|
|
961
|
+
// Initialiser le favicon au chargement de la page
|
|
962
|
+
updateFavicon();
|
|
963
|
+
|
|
964
|
+
// Écouter les changements du mode sombre
|
|
965
|
+
const darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)');
|
|
966
|
+
if (typeof darkModeMediaQuery.addEventListener === 'function') {
|
|
967
|
+
darkModeMediaQuery.addEventListener('change', updateFavicon);
|
|
968
|
+
} else if (typeof darkModeMediaQuery.addListener === 'function') {
|
|
969
|
+
darkModeMediaQuery.addListener(updateFavicon);
|
|
970
|
+
}
|
|
971
|
+
}
|
|
972
|
+
},
|
|
973
973
|
|
|
974
974
|
// Module YouTube Feed
|
|
975
975
|
youtube: {
|
|
@@ -1022,7 +1022,7 @@
|
|
|
1022
1022
|
}
|
|
1023
1023
|
},
|
|
1024
1024
|
|
|
1025
|
-
|
|
1025
|
+
detect: function(scope) {
|
|
1026
1026
|
return scope.querySelector('[bb-youtube-channel]') !== null;
|
|
1027
1027
|
},
|
|
1028
1028
|
|
|
@@ -1091,7 +1091,7 @@
|
|
|
1091
1091
|
} else {
|
|
1092
1092
|
// Timeout après 5 secondes
|
|
1093
1093
|
element.innerHTML = '<div style="padding: 20px; background: #fef2f2; border: 1px solid #fecaca; border-radius: 8px; color: #dc2626;"><strong>Configuration YouTube manquante</strong><br>Ajoutez dans le <head> :<br><code style="display: block; background: #f3f4f6; padding: 10px; margin: 10px 0; border-radius: 4px; font-family: monospace;"><script><br>bbContents.config.youtubeEndpoint = \'votre-worker-url\';<br></script></code></div>';
|
|
1094
|
-
|
|
1094
|
+
return;
|
|
1095
1095
|
}
|
|
1096
1096
|
}
|
|
1097
1097
|
|
|
@@ -1110,9 +1110,9 @@
|
|
|
1110
1110
|
|
|
1111
1111
|
if (!template) {
|
|
1112
1112
|
element.innerHTML = '<div style="padding: 20px; background: #fef2f2; border: 1px solid #fecaca; border-radius: 8px; color: #dc2626;"><strong>Template manquant</strong><br>Ajoutez un élément avec l\'attribut bb-youtube-item</div>';
|
|
1113
|
-
|
|
1114
|
-
|
|
1115
|
-
|
|
1113
|
+
return;
|
|
1114
|
+
}
|
|
1115
|
+
|
|
1116
1116
|
// Cacher le template original
|
|
1117
1117
|
template.style.display = 'none';
|
|
1118
1118
|
|
|
@@ -1139,7 +1139,7 @@
|
|
|
1139
1139
|
const newCachedData = this.cache.get(cacheKey);
|
|
1140
1140
|
if (newCachedData && newCachedData.value) {
|
|
1141
1141
|
this.generateYouTubeFeed(container, template, newCachedData.value, allowShorts, language);
|
|
1142
|
-
|
|
1142
|
+
} else {
|
|
1143
1143
|
container.innerHTML = '<div style="padding: 20px; text-align: center; color: #6b7280;">Erreur de chargement</div>';
|
|
1144
1144
|
}
|
|
1145
1145
|
} else {
|
|
@@ -1284,7 +1284,7 @@
|
|
|
1284
1284
|
if (bbContents.config.debug) {
|
|
1285
1285
|
// Thumbnail optimisée
|
|
1286
1286
|
}
|
|
1287
|
-
|
|
1287
|
+
} else {
|
|
1288
1288
|
// Aucune thumbnail disponible
|
|
1289
1289
|
}
|
|
1290
1290
|
}
|