Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -7,5 +7,6 @@ MCR.Access.Strategy.SubmittedCategory=MCR.Access.Strategy.SubmittedCategories
MIR.Viewer.DisableDerivateType=MCR.Derivate.DisplayFilters.mir.Filter.Filters.20.Mappings.show-file-viewer.[thumbnail,...]
MIR.OwnerStrategy.FallbackClass=MIR.OwnerStrategy.Fallback.Class
MIR.Metadata.Admindata.ShowRealUserName=MIR.AdmindataBox.ShowRealUserName
MIR.Metadata.Navigation.SeriesPanel.RSS.Enabled=MIR.GuidancePanel.RSS.Enabled
MCR.Alias.prefix=MIR.Alias.Prefix
MCR.Alias.Filepattern=MIR.Alias.LayoutFilePattern
Original file line number Diff line number Diff line change
Expand Up @@ -400,6 +400,7 @@ mir.form.editor.dynamic.header.in =
mir.form.editor.dynamic.partof = Erschienen in
mir.geographic = Geografischer Ort:
mir.geographic.gnd.type = GND:
mir.guidancePanel.search = Suche in {0}
mir.help.abstract = Eine kurze Beschreibung des Datensatzes und des Kontextes (z.B. Zweck, Methoden der Datenerzeugung, r\u00E4umliche und zeitliche Eigenschaften, Datenqualit\u00E4t, Herkunft).
mir.help.abstract.aslink = Ist ein Abstract bereits im Web verf\u00FCgbar, kann dieses auch direkt verlinkt werden.
mir.help.abstract.language = Geben Sie die Sprache an, in der das hier ver\u00F6ffentlichte Abstract verfasst ist. Bei Zusammenfassungen in verschiedenen Sprachen k\u00F6nnen Sie diese mit dem \u201E+\u201C-Button wiederholen.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,7 @@ mir.form.editor.dynamic.header.in =
mir.form.editor.dynamic.partof = Part of
mir.geographic = Geographic place:
mir.geographic.gnd.type = GND:
mir.guidancePanel.search = Search in {0}
mir.help.abstract = A human readable description of the dataset and its context (e.g. purpose and methodology of data creation, spatio-temporal characteristics, data quality, provenance).
mir.help.abstract.aslink = Weblink to abstract.
mir.help.abstract.ortext = A short summary of the document content.
Expand Down
25 changes: 24 additions & 1 deletion mir-module/src/main/resources/config/mir/mycore.properties
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,14 @@ MCR.ContentTransformer.mycoreobject-podcast.Stylesheet=xslt/mir/export/mycoreobj
# Apple requires an image of 3000x3000
MCR.IIIFImage.thumbnail.MaxImageBytes=27000000

##############################################################################
# RSS feed #
##############################################################################
MCR.ContentTransformer.mycoreobject-rss.Stylesheet=xslt/mir/export/mycoreobject2rss.xsl
MCR.LayoutTransformerFactory.Default.Ignore=%MCR.LayoutTransformerFactory.Default.Ignore%,mycoreobject-rss
# Optional name of the generator in the RSS feed, e.g. MIR: MyCoRe/MODS Institutional Repository
#MIR.RSS.Generator=

##############################################################################
# ReCaptcha for self registration #
##############################################################################
Expand Down Expand Up @@ -826,7 +834,7 @@ MCR.ContentTransformer.mycoreobject.Steps=mycoreobject-modsmeta,newMetadataStyle

MIR.Layout.Top=mir-breadcrumb,search_browsing,mir-message
MIR.Layout.Start=mir-abstract-badges,mir-workflow,mir-abstract-title,mir-abstract-plus,toc,mir-file-upload,mir-viewer,mir-player,mir-collapse-files,mir-metadata
MIR.Layout.End=mir-edit,mir-citation,mir-thumbnail,mir-epusta,mir-access-rights,mir-export,mir-admindata,mir-historydata,
MIR.Layout.End=mir-edit,mir-guidance-panel,mir-citation,mir-thumbnail,mir-epusta,mir-access-rights,mir-export,mir-admindata,mir-historydata,
MIR.Layout.Bottom=

#MIR.Layout.Start.Col=col-12 col-lg-8
Expand Down Expand Up @@ -884,6 +892,21 @@ MCR.Startup.Class = %MCR.Startup.Class%,org.mycore.mir.migration.MIRMigrateStati
##############################################################################
#MIR.Maintenance.File=%MCR.basedir%/maintenance.xml

