Commit 1b890262 authored by Jenkins's avatar Jenkins
Browse files

Merge commit 'b840596c' into rc

parents ffe71b10 b840596c
package common
import org.fao.geonet.api.records.formatters.FormatType
import org.fao.geonet.api.records.formatters.groovy.Environment
import org.nibor.autolink.*;
public class Functions {
org.fao.geonet.api.records.formatters.groovy.Handlers handlers;
def org.fao.geonet.api.records.formatters.groovy.Functions f
def Environment env
def isHtmlOutput = {
env.formatType == FormatType.html || env.formatType == FormatType.pdf ||
env.formatType == FormatType.testpdf
}
def isPDFOutput = {
env.formatType == FormatType.pdf || env.formatType == FormatType.testpdf
}
/**
* Creates the default html for a label -> text pair. This is the element for primitive/simple data.
* This does not return a function it is returns the actual html and thus can be used within handlers/functions to
* directly get the html
*/
def textEl(label, text) {
return handlers.fileResult("html/text-el.html", ["label": label, "text" : text])
}
/**
* Same as textEl but doesn't escape the XML
*/
def wikiTextEl(label, text) {
return handlers.fileResult("html/wikitext-el.html", ["label": label, "text" : text])
}
/**
* Creates the default html for a label -> text pair. This is the element for primitive/simple data.
* This does not return a function it is returns the actual html and thus can be used within handlers/functions to
* directly get the html
*/
def urlEl(label, href, text) {
return handlers.fileResult("html/url-el.html", ["label": label, "href" : href, "text" :
text.length() > 50 ? (text.substring(0, 50) + "...") : text])
}
def textColEl(content, cols) {
return '<div class="col-md-' + cols + '">' + content + '</div>'
}
def urlToHtml(content) {
LinkExtractor linkExtractor = LinkExtractor.builder()
.linkTypes(EnumSet.of(LinkType.URL)) // limit to URLs
.build();
Iterable<LinkSpan> links = linkExtractor.extractLinks(content);
String result = Autolink.renderLinks(content, links, new LinkRenderer() {
void render(LinkSpan link, CharSequence text, StringBuilder sb) {
sb.append("<a target=\"_blank\" href=\"");
sb.append(text, link.getBeginIndex(), link.getEndIndex());
sb.append("\">");
sb.append(text, link.getBeginIndex(), link.getEndIndex());
sb.append("</a>");
}
});
return result
}
}
package common
import jeeves.server.context.ServiceContext
import org.fao.geonet.api.records.MetadataUtils
import org.fao.geonet.api.records.formatters.groovy.Environment
import org.fao.geonet.api.records.formatters.groovy.util.*
import org.fao.geonet.api.records.model.related.RelatedItemType
import org.fao.geonet.constants.Geonet
import org.fao.geonet.kernel.GeonetworkDataDirectory
import org.fao.geonet.utils.Xml
import org.jdom.Element
public class Handlers {
private org.fao.geonet.api.records.formatters.groovy.Handlers handlers;
private org.fao.geonet.api.records.formatters.groovy.Functions f
private Environment env
common.Matchers matchers
common.Functions func
boolean requireValidMetadataForPublish = false;
public Handlers(handlers, f, env) {
this.handlers = handlers
this.f = f
this.env = env
func = new common.Functions(handlers: handlers, f:f, env:env)
matchers = new common.Matchers(handlers: handlers, f:f, env:env)
}
def addDefaultStartAndEndHandlers() {
handlers.start htmlOrXmlStart
handlers.end htmlOrXmlEnd
}
def entryEl(labeller) {
return entryEl(labeller, null)
}
/**
* Creates a function that will process all children and sort then according to the sorter that applies to the elements. Then
* returns the default html for the container elements.
*
* @param labeller a function for creating a label from the element
* @param classer a function taking the element class(es) to add to the entry element. The method should return a string.
*/
def entryEl(labeller, classer) {
return { el ->
def childData = handlers.processElements(el.children(), el);
def replacement = [label: labeller(el), childData: childData, name:'']
if (classer != null) {
replacement.name = classer(el);
}
if (!childData.isEmpty()) {
return handlers.fileResult('html/2-level-entry.html', replacement)
}
return null
}
}
def processChildren(childSelector) {
return {el ->
handlers.processElements(childSelector(el), el);
}
}
/**
* Creates a function which will:
*
* 1. Select a single element using the selector function
* 2. Process all children of the element selected in step 1 with sorter that applies to the element selected in step 1
* 3. Create a label using executing the labeller on the element passed to handler functions (not element selected in step 1)
*
* @param selector a function that will select a single element from the descendants of the element passed to it
* @param labeller a function for creating a label from the element
*/
def flattenedEntryEl(selector, labeller) {
return { parentEl ->
def el = selector(parentEl)
def childData = handlers.processElements(el.children(), el);
if (!childData.isEmpty()) {
return handlers.fileResult('html/2-level-entry.html', [label: labeller(el), childData: childData])
}
return null
}
}
def selectIsotype(name) {
return {
it.children().find { ch ->
ch.name() == name || ch['@gco:isoType'].text() == name
}
}
}
def htmlOrXmlStart = {
if (func.isHtmlOutput()) {
def minimize = ''
def baseUrl = func.f.fparams.url;
if (env.param("debug").toBool()) {
minimize = '?minimize=false'
}
String cssLinks = """
<link rel="stylesheet" href="$baseUrl../../static/gn_bootstrap.css$minimize"/>
<link rel="stylesheet" href="$baseUrl../../static/gn_metadata.css$minimize"/>""";
if (func.isPDFOutput()) {
cssLinks = """<link rel="stylesheet" href="$baseUrl../../static/gn_metadata_pdf.css$minimize"/>"""
}
return """
<!DOCTYPE html>
<html>
<head lang="en">
<meta charset="UTF-8"/>
$cssLinks
<script src="$baseUrl../../static/lib.js$minimize"></script>
<script src="$baseUrl../../static/gn_formatter_lib.js$minimize"></script>
</head>
<body>
"""
} else {
return ''
}
}
def htmlOrXmlEnd = {
def required = "";
def tabToggle = "";
def activeTab = env.param('tab').toString();
if (activeTab != 'Null Value') {
tabToggle = "gnFormatter.toggleTab('$activeTab');"
}
if (!func.isPDFOutput()) {
required = """
<script type="text/javascript">
//<![CDATA[
gnFormatter.formatterOnComplete();
$tabToggle
//]]>
</script>"""
}
if (func.isHtmlOutput()) {
return required + '</body></html>'
} else {
return required
}
}
NavBarItem createXmlNavBarItem() {
return new NavBarItem(f.translate("xml"), f.translate("xml"), "", "xml.metadata.get?uuid=${env.metadataUUID}")
}
def loadHierarchyLinkBlocks() {
def uuid = this.env.metadataUUID
def id = this.env.metadataId
LinkBlock hierarchy = new LinkBlock("associated-link", "fa fa-sitemap")
Element related = getRelatedReport(id, uuid)
related.getChildren().each { rel ->
rel.getChildren("item").each { item ->
def type = rel.name
def direction = Direction.CHILD
def association
if (type == "siblings") {
association = item.getChildText("associationType")
if (association != null && association != '') {
type = association;
direction = Direction.PARENT
}
} else if (type == "services" || type == "sources" || type == "parent" || type == "fcats") {
direction = Direction.PARENT
} else if( type == 'associated') {
Element aggIndexEl = item.getChildren().find{it.getName() startsWith "agg_"}
if (aggIndexEl != null) {
type = aggIndexEl.name.substring(4)
}
} else if (type == "onlines" || type == "thumbnails") {
return;
}
def relatedIdInfo = addRelation(hierarchy, uuid, item, type, direction)
if (relatedIdInfo != null && direction == Direction.PARENT) {
def parentUUID = relatedIdInfo['uuid'] as String
def report = getRelatedReport(relatedIdInfo['id'] as int, parentUUID)
report.getChildren().each { potentialSiblingRel ->
def relType = potentialSiblingRel.name
potentialSiblingRel.getChildren("item").
findAll { it.getChildren("id").any {!it.getTextTrim().equals(uuid)}}.
each { potentialSiblingItem ->
if (association != null) {
boolean isAggSibling = potentialSiblingItem.getChildren("agg_$association").any {
it.getTextTrim() == parentUUID
}
if (isAggSibling) {
addRelation(hierarchy, parentUUID, potentialSiblingItem, association, Direction.SIBLING)
}
} else if (relType == 'datasets' || relType == 'hassource' || relType == 'hasfeaturecat') {
addRelation(hierarchy, parentUUID, potentialSiblingItem, relType, Direction.SIBLING)
} else if (relType == 'children') {
addRelation(hierarchy, parentUUID, potentialSiblingItem, "siblings", Direction.SIBLING)
}
}
}
}
}
}
return hierarchy;
}
private Element getRelatedReport(int id, String uuid) {
def relatedXsl = this.env.getBean(GeonetworkDataDirectory).getWebappDir().resolve("xslt/services/metadata/relation.xsl");
def RelatedItemType[] types = [];
def raw = MetadataUtils.getRelated(ServiceContext.get(), id, uuid, types, 1, 1000, true)
def withGui = new Element("root").addContent(Arrays.asList(
new Element("gui").addContent(Arrays.asList(
new Element("language").setText(env.lang3),
new Element("locUrl").setText(env.getLocalizedUrl())
)),
raw));
def related = Xml.transform(withGui, relatedXsl);
related
}
private Map addRelation(hierarchy, uuid, rel, type, direction) {
def arrow;
switch (direction) {
case Direction.CHILD:
arrow = "pad-left fa-long-arrow-down"
break
case Direction.PARENT:
arrow = "pad-left fa-long-arrow-up"
break
default:
arrow = "fa-arrows-h"
}
def linkType = new LinkType()
linkType.name = type
linkType.relationDirection = direction
linkType.iconHtml = """
<i class="fa ${arrow}" title="${f.translate(direction.name().toLowerCase() + "-plural")}"></i>
"""
def relUuid = rel.getChild("id").getText()
def relId = rel.getChild("mdid").getText()
def title = rel.getChild("title").getChild("value").getText()
def desc = rel.getChild("description").getChild("value").getText()
if (title == null || title.isEmpty()) {
title = relUuid;
}
def href = createShowMetadataHref(relUuid)
def cls = uuid.trim().isEmpty() ? "text-muted" : ''
def link = new AssociatedLink(href, title, cls)
link.setAbstract(desc);
link.metadataId = relUuid;
link.setLogo(rel.getChildText('logo'));
hierarchy.put(linkType, link)
return ['uuid': relUuid, 'id': relId]
}
private String createShowMetadataHref(String uuid) {
if (uuid.trim().isEmpty()) {
return "javascript:alert('" + this.f.translate("noUuidInLink") + "');"
} else {
return this.env.localizedUrl + "display#/" + URLEncoder.encode(uuid, "UTF-8") + "/formatters/full_view"
}
}
}
package common
public class Matchers {
def handlers;
def f
def env
def hasChild(childName) {
return { !it.children().find {it.name() == childName}.isEmpty() }
}
}
handlers.add select: ~/.*/, {els ->
handlers.fileResult("html/associated.html", ["associated" : new common.Handlers(handlers, f, env).loadHierarchyLinkBlocks()])
}
\ No newline at end of file
<div class="entry {{name}}">
<h3>
<button type="button" class="btn btn-default toggler" target="{{'' | generateUUID}}">
<i class="fa fa-arrow-circle-down"></i>
</button>
{{label}}
</h3>
<div id="{{'' | lastUUID}}">
<dl class="dl-horizontal">
{{childData}}
</dl>
</div>
</div>
<div fmt-repeat="linkBlock in associated"
class="summary-links summary-links-{{linkBlock.name | escapeXmlAttrs}}">
<div fmt-if="isPDF">
<div fmt-include="html/single-link.html" fmt-include-replace="true"/>
</div>
<div fmt-if="!isPDF">
<h3>
<button type="button" class="btn btn-default toggler" target="{{'' | generateUUID}}">
<i class="fa fa-arrow-circle-down"></i>
</button>
<i fmt-if="linkBlock.iconClasses" class="{{linkBlock.iconClasses}} pad-right"></i><span
fmt-translate="">{{linkBlock.name | escapeXmlContent}}</span>
</h3>
<table id="{{'' | lastUUID}}" class="table row">
<tr fmt-repeat="link in linkBlock.links" class="row">
<td class="col-md-2 link-block-title">
<h3>
<button type="button" class="btn btn-default toggler" target="{{'' | generateUUID}}">
<i class="fa fa-arrow-circle-down"></i>
</button>
<span fmt-if="link.type.iconHtml" fmt-only-children="true">{{link.type.iconHtml}}</span>
<i fmt-if="link.type.iconClasses" class="{{link.type.iconClasses}} pad-right"
title="{{link.type.iconTitle | capitalize}}"></i>
<img fmt-if="link.type.icon" src="{{link.type.icon}}"
title="{{link.type.iconTitle | capitalize}}" class="icon pad-right"></img>
<span fmt-translate="">{{link.type.name}}-link</span>
</h3>
</td>
<td class="col-md-10">
<div id="{{'' | lastUUID}}">
<div fmt-repeat="link in link.links">
<a onclick="gnFormatter.loadAssociated(event, 'div#associated-{{- | generateUUID}}', '{{link.metadataId}}');"
title="{{link.tip}}" class="{{link.cls}} associated-link-a"
target="{{'' | lastUUID}}">{{link.text | escapeXmlContent}}</a>
<a href="{{link.href}}" target="_blank" title="{{link.href}}" class="{{link.cls}}">
<i class="fa fa-external-link"></i>
</a>
<div id="{{'' | lastUUID}}" style="display: none;" class="associated-link-row">
<img class="logo" src="{{link.logo}}" fmt-if="link.logo"/>
<h3 class="text-justify" >{{link.tip | capitalize}}</h3>
<p class="text-justify" fmt-if="link.abstract">{{link.abstract}}</p>
<div id="associated-{{'' | lastUUID}}"/>
</div>
</div>
</div>
</td>
</tr>
<span fmt-if="linkBlock.html">{{linkBlock.html}}</span>
</table>
</div>
</div>
<div fmt-transclude="html/2-level-entry.html" fmt-transclude-model="childData">
<div class="thumbnail extent">
<span fmt-if="!pdfOutput" fmt-only-children="true">
<div class="input-group coord coord-north">
<input type="text" class="form-control" value="{{n}}" readonly=""/>
<span class="input-group-addon">N</span>
</div>
<div class="input-group coord coord-south">
<input type="text" class="form-control" value="{{s}}" readonly=""/>
<span class="input-group-addon">S</span>
</div>
<div class="input-group coord coord-east">
<input type="text" class="form-control" value="{{e}}" readonly=""/>
<span class="input-group-addon">E</span>
</div>
<div class="input-group coord coord-west">
<input type="text" class="form-control" value="{{w}}" readonly=""/>
<span class="input-group-addon">W</span>
</div>
</span>
<img
src="region.getmap.png?mapsrs={{mapconfig.mapproj}}&amp;amp;width={{mapconfig.width}}&amp;amp;background=settings&amp;amp;geom=Polygon(({{w}}%20{{n}},{{e}}%20{{n}},{{e}}%20{{s}},{{w}}%20{{s}},{{w}}%20{{n}}))&amp;amp;geomsrs={{geomproj}}"
style="min-width:{{minwidth}}px; min-height:{{minheight}}px;"
alt=""/>
<div fmt-if="pdfOutput">
<div>
<span class="value">{{n}}</span> <span class="input-group-addon">N</span>
<span class="value">{{s}}</span> <span class="input-group-addon">S</span>
</div>
<div>
<span class="value">{{w}}</span> <span class="input-group-addon">W</span>
<span class="value">{{e}}</span> <span class="input-group-addon">E</span>
</div>
</div>
</div>
</div>
<div fmt-repeat="linkBlock in links"
class="summary-links summary-links-{{linkBlock.name | escapeXmlAttrs}}">
<div fmt-include="html/single-link.html" fmt-include-replace="true"/>
</div>
<div fmt-transclude="html/2-level-entry.html" fmt-transclude-model="childData">
<ul class="md-value-list">
<li fmt-repeat="item in listItems">
{{item}}
</li>
</ul>
</div>
<div>
<h3>
<button type="button" class="btn btn-default toggler" target="{{'' | generateUUID}}">
<i class="fa fa-arrow-circle-down"></i>
</button>
<i fmt-if="linkBlock.iconClasses" class="{{linkBlock.iconClasses}} pad-right"></i><span
fmt-translate="">{{linkBlock.name | escapeXmlContent}}</span>
</h3>
<table id="{{'' | lastUUID}}" class="table row target">
<tr fmt-repeat="link in linkBlock.links" class="row">
<td class="col-md-2 link-block-title">
<span fmt-if="link.type.iconHtml" fmt-only-children="true">{{link.type.iconHtml}}</span>
<i fmt-if="link.type.iconClasses" title="{{link.type.iconTitle | capitalize}}"
class="{{link.type.iconClasses}} pad-right"></i>
<img fmt-if="link.type.icon" src="{{link.type.icon}}"
title="{{link.type.iconTitle | capitalize}}" class="icon pad-right"></img>
<span fmt-translate="">{{link.type.name}}-link</span>
</td>
<td class="col-md-10">
<div fmt-repeat="link in link.links">
<a fmt-if="isPDF" href="{{link.href | escapeXmlAttrs}}" target="_blank"
title="{{link.tip | escapeXmlAttrs}}" class="{{link.cls}}">{{link.text |
escapeXmlContent}}</a>
<a fmt-if="!isPDF" href="{{link.href}}" target="_blank" title="{{link.tip}}"
class="{{link.cls}}">{{link.text | escapeXmlContent}}</a>
</div>
</td>
</tr>
<span fmt-if="linkBlock.html">{{linkBlock.html}}</span>
</table>
</div>
<div fmt-if="text" class="md-text">
<dt title="{{label | escapeXmlContent}}">{{label | escapeXmlContent}}</dt>
<dd>{{text | escapeXmlContent}}</dd>
</div>
\ No newline at end of file
<div fmt-if="text" class="md-text">
<dt title="{{label | escapeXmlContent}}">{{label | escapeXmlContent}}</dt>
<dd><a href="{{href | escapeXmlAttrs}}" title="{{href | escapeXmlAttrs}}">{{text | escapeXmlContent}}</a></dd>
</div>
\ No newline at end of file
<div class="container gn-metadata-view gn-metadata-view-groovy">
<script type="application/javascript" fmt-if="isHTML">
//<![CDATA[
document.title = "{{pageTitle}}";
var headEl = $("head");
var iconLink = headEl.children("link[rel='shortcut icon']");
if (iconLink.length > 0) {
iconLink.attr("href", "{{logo}}");
} else {
headEl.append("<link rel='shortcut icon' type='image/x-icon' href='{{logo}}'></link>");
}
//]]>
</script>
<h1>
<img fmt-if="logo" class="logo" src="{{logo | escapeXmlAttrs}}"></img>
<i fmt-if="!logo" class="fa fa-arrow-circle-down"></i>
<span class="title">{{title | escapeXmlContent}}</span>
</h1>
<ul fmt-if="!isPDF" class="view-outline nav nav-tabs">
<li fmt-if="addOverviewNavItem" id="tab-overview">
<a href="" rel=".overview" fmt-translate="">overview</a>
</li>
<li fmt-if="associated" id="tab-associated">
<a href="" rel=".container > .associated"><span fmt-translate="">associated-link</span>&amp;nbsp;
<i class="fa fa-circle-o-notch fa-spin associated-spinner"></i></a>