Skip to content

Commit 4141f26

Browse files
authored
Editor / Add list mode (geonetwork#7998)
* Editor / Add list mode The list can be used to display a list of contact with only organisation name for example. This can facilitate building simple form hiding the details of ISO elements. In this case, use a contact directory to add new contact makes sense. This mode can be also more efficient when record contains lots of contacts which in some case can create large HTML form which can take time to build, download and render in the browser (eg. when having more than 100 contacts in a record). If only `label` are used the form will be faster to render. For large XML record, form may trigger error like `Form with too many keys [1001 > 1000]` when submitted. The list mode allows to deal with such situation. eg. ```xml <action type="add" forceLabel="true" addDirective="data-gn-directory-entry-selector" or="pointOfContact" in="/gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification"> <directiveAttributes data-template-add-action="false" data-search-action="true" data-popup-action="true" data-template-type="contact" data-variables="gmd:role/gmd:CI_RoleCode/@codeListValue~{role}"/> </action> <list name="Contact point" xpath="/gmd:MD_Metadata/gmd:identificationInfo/*/gmd:pointOfContact[*/gmd:role/*/@codeListValue = 'pointOfContact']" del="." sortBy="gmd:organisationName/gco:CharacterString"> <item href="*[1]/@uuid"> <label xpath="*/gmd:organisationName/gco:CharacterString/text()"/> </item> </list> <list name="Originator" xpath="/gmd:MD_Metadata/gmd:identificationInfo/*/gmd:pointOfContact[*/gmd:role/*/@codeListValue = 'originator']" sortBy="gmd:organisationName/gco:CharacterString"> <item> <field xpath="*/gmd:organisationName"/> </item> </list> ``` Funded by Ifremer * Editor / Add list mode / Display list as standard field in view mode This is needed when the custom editor is also used as a formatter.
1 parent 8814532 commit 4141f26

File tree

3 files changed

+294
-41
lines changed

3 files changed

+294
-41
lines changed

schemas/config-editor.xsd

+166-39
Original file line numberDiff line numberDiff line change
@@ -1089,6 +1089,7 @@ the mandatory section with no name and then the inner elements.
10891089
<xs:element ref="xsl"/>
10901090
<xs:element ref="section"/>
10911091
<xs:element ref="fieldset"/>
1092+
<xs:element ref="list"/>
10921093
</xs:choice>
10931094
<xs:attribute ref="mode"/>
10941095
<xs:attribute name="name" type="xs:string">
@@ -1157,6 +1158,119 @@ Note: Only sections with forEach support del attribute.
11571158
</xs:unique>
11581159
</xs:element>
11591160

1161+
1162+
1163+
<xs:element name="list">
1164+
<xs:annotation>
1165+
<xs:documentation><![CDATA[
1166+
Adding a list
1167+
-------------
1168+
1169+
The list can be used to display a list of contact with only organisation name for example.
1170+
This can facilitate building simple form hiding the details of ISO elements. In this case,
1171+
use a contact directory to add new contact makes sense.
1172+
1173+
This mode can be also more efficient when record contains lots of contacts which in some case
1174+
can create large HTML form which can take time to build, download and render in the browser
1175+
(eg. when having more than 100 contacts in a record). If only `label` are used the form will be faster to render.
1176+
1177+
eg.
1178+
1179+
..code-block:: xml
1180+
1181+
1182+
<action type="add"
1183+
forceLabel="true"
1184+
addDirective="data-gn-directory-entry-selector"
1185+
or="pointOfContact"
1186+
in="/gmd:MD_Metadata/gmd:identificationInfo/gmd:MD_DataIdentification">
1187+
<directiveAttributes
1188+
data-template-add-action="false"
1189+
data-search-action="true"
1190+
data-popup-action="true"
1191+
data-template-type="contact"
1192+
data-variables="gmd:role/gmd:CI_RoleCode/@codeListValue~{role}"/>
1193+
</action>
1194+
1195+
<list name="Contact point"
1196+
xpath="/gmd:MD_Metadata/gmd:identificationInfo/*/gmd:pointOfContact[*/gmd:role/*/@codeListValue = 'pointOfContact']"
1197+
del="."
1198+
sortBy="gmd:organisationName/gco:CharacterString">
1199+
<item href="*[1]/@uuid">
1200+
<label xpath="*/gmd:organisationName/gco:CharacterString/text()"/>
1201+
</item>
1202+
</list>
1203+
1204+
<list name="Originator"
1205+
xpath="/gmd:MD_Metadata/gmd:identificationInfo/*/gmd:pointOfContact[*/gmd:role/*/@codeListValue = 'originator']"
1206+
sortBy="gmd:organisationName/gco:CharacterString">
1207+
<item>
1208+
<field xpath="*/gmd:organisationName"/>
1209+
</item>
1210+
</list>
1211+
]]></xs:documentation>
1212+
</xs:annotation>
1213+
<xs:complexType>
1214+
<xs:choice minOccurs="1">
1215+
<xs:element name="item">
1216+
<xs:annotation>
1217+
<xs:documentation><![CDATA[
1218+
An item in the list.
1219+
]]></xs:documentation>
1220+
</xs:annotation>
1221+
<xs:complexType>
1222+
<xs:sequence>
1223+
<xs:element ref="label"/>
1224+
<xs:element ref="text"/>
1225+
<xs:element ref="field"/>
1226+
</xs:sequence>
1227+
<xs:attribute name="href" type="xs:string">
1228+
<xs:annotation>
1229+
<xs:documentation>Add a hyperlink on the item</xs:documentation>
1230+
</xs:annotation>
1231+
</xs:attribute>
1232+
</xs:complexType>
1233+
</xs:element>
1234+
</xs:choice>
1235+
<xs:attribute name="name" type="xs:string">
1236+
<xs:annotation>
1237+
<xs:documentation>An optional name to override the default one base on field name for the
1238+
section. The name must be defined in ``{schema}/loc/{lang}/strings.xml``.
1239+
</xs:documentation>
1240+
</xs:annotation>
1241+
</xs:attribute>
1242+
<xs:attribute name="xpath" type="xs:string">
1243+
<xs:annotation>
1244+
<xs:documentation>The XPath of the element to create list items.
1245+
</xs:documentation>
1246+
</xs:annotation>
1247+
</xs:attribute>
1248+
<xs:attribute ref="del"/>
1249+
<xs:attribute ref="or"/>
1250+
<xs:attribute ref="in"/>
1251+
<xs:attribute name="sortBy">
1252+
<xs:annotation>
1253+
<xs:documentation>XPath of the element to sort the list by. Must use full name of each nodes eg. gmd:organisationName/gco:CharacterString</xs:documentation>
1254+
</xs:annotation>
1255+
</xs:attribute>
1256+
<xs:attribute ref="displayIfRecord"/>
1257+
<xs:attribute ref="displayIfServiceInfo"/>
1258+
<xs:attribute name="collapsed" type="xs:boolean" fixed="true">
1259+
<xs:annotation>
1260+
<xs:documentation>An optional attribute to collapse the section. If not set the section is expanded.
1261+
</xs:documentation>
1262+
</xs:annotation>
1263+
</xs:attribute>
1264+
<xs:attribute name="collapsible" type="xs:boolean" fixed="false">
1265+
<xs:annotation>
1266+
<xs:documentation>An optional attribute to not allow collapse for the section. If not set the section is expandable.
1267+
</xs:documentation>
1268+
</xs:annotation>
1269+
</xs:attribute>
1270+
</xs:complexType>
1271+
</xs:element>
1272+
1273+
11601274
<xs:attribute name="or" type="xs:string">
11611275
<xs:annotation>
11621276
<xs:documentation>Local name to match if the element does not exist.</xs:documentation>
@@ -1171,6 +1285,46 @@ Note: Only sections with forEach support del attribute.
11711285
</xs:annotation>
11721286
</xs:attribute>
11731287

1288+
<xs:attribute name="del" type="xs:string">
1289+
<xs:annotation>
1290+
<xs:documentation>
1291+
<![CDATA[
1292+
Relative XPath of the element to remove when the `remove` button is clicked.
1293+
1294+
e.g. If a template field match linkage and allows editing of field URL,
1295+
the remove control should remove the parent element gmd:onLine.
1296+
1297+
.. code-block:: xml
1298+
1299+
<field name="url"
1300+
xpath="/gmd:MD_Metadata/gmd:distributionInfo/gmd:MD_Distribution/gmd:transferOptions
1301+
/gmd:MD_DigitalTransferOptions/gmd:onLine/gmd:CI_OnlineResource/gmd:linkage"
1302+
del="ancestor::gmd:onLine">
1303+
<template>
1304+
1305+
`del` attribute can be used in template mode or not. Example to remove
1306+
`spatialResolution` while only editing `denominator` or `distance`. `denominator` or `distance`
1307+
are mandatory, but as the `del` element points to the `spatialResolution`
1308+
ancestor, there is no mandatory flag displayed and the remove control
1309+
removes the `spatialResolution` element.
1310+
1311+
1312+
.. code-block:: xml
1313+
1314+
1315+
<field xpath="/gmd:MD_Metadata/gmd:identificationInfo/
1316+
*/gmd:spatialResolution/*/gmd:distance"
1317+
del="ancestor::gmd:spatialResolution"/>
1318+
<field xpath="/gmd:MD_Metadata/gmd:identificationInfo/
1319+
*/gmd:spatialResolution/
1320+
*/gmd:equivalentScale/*/gmd:denominator"
1321+
del="ancestor::gmd:spatialResolution"/>
1322+
1323+
]]>
1324+
</xs:documentation>
1325+
</xs:annotation>
1326+
</xs:attribute>
1327+
11741328

11751329
<xs:element name="fieldset">
11761330
<xs:annotation>
@@ -1314,45 +1468,7 @@ The local name of the geonet child (i.e. non-existing element) to match.
13141468
<xs:documentation>The element to search in for the geonet child.</xs:documentation>
13151469
</xs:annotation>
13161470
</xs:attribute>
1317-
<xs:attribute name="del" type="xs:string">
1318-
<xs:annotation>
1319-
<xs:documentation>
1320-
<![CDATA[
1321-
Relative XPath of the element to remove when the `remove` button is clicked.
1322-
1323-
e.g. If a template field match linkage and allows editing of field URL,
1324-
the remove control should remove the parent element gmd:onLine.
1325-
1326-
.. code-block:: xml
1327-
1328-
<field name="url"
1329-
xpath="/gmd:MD_Metadata/gmd:distributionInfo/gmd:MD_Distribution/gmd:transferOptions
1330-
/gmd:MD_DigitalTransferOptions/gmd:onLine/gmd:CI_OnlineResource/gmd:linkage"
1331-
del="../..">
1332-
<template>
1333-
1334-
`del` attribute can be used in template mode or not. Example to remove
1335-
`spatialResolution` while only editing `denominator` or `distance`. `denominator` or `distance`
1336-
are mandatory, but as the `del` element points to the `spatialResolution`
1337-
ancestor, there is no mandatory flag displayed and the remove control
1338-
removes the `spatialResolution` element.
1339-
1340-
1341-
.. code-block:: xml
1342-
1343-
1344-
<field xpath="/gmd:MD_Metadata/gmd:identificationInfo/
1345-
*/gmd:spatialResolution/*/gmd:distance"
1346-
del="../.."/>
1347-
<field xpath="/gmd:MD_Metadata/gmd:identificationInfo/
1348-
*/gmd:spatialResolution/
1349-
*/gmd:equivalentScale/*/gmd:denominator"
1350-
del="../../../.."/>
1351-
1352-
]]>
1353-
</xs:documentation>
1354-
</xs:annotation>
1355-
</xs:attribute>
1471+
<xs:attribute ref="del"/>
13561472
<xs:attribute name="templateModeOnly" fixed="true" type="xs:boolean">
13571473
<xs:annotation>
13581474
<xs:documentation><![CDATA[
@@ -1373,6 +1489,17 @@ displayed based on the XML template snippet field configuration. Default is fals
13731489
</xs:element>
13741490

13751491

1492+
<xs:element name="label">
1493+
<xs:complexType>
1494+
<xs:attribute name="xpath" use="required">
1495+
<xs:annotation>
1496+
<xs:documentation>The xpath of the text to display as label. eg. `*/gmd:organisationName/gco:CharacterString/text()`</xs:documentation>
1497+
</xs:annotation>
1498+
</xs:attribute>
1499+
</xs:complexType>
1500+
</xs:element>
1501+
1502+
13761503
<xs:element name="template">
13771504
<xs:annotation>
13781505
<xs:documentation><![CDATA[

web/src/main/webapp/WEB-INF/data/data/formatter/xslt/render-layout.xsl

+2-2
Original file line numberDiff line numberDiff line change
@@ -419,7 +419,7 @@
419419
<xsl:if test="$isDisplayed">
420420
<xsl:variable name="content">
421421
<xsl:apply-templates mode="render-view"
422-
select="section|field|xsl"/>&#160;
422+
select="section|field|xsl|list"/>&#160;
423423
</xsl:variable>
424424

425425
<xsl:if test="count($content/*) > 0">
@@ -459,7 +459,7 @@
459459

460460
<!-- Render metadata elements defined by XPath -->
461461
<xsl:template mode="render-view"
462-
match="field[not(template)]">
462+
match="field[not(template)]|list[@xpath]">
463463
<xsl:param name="base" select="$metadata"/>
464464

465465
<!-- Matching nodes -->

web/src/main/webapp/xslt/ui-metadata/form-configurator.xsl

+126
Original file line numberDiff line numberDiff line change
@@ -606,6 +606,132 @@
606606
</xsl:template>
607607

608608

609+
<xsl:template mode="form-builder"
610+
match="list">
611+
<xsl:param name="base" as="node()"/>
612+
613+
<xsl:variable name="isDisplayed"
614+
as="xs:boolean"
615+
select="gn-fn-metadata:check-elementandsession-visibility(
616+
$schema, $metadata, $serviceInfo, @displayIfRecord, @displayIfServiceInfo)"/>
617+
618+
<xsl:if test="$isDisplayed">
619+
<xsl:variable name="del" select="@del"/>
620+
<xsl:variable name="href" select="item/@href"/>
621+
<xsl:variable name="listConfig" select="."/>
622+
<xsl:variable name="xpathPrefix"
623+
select="if (starts-with(@xpath, '/'))
624+
then '/..'
625+
else '/'"/>
626+
627+
<xsl:variable name="items">
628+
<saxon:call-template name="{concat('evaluate-', $schema)}">
629+
<xsl:with-param name="base" select="$base"/>
630+
<xsl:with-param name="in" select="concat($xpathPrefix, @xpath)"/>
631+
</saxon:call-template>
632+
</xsl:variable>
633+
634+
<xsl:variable name="listItems">
635+
<xsl:if test="count($items/*) > 0">
636+
<ul class="list-group">
637+
638+
<xsl:for-each select="$items/*">
639+
<xsl:sort select=".//*[ends-with(string-join(ancestor-or-self::*/name(), '/'), $listConfig/@sortBy)]"
640+
order="{($listConfig/@sortOrder, 'ascending')[1]}"/>
641+
<xsl:variable name="base" select="."/>
642+
643+
<li class="list-group-item flex-row flex-align-center">
644+
<div class="flex-grow">
645+
<xsl:variable name="itemLink">
646+
<xsl:if test="$href">
647+
<saxon:call-template name="{concat('evaluate-', $schema)}">
648+
<xsl:with-param name="base" select="$base"/>
649+
<xsl:with-param name="in" select="concat('/', $href)"/>
650+
</saxon:call-template>
651+
</xsl:if>
652+
</xsl:variable>
653+
654+
<xsl:variable name="itemText">
655+
<xsl:for-each select="$listConfig/item/(field|label|text)">
656+
<xsl:choose>
657+
<xsl:when test="name() = ('field', 'text')">
658+
<xsl:apply-templates mode="form-builder" select=".">
659+
<xsl:with-param name="base" select="$base"/>
660+
</xsl:apply-templates>
661+
</xsl:when>
662+
<xsl:otherwise>
663+
<saxon:call-template name="{concat('evaluate-', $schema)}">
664+
<xsl:with-param name="base" select="$base"/>
665+
<xsl:with-param name="in" select="concat('/', @xpath)"/>
666+
</saxon:call-template>
667+
</xsl:otherwise>
668+
</xsl:choose>
669+
</xsl:for-each>
670+
</xsl:variable>
671+
672+
<xsl:choose>
673+
<xsl:when test="$itemLink != ''">
674+
<a href="{$itemLink}" target="_blank">
675+
<xsl:copy-of select="$itemText"/>
676+
</a>
677+
</xsl:when>
678+
<xsl:otherwise>
679+
<xsl:copy-of select="$itemText"/>
680+
</xsl:otherwise>
681+
</xsl:choose>
682+
</div>
683+
684+
<xsl:if test="$del != ''">
685+
<div class="">
686+
<xsl:variable name="refToDelete">
687+
<xsl:call-template name="get-ref-element-to-delete">
688+
<xsl:with-param name="node" select="$base"/>
689+
<xsl:with-param name="delXpath" select="$del"/>
690+
</xsl:call-template>
691+
</xsl:variable>
692+
693+
<xsl:call-template name="render-form-field-control-remove">
694+
<xsl:with-param name="editInfo" select="gn:element"/>
695+
</xsl:call-template>
696+
</div>
697+
</xsl:if>
698+
</li>
699+
</xsl:for-each>
700+
</ul>
701+
</xsl:if>
702+
</xsl:variable>
703+
704+
<xsl:variable name="sectionName" select="@name"/>
705+
<xsl:choose>
706+
<xsl:when test="$sectionName">
707+
<fieldset data-gn-field-highlight="" class="gn-{@name}">
708+
<legend>
709+
<xsl:if test="not(@collapsible)">
710+
<xsl:attribute name="data-gn-slide-toggle" select="exists(@collapsed)"/>
711+
</xsl:if>
712+
<xsl:value-of
713+
select="if (contains($sectionName, ':'))
714+
then gn-fn-metadata:getLabel($schema, $sectionName, $labels)/label
715+
else if ($strings/*[name() = $sectionName] != '')
716+
then $strings/*[name() = $sectionName]
717+
else $sectionName"
718+
/>
719+
</legend>
720+
<div class="row">
721+
<div class="col-md-12">
722+
<xsl:copy-of select="$listItems"/>
723+
</div>
724+
</div>
725+
</fieldset>
726+
</xsl:when>
727+
<xsl:otherwise>
728+
<xsl:copy-of select="$listItems"/>
729+
</xsl:otherwise>
730+
</xsl:choose>
731+
</xsl:if>
732+
</xsl:template>
733+
734+
609735
<!-- Get the reference of the element to delete if delete is allowed. -->
610736
<xsl:template name="get-ref-element-to-delete">
611737
<xsl:param name="node" as="node()?"/>

0 commit comments

Comments
 (0)