##############################################################################
# Guidance panel #
##############################################################################
# Enables the guidance panel on the metadata page, in the result list of a series search (q or fq=mods.relatedItem.root:{id})
# and in MyCoReWebPages
MIR.GuidancePanel.Enabled=false
# Shows a link to the RSS feed of the series (see RSS feed) in the panel
MIR.GuidancePanel.RSS.Enabled=true
MCR.URIResolver.xslImports.modsmeta=%MCR.URIResolver.xslImports.modsmeta%,mir/object-page/boxes/guidance-panel.xsl
MCR.URIResolver.xslIncludes.MyCoReWebPage=%MCR.URIResolver.xslIncludes.MyCoReWebPage%,resource:xslt/mir/guidance-panel/webpage.xsl
# navigation derivates (navigation.xml, banner, web pages) are not shown in the object view and not exported
MCR.Derivate.DisplayFilters.mir.Filter.Filters.20.Mappings.show-file-viewer.navigation=false
MCR.Derivate.DisplayFilters.mir.Filter.Filters.20.Mappings.show-file-area.navigation=false
MCR.Derivate.DisplayFilters.mir.Filter.Filters.20.Mappings.export.navigation=false

##############################################################################
# Alias #
##############################################################################
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,5 +376,14 @@
"source": "mods.nameIdentifier",
"dest": "mods.nameIdentifier.id"
}
},
{
"add-field": {
"name": "mods.relatedItem.root",
"type": "string",
"indexed": true,
"stored": true,
"multiValued": true
}
}
]
110 changes: 110 additions & 0 deletions mir-module/src/main/resources/xslt/mir/export/mycoreobject2rss.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
xmlns:mcracl="http://www.mycore.de/xslt/acl"
xmlns:mcrproperty="http://www.mycore.de/xslt/property"
xmlns:mods="http://www.loc.gov/mods/v3"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="#all">

<xsl:include href="resource:xslt/default-parameters.xsl" />
<xsl:include href="xslInclude:functions" />

<xsl:output method="xml" encoding="UTF-8" media-type="application/rss+xml" indent="yes" />

<xsl:template match="/">
<rss version="2.0">
<xsl:apply-templates select="mycoreobject" mode="channel" />
</rss>
</xsl:template>

<xsl:template match="mycoreobject" mode="channel">
<xsl:variable name="mods" select="metadata/def.modsContainer/modsContainer/mods:mods" />
<xsl:variable name="generator" select="mcrproperty:get('MIR.RSS.Generator')" />
<channel>
<xsl:apply-templates select="$mods/mods:titleInfo[1]" />
<xsl:call-template name="render-rss-link" />
<xsl:choose>
<xsl:when test="$mods/mods:abstract[normalize-space()]">
<xsl:apply-templates select="$mods/mods:abstract[normalize-space()][1]" />
</xsl:when>
<xsl:otherwise>
<!-- description is required for a channel -->
<description>
<xsl:apply-templates select="$mods/mods:titleInfo[1]" mode="text" />
</description>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="$mods/mods:language[mods:languageTerm[@type = 'code']][1]" />
<xsl:if test="$generator">
<generator>
<xsl:value-of select="$generator" />
</generator>
</xsl:if>
<docs>https://www.rssboard.org/rss-specification</docs>
<xsl:variable name="query" select="concat('solr:q=', encode-for-uri(concat('mods.relatedItem.root:', @ID)),
'&amp;fl=id&amp;rows=20&amp;sort=', encode-for-uri('mods.dateIssued desc,mods.dateIssued.host desc'))" />
<!-- the Solr query does not check permissions, so only readable objects are listed -->
<xsl:for-each select="document($query)/response/result/doc/str[@name = 'id'][mcracl:check-permission(., 'read')]">
<xsl:apply-templates select="document(concat('mcrobject:', .))/mycoreobject" mode="item" />
</xsl:for-each>
</channel>
</xsl:template>

<xsl:template match="mycoreobject" mode="item">
<xsl:variable name="mods" select="metadata/def.modsContainer/modsContainer/mods:mods" />
<item>
<xsl:apply-templates select="$mods/mods:titleInfo[1]" />
<xsl:call-template name="render-rss-link" />
<xsl:apply-templates select="$mods/mods:abstract[normalize-space()][1]" />
<xsl:apply-templates select="service/servdates/servdate[@type = 'modifydate'][. castable as xs:dateTime]" />
<guid>
<xsl:value-of select="concat($WebApplicationBaseURL, 'receive/', @ID)" />
</guid>
</item>
</xsl:template>

<xsl:template name="render-rss-link">
<link>
<xsl:value-of select="concat($WebApplicationBaseURL, 'receive/', @ID)" />
</link>
</xsl:template>

<xsl:template match="mods:titleInfo">
<title>
<xsl:apply-templates select="." mode="text" />
</title>
</xsl:template>

