Estoy intentando hacer que las publicaciones anónimas sean más anónimas anulando cómo se muestran las citas en las categorías donde solo está habilitada la publicación anónima. Así que, en lugar del predeterminado
anonymous4302934
algun texto citado
lo que quiero es
Anónimo:
algún texto citado
Puedo hacer esto con el texto que se cita mediante el botón de la barra de herramientas, basado en How to override the buildQuote function? - #7 by Canapin (tuve que agregar una búsqueda de contenedor al final para que funcionara según la solución alternativa aquí: api.modifyClass sometimes(!) not working - #12 by RGJ).
He revisado los archivos principales y no puedo determinar exactamente dónde se construye la cita cuando se inserta una cita en el compositor mediante la selección y haciendo clic en el botón de cita. Veo en _selectionChanged() en quote-button.js que opts.username se establece si el texto seleccionado está en un blockquote, pero si intento modificar esto para establecer manualmente opts.username, no afecta nada.
¿Es esto lo correcto para intentar anular? ¿Es modifyClass la forma correcta de abordar esto?
<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 = `Anonymous`;
} 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 no hay publicación actual, usa el primer ID de publicación del flujo
if (!postId && postStream) {
postId = postStream.get("stream.firstObject");
}
// Si estamos editando una publicación, obtén la respuesta al importar una cita
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;
}
// asegurarnos de que solo se seleccionó contenido dentro de 1 publicación
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];
// calcular markdown toma mucho tiempo en publicaciones largas
// este código intenta calcularlo solo cuando no podemos acelerar
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 = `Anonymous`
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("|") || // las tablas son demasiado complejas
quoteState.buffer.match(/\n/g) || // los saltos de línea son demasiado complejos
matches?.length > 1 // los duplicados son demasiado complejos
) {
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);
}
}
}
// evitar bucles duros en la selección de citas incondicionalmente
// esto puede suceder si haces triple clic en el texto en Firefox
if (this._prevSelection === _selectedText) {
return;
}
this._prevSelection = _selectedText;
// en escritorio, muestra el botón al inicio de la selección
// en móvil, muestra el botón al final de la selección
const isMobileDevice = this.site.isMobileDevice;
const { isIOS, isAndroid, isOpera } = this.capabilities;
const showAtEnd = isMobileDevice || isIOS || isAndroid || isOpera;
const boundaryPosition = this._getRangeBoundaryRect(firstRange, showAtEnd);
// cambiar la posición del botón
schedule("afterRender", () => {
if (!this.element || this.isDestroying || this.isDestroyed) {
return;
}
let top = 0;
let left = 0;
const pxFromSelection = 5;
if (showAtEnd) {
// Los manejadores de selección en iOS tienen un área de impacto de ~50px de radio
// así que debemos asegurarnos de que nuestros botones estén fuera de ese radio
// Aplicar la misma lógica en todos los dispositivos móviles para consistencia
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 = [
{
// mover a la izquierda
top,
left: left - width - safeRadius,
},
{
// mover a la derecha
top,
left: left + safeRadius,
},
{
// centrado debajo del manejador final
top: top + safeRadius,
left: left - width / 2,
},
];
for (const pos of possiblePositions) {
// Asegurar que los botones estén completamente dentro de .topic-area
pos.left = Math.max(topicArea.left, pos.left);
pos.left = Math.min(topicArea.right - width, pos.left);
let clearOfStartHandle = true;
if (isAndroid) {
// En Android, el manejador de selección inicial se extiende por debajo de la línea, así que también debemos evitarlo:
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 {
// Escritorio
top =
boundaryPosition.top - this.element.clientHeight - pxFromSelection;
left = boundaryPosition.left;
}
Object.assign(this.element.style, { top: `${top}px`, left: `${left}px` });
if (!this.animated) {
// Solo habilitamos las transiciones CSS después de la posición inicial
// de lo contrario, el botón puede parecer que vuela desde fuera de la pantalla
next(() => this.set("animated", true));
}
});
}
}
});
const composerController = api.container.lookup("controller:composer");
const componentQuoteButton = api.container.lookup("component:quote-button");
</script>