Ja, das Hinzufügen einer URL führt zu einer Navigation, da es keine Logik gibt, die das Ereignis abfängt.
Der Link ruft eine Ember-Aktion auf. Alle Aktionen in Discourse sind erweiterbar. Sie wirken also gewissermaßen wie Anpassungshooks. Wie modifiziert man also eine Aktion? Nun, schauen wir uns zunächst an, was sie tut.
Suche auf GitHub oder lokal nach dem Namen der Aktion. Aktionen werden immer in JS-Dateien definiert und in Handlebars referenziert. Wir wollen die Definition sehen, also beschränken wir die Suche auf JS-Dateien.
Repository search results · GitHub
Du erhältst vier Dateien. Welche solltest du dir ansehen? Du möchtest die
discovery/topics.hbs
Vorlage anpassen. Also ist
discovery/topics.js
das, was du dir ansehen solltest.
Ist irgendeiner dieser Codeabschnitte hilfreich? Nein, aber jetzt wissen wir, wo die Aktion definiert ist. Also ändern wir sie.
discovery/topics.js ist eine Ember-Klasse. Du kannst Ember-Klassen mit einer Methode in der plugin-api ändern, die … modifyClass heißt ![]()
Wir wissen bereits, welche Klasse wir ändern möchten. Es ist discovery/topics. Wir müssen wissen, um welche Art von Klasse es sich handelt. Prüfen wir also das Verzeichnis.
discourse/app/controllers/discovery/topics.js
Es ist ein Controller.
Wir wissen auch, dass wir die showInserted-Aktion in dieser Klasse ändern möchten. Also beginnen wir damit.
api.modifyClass("controller:discovery/topics", {
pluginId: 'sticky-new-topics-banner',
actions: {
showInserted() {
// lass uns etwas arbeiten
}
}
});
Anschließend kannst du beliebigen Code hinzufügen, um das Fenster zu scrollen, wenn der Benutzer auf das Banner „neue Themen" klickt. Ich habe mich für etwas wie das hier entschieden.
const listControls = document.querySelector(".list-controls");
listControls.scrollIntoView();
Weitere Informationen zu scrollIntoView() findest du hier.
Dann fügst du das wie folgt zur plugin-api-Methode hinzu.
api.modifyClass("controller:discovery/topics", {
pluginId: 'sticky-new-topics-banner',
actions: {
showInserted() {
+ const listControls = document.querySelector(".list-controls");
+ listControls.scrollIntoView();
}
}
});
Sind wir also fertig? Nein. Das bricht Discourse, weil du die Aktion vollständig überschreibst. Beim Klicken auf den Link wird nun zum list-controls-Element gescrollt, aber die neuen Themen werden nicht geladen. Warum? Weil der Code im Kern nicht mehr ausgeführt wird. Ich meine, dieser Teil hier
Wie behebt man das also? Mit dieser einfachen Zeile
this._super(...arguments);
Du musst keinen Code aus dem Kern kopieren, wenn du ihn nur erweitern möchtest. Erledige deine Arbeit und füge dann diese Zeile hinzu. Alles, was sie bewirkt, ist, dass der Code aus dem Kern angewendet wird.
api.modifyClass("controller:discovery/topics", {
pluginId: 'sticky-new-topics-banner',
actions: {
showInserted() {
const listControls = document.querySelector(".list-controls");
listControls.scrollIntoView();
+
+ this._super(...arguments);
}
}
});
Wenn du dies testest, wirst du sehen, dass fast alles gut funktioniert, außer … der Header überlappt mit list-controls. Warum? Weil der Header auf „sticky" gesetzt ist.
Du kannst dies auf verschiedene Arten in JS beheben – die Höhe berechnen, den Offset ermitteln, einen Helfer aus Discourse importieren usw. Ich werde darauf nicht näher eingehen.
Der einfachste Weg ist CSS mit scroll-margin-top, über das du hier mehr lesen kannst.
Also fügen wir Folgendes hinzu
.list-controls {
scroll-margin-top: calc(var(--header-offset) * 2);
}
Auf Deutsch: Wenn auf den Link geklickt wird, zum oberen Rand von list-controls scrollen – 2 * die Headerhöhe, damit keine Überlappung entsteht und etwas Platz darunter bleibt.
Bringen wir also alles zusammen.
Common Header Tab
<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>
Common CSS
#list-area {
// Mobile hat ein anderes Layout
.alert-info,
.show-more.has-topics {
position: sticky;
// Safari ist manchmal ohne das Präfix pingelig
position: -webkit-sticky;
top: var(--header-offset);
// Banner sollte über dem Inhalt liegen
z-index: z("header");
}
}
.list-controls {
scroll-margin-top: calc(var(--header-offset) * 2);
}