<xsl:template match="mods:titleInfo" mode="text">
<xsl:value-of select="mods:nonSort, mods:title" separator=" " />
<xsl:if test="mods:subTitle">
<!-- separate the subtitle by a colon, unless the title ends with a punctuation mark -->
<xsl:if test="not(matches(mods:title, '[?!.:,;-]$'))">
<xsl:text>:</xsl:text>
</xsl:if>
<xsl:value-of select="concat(' ', mods:subTitle)" />
</xsl:if>
</xsl:template>

<xsl:template match="mods:abstract">
<description>
<xsl:value-of select="." />
</description>
</xsl:template>

<xsl:template match="mods:language">
<language>
<xsl:value-of select="mods:languageTerm[@type = 'code'][1]" />
</language>
</xsl:template>

<!-- RFC 822 date as required by RSS, e.g. Mon, 05 Oct 2026 12:00:00 +0200 -->
<xsl:template match="servdate">
<pubDate>
<xsl:value-of select="format-dateTime(xs:dateTime(.),
'[FNn,3-3], [D01] [MNn,3-3] [Y0001] [H01]:[m01]:[s01] [Z0000]', 'en', (), ())" />
</pubDate>
</xsl:template>

</xsl:stylesheet>
9 changes: 9 additions & 0 deletions mir-module/src/main/resources/xslt/mir/functions/mirmods.xsl
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
xmlns:mcrmods="http://www.mycore.de/xslt/mods"
xmlns:mirmods="http://www.mycore.de/xslt/mirmods"
xmlns:mods="http://www.loc.gov/mods/v3"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="#all">
Expand All @@ -20,4 +21,12 @@
</xsl:if>
</xsl:function>

<xsl:function name="mirmods:root-ids" as="xs:string*">
<xsl:param name="parent" as="element()" />
<xsl:for-each select="$parent/mods:relatedItem[@type = ('host', 'series')][@xlink:href]">
<xsl:variable name="ancestor-ids" select="mirmods:root-ids(.)" />
<xsl:sequence select="if (exists($ancestor-ids)) then $ancestor-ids else string(@xlink:href)" />
</xsl:for-each>
</xsl:function>

</xsl:stylesheet>
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
xmlns:mcracl="http://www.mycore.de/xslt/acl"
xmlns:mcrproperty="http://www.mycore.de/xslt/property"
xmlns:mirguidancepanel="http://www.mycore.de/xslt/mirguidancepanel"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="#all">

<xsl:function name="mirguidancepanel:is-enabled" as="xs:boolean">
<xsl:sequence select="lower-case(mcrproperty:get('MIR.GuidancePanel.Enabled')) = 'true'" />
</xsl:function>

<xsl:function name="mirguidancepanel:is-rss-enabled" as="xs:boolean">
<xsl:sequence select="lower-case(mcrproperty:get('MIR.GuidancePanel.RSS.Enabled')) = 'true'" />
</xsl:function>

<!--
true if the id is a MyCoRe ID readable by the current user; the id may come from request parameters,
the format is checked first because checkPermission fails for ids containing a colon
-->
<xsl:function name="mirguidancepanel:is-readable" as="xs:boolean">
<xsl:param name="id" as="xs:string" />
<xsl:sequence select="matches($id, '^[a-zA-Z][a-zA-Z0-9]*_[a-zA-Z0-9]+_[0-9]+$')
and mcracl:check-permission($id, 'read')" />
</xsl:function>

<!-- label in the current language, falls back to the default language and then to the first label -->
<xsl:function name="mirguidancepanel:label" as="xs:string">
<xsl:param name="labels" as="element(label)*" />
<xsl:param name="current-lang" as="xs:string" />
<xsl:param name="default-lang" as="xs:string" />
<xsl:sequence select="string(($labels[lang($current-lang)], $labels[lang($default-lang)], $labels)[1])" />
</xsl:function>

</xsl:stylesheet>
128 changes: 128 additions & 0 deletions mir-module/src/main/resources/xslt/mir/guidance-panel/render.xsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="3.0"
xmlns:mcrderivate="http://www.mycore.de/xslt/derivate"
xmlns:mcri18n="http://www.mycore.de/xslt/i18n"
xmlns:mcrobject="http://www.mycore.de/xslt/object"
xmlns:mirguidancepanel="http://www.mycore.de/xslt/mirguidancepanel"
xmlns:xlink="http://www.w3.org/1999/xlink"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
exclude-result-prefixes="#all">

<xsl:include href="resource:xslt/mir/guidance-panel/functions/mirguidancepanel.xsl" />

<xsl:param name="CurrentLang" />
<xsl:param name="DefaultLang" />
<xsl:param name="ServletsBaseURL" />
<xsl:param name="WebApplicationBaseURL" />

