1
0
Fork 0
mirror of https://github.com/miniflux/v2.git synced 2025-10-05 19:31:01 +00:00
miniflux-v2/internal/template/templates/views/entry.html
jvoisin 4f252b33c9 refactor(template): rename noescape to safeHTML
This makes the code more consistent, since all the other escaping escape
hatches have a `safe` prefix.
2025-08-22 12:51:21 -07:00

319 lines
17 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

{{ define "title"}}{{ .entry.Title }}{{ end }}
{{ define "entry_pagination" }}
<div class="pagination">
<div class="pagination-prev {{ if not .prevEntry }}disabled{{end}}">
{{ if .prevEntry }}
<a href="{{ .prevEntryRoute }}{{ if .searchQuery }}?q={{ .searchQuery }}{{ end }}" title="{{ .prevEntry.Title }}" data-page="previous" rel="prev">{{ t "pagination.previous" }}</a>
{{ else }}
{{ t "pagination.previous" }}
{{ end }}
</div>
<div class="pagination-next {{ if not .nextEntry }}disabled{{end}}">
{{ if .nextEntry }}
<a href="{{ .nextEntryRoute }}{{ if .searchQuery }}?q={{ .searchQuery }}{{ end }}" title="{{ .nextEntry.Title }}" data-page="next" rel="next">{{ t "pagination.next" }}</a>
{{ else }}
{{ t "pagination.next" }}
{{ end }}
</div>
</div>
{{ end }}
{{ define "enclosure_media_controls" }}
<div class="media-controls">
<div class="media-seek-control">
<div class="media-control-label">{{ t "enclosure_media_controls.seek" }} </div>
<button class="page-button" data-enclosure-id="{{.ID}}" data-enclosure-action="seek" data-action-value="-30" title="{{ t "enclosure_media_controls.seek.title" "-30" }}" ><span class="icon-label" >-30s</span></button>
<button class="page-button" data-enclosure-id="{{.ID}}" data-enclosure-action="seek" data-action-value="-10" title="{{ t "enclosure_media_controls.seek.title" "-10" }}" ><span class="icon-label" >-10s</span></button>
<button class="page-button" data-enclosure-id="{{.ID}}" data-enclosure-action="seek" data-action-value="+10" title="{{ t "enclosure_media_controls.seek.title" "+10" }}" ><span class="icon-label" >+10s</span></button>
<button class="page-button" data-enclosure-id="{{.ID}}" data-enclosure-action="seek" data-action-value="+30" title="{{ t "enclosure_media_controls.seek.title" "+30" }}" ><span class="icon-label" >+30s</span></button>
</div>
<div class="media-speed-control">
<div class="media-control-label">{{ t "enclosure_media_controls.speed" }} (<span class="speed-indicator" data-enclosure-id="{{.ID}}">1.00x</span>)</div> <!-- Need JS to display the current speed unfortunately -->
<button class="page-button" data-enclosure-id="{{.ID}}" data-enclosure-action="speed" data-action-value="-0.25" title="{{ t "enclosure_media_controls.speed.slower.title" "0.25" }}"><span class="icon-label" >{{ t "enclosure_media_controls.speed.slower" }}</span></button>
<button class="page-button" data-enclosure-id="{{.ID}}" data-enclosure-action="speed-reset" data-action-value="1" title="{{ t "enclosure_media_controls.speed.reset.title"}}"><span class="icon-label" >{{ t "enclosure_media_controls.speed.reset" }}</span></button>
<button class="page-button" data-enclosure-id="{{.ID}}" data-enclosure-action="speed" data-action-value="+0.25" title="{{ t "enclosure_media_controls.speed.faster.title" "0.25" }}"><span class="icon-label" >{{ t "enclosure_media_controls.speed.faster" }}</span></button>
</div>
</div>
{{ end }}
{{ define "page_header"}}
<section class="entry" data-id="{{ .entry.ID }}" aria-labelledby="page-header-title">
<header class="entry-header">
<h1 id="page-header-title" dir="auto">
<a href="{{ .entry.URL | safeURL }}" {{ if $.user.OpenExternalLinksInNewTab }}target="_blank"{{ else }}rel="noopener"{{ end }}>{{ .entry.Title }}</a>
</h1>
{{ if .user }}
<div class="entry-actions">
<ul>
<li>
<button
class="page-button"
title="{{ t "entry.status.title" }}"
data-toggle-status="true"
data-label-loading="{{ t "entry.state.saving" }}"
data-label-unread="{{ t "entry.status.mark_as_unread" }}"
data-label-read="{{ t "entry.status.mark_as_read" }}"
data-toast-unread="{{ t "entry.status.toast.unread" }}"
data-toast-read="{{ t "entry.status.toast.read" }}"
data-value="{{ if eq .entry.Status "read" }}read{{ else }}unread{{ end }}"
>{{ if eq .entry.Status "unread" }}{{ icon "read" }}{{ else }}{{ icon "unread" }}{{ end }}<span class="icon-label">{{ if eq .entry.Status "unread" }}{{ t "entry.status.mark_as_read" }}{{ else }}{{ t "entry.status.mark_as_unread" }}{{ end }}</span></button>
</li>
<li>
<button
class="page-button"
data-toggle-starred="true"
data-star-url="{{ route "toggleStarred" "entryID" .entry.ID }}"
data-label-loading="{{ t "entry.state.saving" }}"
data-label-star="{{ t "entry.starred.toggle.on" }}"
data-label-unstar="{{ t "entry.starred.toggle.off" }}"
data-toast-star="{{ t "entry.starred.toast.on" }}"
data-toast-unstar="{{ t "entry.starred.toast.off" }}"
data-value="{{ if .entry.Starred }}star{{ else }}unstar{{ end }}"
>{{ if .entry.Starred }}{{ icon "unstar" }}{{ else }}{{ icon "star" }}{{ end }}<span class="icon-label">{{ if .entry.Starred }}{{ t "entry.starred.toggle.off" }}{{ else }}{{ t "entry.starred.toggle.on" }}{{ end }}</span></button>
</li>
{{ if .hasSaveEntry }}
<li>
<button
class="page-button"
title="{{ t "entry.save.title" }}"
data-save-entry="true"
data-save-url="{{ route "saveEntry" "entryID" .entry.ID }}"
data-label-loading="{{ t "entry.state.saving" }}"
data-label-done="{{ t "entry.save.completed" }}"
data-toast-done="{{ t "entry.save.toast.completed" }}"
>{{ icon "save" }}<span class="icon-label">{{ t "entry.save.label" }}</span></button>
</li>
{{ end }}
{{ if .entry.ShareCode }}
<li>
<a href="{{ route "sharedEntry" "shareCode" .entry.ShareCode }}"
title="{{ t "entry.shared_entry.title" }}"
data-share-status="shared"
{{ if $.user.OpenExternalLinksInNewTab }}target="_blank"{{ end }}>{{ icon "share" }}<span class="icon-label">{{ t "entry.shared_entry.label" }}</span></a>
</li>
<li>
<button
class="page-button"
data-confirm="true"
data-url="{{ route "unshareEntry" "entryID" .entry.ID }}"
data-label-question="{{ t "confirm.question" }}"
data-label-yes="{{ t "confirm.yes" }}"
data-label-no="{{ t "confirm.no" }}"
data-label-loading="{{ t "confirm.loading" }}">{{ icon "delete" }}<span class="icon-label">{{ t "entry.unshare.label" }}</span></button>
</li>
{{ else }}
<li>
<form method="post" action="{{route "shareEntry" "entryID" .entry.ID }}">
<input type="hidden" name="csrf" value="{{ .csrf }}">
<button type="submit" class="page-button">
{{ icon "share" }}<span class="icon-label">{{ t "entry.share.label" }}</span>
</button>
</form>
</li>
{{ end }}
<li>
<button
class="page-button"
title="{{ t "entry.scraper.title" }}"
data-fetch-content-entry="true"
data-fetch-content-url="{{ route "fetchContent" "entryID" .entry.ID }}"
data-label-loading="{{ t "entry.state.loading" }}"
>{{ icon "scraper" }}<span class="icon-label">{{ t "entry.scraper.label" }}</span></button>
</li>
{{ if .entry.CommentsURL }}
<li>
<a href="{{ .entry.CommentsURL | safeURL }}"
class="page-link"
title="{{ t "entry.comments.title" }}"
{{ if $.user.OpenExternalLinksInNewTab }}target="_blank"{{ else }}rel="noopener"{{ end }}
data-comments-link="true"
>{{ icon "comment" }}<span class="icon-label">{{ t "entry.comments.label" }}</span></a>
</li>
{{ end }}
</ul>
</div>
{{ end }}
<div class="entry-meta" dir="auto">
<span class="entry-website">
{{ if ne .entry.Feed.Icon.IconID 0 }}
<img src="{{ route "feedIcon" "externalIconID" .entry.Feed.Icon.ExternalIconID }}" width="16" height="16" loading="lazy" alt="{{ .entry.Feed.Title }}">
{{ end }}
{{ if .user }}
<a href="{{ route "feedEntries" "feedID" .entry.Feed.ID }}">{{ .entry.Feed.Title }}</a>
{{ else }}
<a href="{{ .entry.Feed.SiteURL | safeURL }}">{{ .entry.Feed.Title }}</a>
{{ end }}
</span>
{{ if .entry.Author }}
<span class="entry-author">
{{ if isEmail .entry.Author }}
- <a href="mailto:{{ .entry.Author }}">{{ .entry.Author }}</a>
{{ else }}
<em>{{ .entry.Author }}</em>
{{ end }}
</span>
{{ end }}
{{ if .user }}
<span class="category">
<a href="{{ route "categoryEntries" "categoryID" .entry.Feed.Category.ID }}">{{ .entry.Feed.Category.Title }}</a>
</span>
{{ end }}
</div>
{{ if .entry.Tags }}
<div class="entry-tags">
{{ t "entry.tags.label" }}
{{ $allTags := .entry.Tags }}
{{ $numTags := len $allTags }}
{{ $tagsLimit := 5 }}
{{ $numerOfAdditionalTags := subtract $numTags $tagsLimit }}
<ul class="entry-tags-list">
{{ range $i, $tagName := $allTags }}
{{ if lt $i $tagsLimit }}
{{ if $.user }}
<li><a href="{{ route "tagEntriesAll" "tagName" (urlEncode $tagName) }}"><strong>{{ $tagName }}</strong></a></li>
{{ else }}
<li><strong>{{ $tagName }}</strong></li>
{{ end }}
{{ end }}
{{ end }}
</ul>
{{ if gt $numTags $tagsLimit }}
<details class="entry-additional-tags">
<summary>
{{ plural "entry.tags.more_tags_label" $numerOfAdditionalTags $numerOfAdditionalTags }}
</summary>
<ul class="entry-tags-list">
{{ range $idx, $tagName := $allTags }}
{{ if ge $idx $tagsLimit }}
{{ if $.user }}
<li><a href="{{ route "tagEntriesAll" "tagName" (urlEncode $tagName) }}"><strong>{{ $tagName }}</strong></a></li>
{{ else }}
<li><strong>{{ $tagName }}</strong></li>
{{ end }}
{{ end }}
{{ end }}
</ul>
</details>
{{ end }}
</div>
{{ end }}
<div class="entry-external-link">
<a
href="{{ .entry.URL | safeURL }}"
{{ if $.user.OpenExternalLinksInNewTab }}target="_blank"{{ else }}rel="noopener"{{ end }}
data-original-link="{{ $.user.MarkReadOnView }}">{{ .entry.URL }}</span></a>
</div>
<div class="entry-date">
{{ if .user }}
<time datetime="{{ isodate .entry.Date }}" title="{{ isodate .entry.Date }}">{{ elapsed $.user.Timezone .entry.Date }}</time>
{{ else }}
<time datetime="{{ isodate .entry.Date }}" title="{{ isodate .entry.Date }}">{{ elapsed "UTC" .entry.Date }}</time>
{{ end }}
{{ if and .user.ShowReadingTime (gt .entry.ReadingTime 0) }}
&centerdot;
<span class="entry-reading-time">
{{ plural "entry.estimated_reading_time" .entry.ReadingTime .entry.ReadingTime }}
</span>
{{ end }}
</div>
</header>
</section>
{{ end }}
{{ define "content"}}
{{ if gt (len .entry.Content) 120 }}
{{ if .user }}
<div class="pagination-entry-top">
{{ template "entry_pagination" . }}
</div>
{{ end }}
{{ end }}
<article class="entry-content {{ if ne $.user.GestureNav "none" }}gesture-nav-{{ $.user.GestureNav }}{{ end }}" dir="auto">
{{ if not .entry.Feed.NoMediaPlayer }}
{{ $mediaPlayerEnclosure := .entry.Enclosures.FindMediaPlayerEnclosure }}
{{ if $mediaPlayerEnclosure }}
{{ with $mediaPlayerEnclosure }}
{{ if .IsAudio }}
<div class="enclosure-audio" >
<audio controls preload="metadata"
{{ if $.user }}data-last-position="{{ .MediaProgression }}"{{ end }}
{{ if $.user.MediaPlaybackRate }}data-playback-rate="{{ $.user.MediaPlaybackRate }}"{{ end }}
{{ if $.user.MarkReadOnMediaPlayerCompletion }}data-mark-read-on-completion="0.9"{{ end }}
{{ if $.user }}data-save-url="{{ route "saveEnclosureProgression" "enclosureID" .ID }}"{{ end }}
data-enclosure-id="{{ .ID }}"
>
{{ if (and $.user (mustBeProxyfied "audio")) }}
<source src="{{ proxyURL .URL }}" type="{{ .Html5MimeType }}">
{{ else }}
<source src="{{ .URL | safeURL }}" type="{{ .Html5MimeType }}">
{{ end }}
</audio>
{{ template "enclosure_media_controls" . }}
</div>
{{ else if .IsVideo }}
<div class="enclosure-video">
<video controls preload="metadata"
{{ if $.user }}data-last-position="{{ .MediaProgression }}"{{ end }}
{{ if $.user.MediaPlaybackRate }}data-playback-rate="{{ $.user.MediaPlaybackRate }}"{{ end }}
{{ if $.user.MarkReadOnMediaPlayerCompletion }}data-mark-read-on-completion="0.9"{{ end }}
{{ if $.user }}data-save-url="{{ route "saveEnclosureProgression" "enclosureID" .ID }}"{{ end }}
data-enclosure-id="{{ .ID }}"
>
{{ if (and $.user (mustBeProxyfied "video")) }}
<source src="{{ proxyURL .URL }}" type="{{ .Html5MimeType }}">
{{ else }}
<source src="{{ .URL | safeURL }}" type="{{ .Html5MimeType }}">
{{ end }}
</video>
{{ template "enclosure_media_controls" . }}
</div>
{{ end }}
{{ end }}
{{ end }}
{{ end }}
{{ if .user }}
{{ safeHTML (proxyFilter .entry.Content) }}
{{ else }}
{{ safeHTML .entry.Content }}
{{ end }}
</article>
{{ if .entry.Enclosures }}
<details class="entry-enclosures">
<summary>{{ t "page.entry.attachments" }} ({{ len .entry.Enclosures }})</summary>
{{ range .entry.Enclosures }}
{{ if ne .URL "" }}
<div class="entry-enclosure">
{{ if .IsImage }}
<div class="enclosure-image">
{{ if (and $.user (mustBeProxyfied "image")) }}
<img src="{{ proxyURL .URL }}" title="{{ .URL }} ({{ .MimeType }})" loading="lazy" alt="{{ .URL }} ({{ .MimeType }})">
{{ else }}
<img src="{{ .URL | safeURL }}" title="{{ .URL }} ({{ .MimeType }})" loading="lazy" alt="{{ .URL }} ({{ .MimeType }})">
{{ end }}
</div>
{{ end }}
<div class="entry-enclosure-download">
<a href="{{ .URL | safeURL }}" title="{{ t "action.download" }}{{ if gt .Size 0 }} - {{ formatFileSize .Size }}{{ end }}" {{ if $.user.OpenExternalLinksInNewTab }}target="_blank"{{ else }}rel="noopener"{{ end }}>{{ .URL | safeURL }}</a>
<small>{{ if gt .Size 0 }} - <strong>{{ formatFileSize .Size }}</strong>{{ end }}</small>
</div>
</div>
{{ end }}
{{ end }}
</details>
{{ end }}
{{ if .user }}
<div class="pagination-entry-bottom">
{{ template "entry_pagination" . }}
</div>
{{ end }}
{{ end }}