Ich wollte heute einen Blogbeitrag erstellen, in dem mehrere 360°-Fotos (hier nur noch “Sphere” genannt) eingebunden werden und stellte fest, dass immer nur die erste Sphere angezeigt wurde. Vermutlich hatte ich damals beim “Implementieren” nicht an so etwas gedacht.

Das Problem ist, dass der Shortcode den folgenden Code beinhaltet:

<div id="viewer" style="width: 100%; height: 60vh;"></div>
<script>
    const viewer = new PhotoSphereViewer.Viewer({
        container: document.querySelector('#viewer'),
[…]

Eindeutige ID mit .Ordinal

Ich habe jetzt nicht wirklich Ahnung von diesem ganzen Zeugs, aber eine ID innerhalb eines HTML-Dokuments muss eindeutig sein und sobald man mehrere Spheres einbindet, gibt es mindestens zwei id="viewer".

D. h. ich musste den Code ändern und sowohl die ID als auch die Konstante viewer für jedes eingebundene Sphere eindeutig machen. Mit Hilfe der Variable .Ordinal ist das einfach umsetzbar. Die Variable besagt, an wie vielter Stelle der aktuelle Shortcode im Kontext der aktuellen Seite steht.

Dabei stieß ich auf ein Problem, denn irgendwas in Hugo macht magische Dinge und fügt automatisch Anführungszeichen ein, sobald man eine Hugo Variable innerhalb eines <script>-Konstrukts einfügt.

So wird aus:

<script>
 const viewer_{{ .Ordinal }} = new []
</script>

In Ergebnis das hier:

<script>
 const viewer_"2" = new []
</script>

Details dazu gibt es hier zu lesen und die Lösung ist safeJS.

Der funktionierende Code sieht dann so aus und die Anführungszeichen sind dann weg:

<script>
 const viewer_{{ .Ordinal | safeJS }} = new []
</script>

Noch mehr Arbeit für die Karte

Optional kann ich für jede Sphere auch einen Kartenausschnitt von OpenStreetMap einbinden, siehe hier. Dabei gibt es jedoch das selbe Problem mit der eindeutigen ID und auch hier lädt nur die erste Karte. Denn das JavaScript referenziert auch mehrere IDs.

Doch das übersteigt meine Fertigkeiten mit JavaScript und Co und deshalb werde ich die Karten bei mehreren Spheres pro Blogbeitrag erst einmal nicht einbinden, bis ich eine Lösung gefunden habe.

Immerhin gibt es unter jeder Sphere optional die Möglichkeit, einen Link zum Standort zu hinterlegen und das werde ich stattdessen nutzen.

Scripte und CSS nur einmal einbinden

So kann ich jetzt auch mehrere Spheres in einem Blogbeitrag einfügen. Doch es werden noch bei jeder Einbindung die notwendigen, externen Scripte eingebunden. Ordinal kann ich hier nicht dafür verwenden, denn der liefert für jeden verwendeten Shortcode innerhalb eines Blogbeitrags eine eindeutige Nummer, jedoch nicht die Information, ob der Shortcode bereits aufgerufen wurde.

Deshalb bietet sich die Funktion .Scratch an.

Mit diesem Code werden Scripte und CSS nur beim ersten Sphere eingebunden, bei weiteren nicht erneut:

<!-- Sphere js und css nur einmalig einbinden -->
{{ if ne ($.Page.Scratch.Get "sphere_used") "true" }}
{{ $.Page.Scratch.Set "sphere_used" "true" }}
Hier Einbindung der Scripte und CSS.
{{ end }}