<xsl:template name="render-guidance-panels">
<xsl:param name="object-id" as="xs:string" />
<xsl:if test="mirguidancepanel:is-readable($object-id)">
<xsl:for-each select="mcrobject:get($object-id)/mycoreobject/structure/derobjects
/derobject[classification[@classid = 'derivate_types'][@categid = 'navigation']]">
<xsl:call-template name="render-guidance-panel">
<xsl:with-param name="object-id" select="$object-id" />
<xsl:with-param name="derivate-id" select="string(@xlink:href)" />
</xsl:call-template>
</xsl:for-each>
</xsl:if>
</xsl:template>

<xsl:template name="render-guidance-panel">
<xsl:param name="object-id" as="xs:string" />
<xsl:param name="derivate-id" as="xs:string" />
<xsl:variable name="navigation" select="if (mirguidancepanel:is-readable($object-id)
and mirguidancepanel:is-readable($derivate-id)) then mcrderivate:get-file($derivate-id, 'navigation.xml')/item else ()" />
<xsl:if test="$navigation">
<xsl:variable name="title" select="mirguidancepanel:label($navigation/label, $CurrentLang, $DefaultLang)" />
<div class="mir-guidance-panel">
<div class="card">
<xsl:if test="normalize-space($navigation/@banner)">
<xsl:call-template name="render-guidance-panel-banner">
<xsl:with-param name="object-id" select="$object-id" />
<xsl:with-param name="banner" select="string($navigation/@banner)" />
<xsl:with-param name="title" select="$title" />
</xsl:call-template>
</xsl:if>
<div class="card-header">
<h3 class="card-title">
<xsl:value-of select="$title" />
</h3>
</div>
<div class="card-body">
<ul>
<xsl:for-each select="$navigation/item">
<xsl:call-template name="render-guidance-panel-item">
<xsl:with-param name="item" select="." />
</xsl:call-template>
</xsl:for-each>
<xsl:if test="mirguidancepanel:is-rss-enabled()">
<xsl:call-template name="render-guidance-panel-rss-item">
<xsl:with-param name="object-id" select="$object-id" />
</xsl:call-template>
</xsl:if>
</ul>
</div>
<div class="card-footer">
<xsl:call-template name="render-guidance-panel-search-form">
<xsl:with-param name="object-id" select="$object-id" />
<xsl:with-param name="derivate-id" select="$derivate-id" />
<xsl:with-param name="title" select="$title" />
</xsl:call-template>
</div>
</div>
</div>
</xsl:if>
</xsl:template>

<xsl:template name="render-guidance-panel-banner">
<xsl:param name="object-id" as="xs:string" />
<xsl:param name="banner" as="xs:string" />
<xsl:param name="title" as="xs:string" />
<a class="mir-guidance-panel-banner" href="{$WebApplicationBaseURL}receive/{$object-id}">
<img src="{$WebApplicationBaseURL}{$banner}" class="card-img-top" alt="{$title}" />
</a>
</xsl:template>

<xsl:template name="render-guidance-panel-search-form">
<xsl:param name="object-id" as="xs:string" />
<xsl:param name="derivate-id" as="xs:string" />
<xsl:param name="title" as="xs:string" />
<!-- unique, a page may contain several panels -->
<xsl:variable name="input-id" select="concat('mir-guidance-panel-search-', $derivate-id)" />
<xsl:variable name="search-label" select="mcri18n:translate-with-params('mir.guidancePanel.search', $title)" />
<form role="search" action="{$ServletsBaseURL}solr/find">
<input type="hidden" name="fq" value="mods.relatedItem.root:{$object-id}" />
<label class="visually-hidden" for="{$input-id}">
<xsl:value-of select="$search-label" />
</label>
<div class="input-group">
<input id="{$input-id}" type="text" name="condQuery" class="form-control" placeholder="{$search-label}" />
<button class="btn btn-primary" type="submit" aria-label="{$search-label}">
<i class="fas fa-search" />
</button>
</div>
</form>
</xsl:template>

<xsl:template name="render-guidance-panel-rss-item">
<xsl:param name="object-id" as="xs:string" />
<li>
<a href="{$WebApplicationBaseURL}receive/{$object-id}?XSL.Style=rss">
<i class="fas fa-rss" />
<xsl:text> RSS 2.0 Feed</xsl:text>
</a>
</li>
</xsl:template>

<xsl:template name="render-guidance-panel-item">
<xsl:param name="item" as="element(item)" />
<li>
<a href="{if (starts-with($item/@ref, 'http')) then $item/@ref else concat($WebApplicationBaseURL, $item/@ref)}">
<xsl:value-of select="mirguidancepanel:label($item/label, $CurrentLang, $DefaultLang)" />
</a>
</li>
</xsl:template>

</xsl:stylesheet>
Loading