J’essaie de rendre les publications anonymes encore plus anonymes en remplaçant la façon dont les citations sont affichées dans les catégories où seule la publication anonyme est autorisée. Ainsi, au lieu de la valeur par défaut :
anonymous4302934
un texte cité
ce que je veux, c’est :
Anonyme :
un texte cité
Je parviens à le faire pour le texte cité via le bouton de la barre d’outils, en me basant sur How to override the buildQuote function? - #7 by Canapin (j’ai dû ajouter une recherche de conteneur en bas pour que cela fonctionne, conformément à la solution de contournement présentée ici : api.modifyClass sometimes(!) not working - #12 by RGJ).
J’ai fouillé dans les fichiers principaux et je n’arrive pas à déterminer exactement où la citation est générée lorsqu’une citation est insérée dans le compositeur via la sélection et en cliquant sur le bouton de citation. Je vois dans _selectionChanged() dans quote-button.js que opts.username est défini si le texte sélectionné se trouve dans un bloc de citation, mais si j’essaie de le modifier pour définir manuellement opts.username, cela n’a aucun effet.
Est-ce la bonne approche pour remplacer cela ? Est-ce que modifyClass est la bonne méthode pour aborder ce problème ?
<script type="text/discourse-plugin" version="0.8">
const controller = api.container.lookup('controller:topic');
const anon_categories = [5, 6, 14, 15, 16, 17, 18]
function buildQuote(post, contents, opts = {}) {
if (!post || !contents) {
return "";
}
let anon_name = ``;
// console.log(anon_categories, controller.get("model.category_id"))
if (anon_categories.includes(controller.get("model.category_id"))) {
anon_name = `Anonyme`;
} else {
anon_name = opts.username || post.username;
}
const params = [
anon_name,
`post:${opts.post || post.post_number}`,
`topic:${opts.topic || post.topic_id}`
];
if (opts.full) params.push("full:true");
return `\n[quote="${params.join(", ")}"]\n${contents.trim()}\n[/quote]\n\n`;
}
api.modifyClass('controller:composer', {
pluginId: 'anonymize-quotes',
actions: {
importQuote(toolbarEvent) {
const postStream = this.get("topic.postStream");
let postId = this.get("model.post.id");
// Si aucun post actuel, utiliser le premier ID de post du flux
if (!postId && postStream) {
postId = postStream.get("stream.firstObject");
}
// Si nous modifions un post, récupérer la réponse lors de l'importation d'une citation
if (this.get("model.editingPost")) {
const replyToPostNumber = this.get("model.post.reply_to_post_number");
if (replyToPostNumber) {
const replyPost = postStream.posts.findBy(
"post_number",
replyToPostNumber
);
if (replyPost) {
postId = replyPost.id;
}
}
}
if (postId) {
this.set("model.loading", true);
return this.store.find("post", postId).then(post => {
const quote = buildQuote(post, post.raw, {
full: true
});
toolbarEvent.addText(quote);
this.set("model.loading", false);
});
}
}
}
});
api.modifyClass('component:quote-button', {
pluginId: 'anonymize-quotes',
actions: {
_selectionChanged() {
if (this._displayFastEditInput) {
return;
}
const quoteState = this.quoteState;
const selection = window.getSelection();
if (selection.isCollapsed) {
if (this.visible) {
this._hideButton();
}
return;
}
// s'assurer que nous avons sélectionné du contenu dans un seul post *seulement*
let firstRange, postId;
for (let r = 0; r < selection.rangeCount; r++) {
const range = selection.getRangeAt(r);
const $selectionStart = $(range.startContainer);
const $ancestor = $(range.commonAncestorContainer);
if ($selectionStart.closest(".cooked").length === 0) {
return;
}
firstRange = firstRange || range;
postId = postId || $ancestor.closest(".boxed, .reply").data("post-id");
if ($ancestor.closest(".contents").length === 0 || !postId) {
if (this.visible) {
this._hideButton();
}
return;
}
}
const _selectedElement = selectedElement();
const _selectedText = selectedText();
const $selectedElement = $(_selectedElement);
const cooked =
$selectedElement.find(".cooked")[0] ||
$selectedElement.closest(".cooked")[0];
// le calcul du markdown prend beaucoup de temps sur les longs posts
// ce code tente de le calculer uniquement lorsque nous ne pouvons pas accélérer le processus
let opts = {
full:
selectedRange().startOffset > 0
? false
: _selectedText === toMarkdown(cooked.innerHTML),
};
for (
let element = _selectedElement;
element && element.tagName !== "ARTICLE";
element = element.parentElement
) {
if (element.tagName === "ASIDE" && element.classList.contains("quote")) {
opts.username = element.dataset.username || getQuoteTitle(element);
opts.post = element.dataset.post;
opts.topic = element.dataset.topic;
break;
}
}
opts.username = `Anonyme`
quoteState.selected(postId, _selectedText, opts);
this.set("visible", quoteState.buffer.length > 0);
if (this.siteSettings.enable_fast_edit) {
this.set(
"_canEditPost",
this.topic.postStream.findLoadedPost(postId)?.can_edit
);
if (this._canEditPost) {
const regexp = new RegExp(regexSafeStr(quoteState.buffer), "gi");
const matches = cooked.innerHTML.match(regexp);
if (
quoteState.buffer.length < 1 ||
quoteState.buffer.includes("|") || // les tableaux sont trop complexes
quoteState.buffer.match(/\n/g) || // les sauts de ligne sont trop complexes
matches?.length > 1 // les doublons sont trop complexes
) {
this.set("_isFastEditable", false);
this.set("_fastEditInitalSelection", null);
this.set("_fastEditNewSelection", null);
} else if (matches?.length === 1) {
this.set("_isFastEditable", true);
this.set("_fastEditInitalSelection", quoteState.buffer);
this.set("_fastEditNewSelection", quoteState.buffer);
}
}
}
// éviter les boucles infinies dans la sélection de citation sans condition
// cela peut arriver si vous cliquez trois fois sur du texte dans Firefox
if (this._prevSelection === _selectedText) {
return;
}
this._prevSelection = _selectedText;
// sur Desktop, affiche le bouton au début de la sélection
// sur Mobile, affiche le bouton à la fin de la sélection
const isMobileDevice = this.site.isMobileDevice;
const { isIOS, isAndroid, isOpera } = this.capabilities;
const showAtEnd = isMobileDevice || isIOS || isAndroid || isOpera;
const boundaryPosition = this._getRangeBoundaryRect(firstRange, showAtEnd);
// changer la position du bouton
schedule("afterRender", () => {
if (!this.element || this.isDestroying || this.isDestroyed) {
return;
}
let top = 0;
let left = 0;
const pxFromSelection = 5;
if (showAtEnd) {
// Les poignées de sélection sur iOS ont une zone de clic d'environ 50px de rayon
// nous devons donc nous assurer que nos boutons sont en dehors de ce rayon
// Appliquer la même logique sur tous les appareils mobiles pour la cohérence
top = boundaryPosition.bottom + pxFromSelection;
left = boundaryPosition.left;
const safeRadius = 50;
const topicArea = document
.querySelector(".topic-area")
.getBoundingClientRect();
topicArea.x += document.documentElement.scrollLeft;
topicArea.y += document.documentElement.scrollTop;
const endHandlePosition = boundaryPosition;
const width = this.element.clientWidth;
const possiblePositions = [
{
// déplacer vers la gauche
top,
left: left - width - safeRadius,
},
{
// déplacer vers la droite
top,
left: left + safeRadius,
},
{
// centré sous la poignée de fin
top: top + safeRadius,
left: left - width / 2,
},
];
for (const pos of possiblePositions) {
// S'assurer que les boutons sont entièrement dans .topic-area
pos.left = Math.max(topicArea.left, pos.left);
pos.left = Math.min(topicArea.right - width, pos.left);
let clearOfStartHandle = true;
if (isAndroid) {
// Sur Android, la poignée de sélection de départ s'étend sous la ligne, nous devons donc l'éviter également :
const startHandlePosition = this._getRangeBoundaryRect(
firstRange,
false
);
clearOfStartHandle =
pos.top - startHandlePosition.bottom >= safeRadius ||
pos.left + width <= startHandlePosition.left - safeRadius ||
pos.left >= startHandlePosition.left + safeRadius;
}
const clearOfEndHandle =
pos.top - endHandlePosition.top >= safeRadius ||
pos.left + width <= endHandlePosition.left - safeRadius ||
pos.left >= endHandlePosition.left + safeRadius;
if (clearOfStartHandle && clearOfEndHandle) {
left = pos.left;
top = pos.top;
break;
}
}
} else {
// Desktop
top =
boundaryPosition.top - this.element.clientHeight - pxFromSelection;
left = boundaryPosition.left;
}
Object.assign(this.element.style, { top: `${top}px`, left: `${left}px` });
if (!this.animated) {
// Nous n'activons les transitions CSS qu'après le positionnement initial
// sinon le bouton peut sembler arriver de l'écran
next(() => this.set("animated", true));
}
});
}
}
});
const composerController = api.container.lookup("controller:composer");
const componentQuoteButton = api.container.lookup("component:quote-button");
</script>