Sì, aggiungere un URL causerà la navigazione, dato che non esiste una logica per intercettare l’evento.
Il link sta chiamando un’azione di Ember. Tutte le azioni in Discourse sono estendibili. Quindi, agiscono in un certo senso come hook di personalizzazione. Allora, come si modifica un’azione? Bene, controlliamo prima cosa fa.
Cerca su GitHub o localmente il nome dell’azione. Le azioni sono sempre definite nei file JS e richiamate in Handlebars. Vogliamo vedere la definizione, quindi restringiamo la ricerca ai file JS.
Repository search results · GitHub
Otterrai quattro file. Quale dovresti esaminare? Vuoi personalizzare il
discovery/topics.hbs
template. Quindi
discovery/topics.js
è quello che ti serve.
C’è qualche parte di questo codice che può esserti utile? No, ma ora sappiamo dove è definita l’azione. Quindi, modifichiamola.
discovery/topics.js è una classe Ember. Puoi modificare le classi Ember con un metodo nell’API dei plugin chiamato… modifyClass ![]()
Sappiamo già la Classe che vogliamo modificare. È discovery/topics. Dobbiamo sapere che tipo di Classe sia. Quindi, controlliamo la directory dei file.
discourse/app/controllers/discovery/topics.js
È un controller.
Sappiamo anche che vogliamo modificare l’azione showInserted in quella Classe. Quindi, iniziamo così.
api.modifyClass("controller:discovery/topics", {
pluginId: 'sticky-new-topics-banner',
actions: {
showInserted() {
// facciamo un po' di lavoro
}
}
});
Puoi quindi aggiungere tutto il codice che desideri per scorrere la finestra quando l’utente clicca sul banner “nuovi argomenti”. Io ho optato per qualcosa di simile.
const listControls = document.querySelector(".list-controls");
listControls.scrollIntoView();
Puoi leggere di più su scrollIntoView() qui.
Poi aggiungi questo al metodo plugin-api in questo modo.
api.modifyClass("controller:discovery/topics", {
pluginId: 'sticky-new-topics-banner',
actions: {
showInserted() {
+ const listControls = document.querySelector(".list-controls");
+ listControls.scrollIntoView();
}
}
});
Allora, abbiamo finito? No. Questo rompe Discourse perché stai sovrascrivendo completamente l’azione. Cliccando il link ora si scorrerà fino all’elemento list-controls, ma non caricherà i nuovi argomenti. Perché? Perché il codice nel core non viene più applicato. Intendo, questa roba qui
Allora, come si risolve? Con questa semplice riga
this._super(...arguments);
Non devi copiare alcun codice dal core se vuoi solo aggiungerci qualcosa. Fai il tuo lavoro, poi aggiungi quella riga. Tutto quello che fa è assicurarsi che il codice del core venga applicato.
api.modifyClass("controller:discovery/topics", {
pluginId: 'sticky-new-topics-banner',
actions: {
showInserted() {
const listControls = document.querySelector(".list-controls");
listControls.scrollIntoView();
+
+ this._super(...arguments);
}
}
});
Se provi questo, vedrai che quasi tutto funziona benissimo, tranne… l’intestazione si sovrappone a list-controls. Perché? Perché l’intestazione è impostata come sticky.
Puoi risolvere in diversi modi in JS: calcolare l’altezza, ottenere l’offset, importare un helper da Discourse… ecc. Non entrerò in questi dettagli.
Il modo più semplice è con CSS usando scroll-margin-top, di cui puoi leggere qui.
Quindi, aggiungiamo questo
.list-controls {
scroll-margin-top: calc(var(--header-offset) * 2);
}
In inglese: Quando il link viene cliccato, scorri fino alla parte superiore di list-controls - 2 * l’altezza dell’intestazione, così non si sovrappone e ha un po’ di spazio sotto di essa.
Quindi, mettiamo tutto insieme.
scheda header comune
<script type="text/discourse-plugin" version="0.8">
api.modifyClass("controller:discovery/topics", {
pluginId: "sticky-new-topics-banner",
actions: {
showInserted() {
const listControls = document.querySelector(".list-controls");
listControls.scrollIntoView();
this._super(...arguments);
}
}
});
</script>
CSS comune
#list-area {
// mobile ha un layout diverso
.alert-info,
.show-more.has-topics {
position: sticky;
// safari a volte è capriccioso senza il prefisso
position: -webkit-sticky;
top: var(--header-offset);
// il banner deve essere sopra il contenuto
z-index: z("header");
}
}
.list-controls {
scroll-margin-top: calc(var(--header-offset) * 2);
}