Skip to content

Instantly share code, notes, and snippets.

@arbakker
Created May 31, 2022 10:16
Show Gist options
  • Save arbakker/83145e4567995c0ed93713eed166db55 to your computer and use it in GitHub Desktop.
Save arbakker/83145e4567995c0ed93713eed166db55 to your computer and use it in GitHub Desktop.
NGR - improved xml metadata view - greasemonkey userscript #greasemonkey #js #userscript #NGR #geonetwork
// ==UserScript==
// @name NGR - improved xml metadata view
// @version 1.0.4
// @grant GM.info
// @require https://cdn.jsdelivr.net/gh/highlightjs/[email protected]/build/highlight.min.js
// @match https://nationaalgeoregister.nl/geonetwork/srv/dut/catalog.search*
// @match https://ngr.acceptatie.nationaalgeoregister.nl/geonetwork/srv/dut/catalog.search*
// @run-at document-end
// ==/UserScript==
// run in your browser with https://www.tampermonkey.net/
var customCSS = `
code span{
font-family: Menlo, Monaco, Consolas, "Courier New", monospace !important; /* highlightjs spans causes font change */
}
pre{
background-color: #fdf6e3; /* bg color of solarized light */
margin-top:1em;
}
.hljs{
background: unset;
}
// solarized light highlight
.hljs{display:block;overflow-x:auto;padding:.5em;background:#fdf6e3;color:#657b83}.hljs-comment,.hljs-quote{color:#93a1a1}.hljs-addition,.hljs-keyword,.hljs-selector-tag{color:#859900}.hljs-doctag,.hljs-literal,.hljs-meta .hljs-meta-string,.hljs-number,.hljs-regexp,.hljs-string{color:#2aa198}.hljs-name,.hljs-section,.hljs-selector-class,.hljs-selector-id,.hljs-title{color:#268bd2}.hljs-attr,.hljs-attribute,.hljs-class .hljs-title,.hljs-template-variable,.hljs-type,.hljs-variable{color:#b58900}.hljs-bullet,.hljs-link,.hljs-meta,.hljs-meta .hljs-keyword,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-subst,.hljs-symbol{color:#cb4b16}.hljs-built_in,.hljs-deletion{color:#dc322f}.hljs-formula{background:#eee8d5}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}
`
function GM_addStyle(cssStr) {
var D = document;
var newNode = D.createElement('style');
newNode.textContent = cssStr;
var targ = D.getElementsByTagName('head')[0] || D.body || D.documentElement;
targ.appendChild(newNode);
}
// see https://stackoverflow.com/a/33928558/1763690
function copyToClipboard(text) {
if (window.clipboardData && window.clipboardData.setData) {
// Internet Explorer-specific code path to prevent textarea being shown while dialog is visible.
return clipboardData.setData("Text", text)
}
else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
var textarea = document.createElement("textarea")
textarea.textContent = text
textarea.style.position = "fixed"; // Prevent scrolling to bottom of page in Microsoft Edge.
document.body.appendChild(textarea)
textarea.select()
try {
return document.execCommand("copy"); // Security exception may be thrown by some browsers.
}
catch (ex) {
console.warn("Copy to clipboard failed.", ex)
return false
}
finally {
document.body.removeChild(textarea)
}
}
}
function queryMetadata(selector) {
let parser = new DOMParser()
let xmlEl = document.getElementById("xml")
let xmlDoc = parser.parseFromString(xmlEl.innerText, "text/xml")
console.log(xmlDoc)
let el = xmlDoc.querySelector(selector)
if (el) {
return el
}
return null
}
function queryAll(selector) {
let parser = new DOMParser()
let xmlEl = document.getElementById("xml")
let xmlDoc = parser.parseFromString(xmlEl.innerText, "text/xml")
return xmlDoc.querySelectorAll(selector)
}
function getParams(url) {
var params = {};
var parser = document.createElement('a');
parser.href = url;
var query = parser.search.substring(1);
var vars = query.split('&');
for (var i = 0; i < vars.length; i++) {
var pair = vars[i].split('=');
params[pair[0]] = decodeURIComponent(pair[1]);
}
return params;
};
function createButton(id, text, title, anchor=false) {
let btn = document.createElement("button")
if (anchor){
btn = document.createElement("a")
}
btn.id = id
btn.innerText = text
btn.classList.add("btn")
btn.classList.add("btn-default")
btn.title = title
return btn
}
function showCopyError(query) {
let querySlash = query.replaceAll(" ", "/")
alert(`could not locate //${querySlash} element in metadata`)
}
function copySucces() {
let icon = document.getElementById("copy-succes")
icon.style.display = "inline-block"
setTimeout(function () { icon.style.display = "none" }, 1000);
}
function copySuccesMd() {
let icon = document.getElementById("copy-succes-md")
icon.style.display = "inline-block"
setTimeout(function () { icon.style.display = "none" }, 1000);
}
function getMenuItem(id, text, title) {
let menuItem = document.createElement("li")
menuItem.setAttribute("role", "menuitem")
let menuA = document.createElement("a")
menuA.id = id
menuA.title = title
let menuSpan = document.createElement("span")
menuSpan.innerText = text
menuA.appendChild(menuSpan)
menuItem.appendChild(menuA)
return menuItem
}
function is_service_record(){
// <gmd:hierarchyLevel>
// <gmd:MD_ScopeCode @codeListValue
let query = "hierarchyLevel MD_ScopeCode"
let result = queryMetadata(query)
let scopeString = result.getAttribute("codeListValue")
console.log(scopeString)
return scopeString == "service"
}
function initCodeBlock() {
if (window.location.hash.includes("&output=xml")) {
new Promise(function (resolve, reject) {
setTimeout(resolve,
2000)
}).then(function () {
let codeDiv = document.getElementById("gn-metadata-display")
if (codeDiv.firstElementChild && codeDiv.firstElementChild.tagName === "LINK") {
codeDiv.removeChild(codeDiv.firstElementChild)
}
let groupDiv = document.createElement("div")
groupDiv.classList.add("btn-group")
groupDiv.innerHTML = '<div class="btn-group" id="mdxmltools-btn-group"><button type="button" title="Copy metadata elements"' +
'class="btn btn-default dropdown-toggle" data-toggle="dropdown"><i id="copy-succes" style="display:none;"' +
'class="fa fa-fw fa-check"></i><span>Copy md elements</span><span class="caret"></span></button>' +
'<ul role="menu" class="dropdown-menu" id="mdxmltools-menuitems"></ul>' +
'</div>'
let ul = groupDiv.firstChild.lastChild
let codeEl = document.querySelector("code.html")
if (codeEl) {
let unescapedXml = codeEl.innerHTML
let xml = codeEl.innerHTML.replaceAll("&amp;amp;",
"&amp;")
codeEl.innerHTML = xml
let xmlDiv = document.getElementById("xml")
if (!xmlDiv) {
xmlDiv = document.createElement("div")
xmlDiv.id = "xml"
xmlDiv.style.display = "none" // Prevent scrolling to bottom of page in Microsoft Edge.
document.body.appendChild(xmlDiv)
}
xmlDiv.innerHTML = unescapedXml
}
hljs.highlightBlock(codeEl)
// copy md button
let btn = createButton("copy-metadata", "Copy metadata", "Copy metadata to clipboard")
btn.innerHTML = '<i id="copy-succes-md" style="display:none;" class="fa fa-fw fa-check"></i><span>Copy metadata</span>'
btn.addEventListener("click", function () {
let xmlEl = document.getElementById("xml")
copyToClipboard(xmlEl.innerText)
copySuccesMd()
})
// copy online resource
let menuItem = getMenuItem("copy-onlineresource", "Copy onlineResource", "Copy onlineResource to clipboard")
ul.appendChild(menuItem)
menuItem.firstChild.addEventListener("click", function () {
try {
const query = "MD_DigitalTransferOptions onLine CI_OnlineResource linkage URL"
let result = queryMetadata(query)
if (result) {
copyToClipboard(result.textContent)
copySucces()
} else {
showCopyError(query)
}
} catch (ex) {
console.log(ex)
}
})
// copy md id
let menuItem2 = getMenuItem("copy-mdid", "Copy metadata id", "Copy metadata identifier to clipboard")
ul.appendChild(menuItem2)
let menuA2 =
menuItem2.firstChild.addEventListener("click", function () {
let query = "fileIdentifier CharacterString"
let result = queryMetadata(query)
if (result) {
copyToClipboard(result.textContent)
copySucces()
} else {
showCopyError(query)
}
})
// copy ds id
let menuItem3 = getMenuItem("copy-did", "Copy dataset source id", "Copy dataset source identifier to clipboard")
ul.appendChild(menuItem3)
menuItem3.firstChild.addEventListener("click", function () {
let sourceId =''
let query = ''
if (! is_service_record()){
query = "identifier MD_Identifier code CharacterString"
let result = queryMetadata(query)
if (result) {
console.log(result)
sourceId = result.textContent
}
}else{
query = "operatesOn"
let result = queryMetadata(query)
if (result) {
sourceId = result.getAttribute("uuidref")
}
}
if(sourceId){
copyToClipboard(sourceId)
copySucces()
}else{
showCopyError(query)
}
})
let menuItem4 = getMenuItem("copy-title", "Copy title", "Copy service metadataa title to clipboard")
ul.appendChild(menuItem4)
menuItem4.firstChild.addEventListener("click", function () {
let query = "CI_Citation title CharacterString"
let result = queryMetadata(query)
if (result) {
copyToClipboard(result.textContent)
copySucces()
} else {
showCopyError(query)
}
})
if (is_service_record()){
let menuItem5 = getMenuItem("copy-layers", "Copy layers", "Copy layers from service to clipboard")
ul.appendChild(menuItem5)
menuItem5.firstChild.addEventListener("click", function () {
let query = "SV_CoupledResource ScopedName"
let layers = []
let result = queryAll(query)
result.forEach(function (el) { layers.push(el.textContent) })
let unique = [...new Set(layers)];
let layersString = Array.from(unique).join(', ')
if (layersString) {
copyToClipboard(layersString)
copySucces()
} else {
showCopyError(query)
}
})
}
// copy ds md id
if (is_service_record()){
let menuItem6 = getMenuItem("copy-dmdid", "Copy dataset metadata id", "Copy dataset metadata identifier to clipboard")
ul.appendChild(menuItem6)
menuItem6.firstChild.addEventListener("click", function () {
let query = "operatesOn"
let result = queryMetadata(query)
if (result) {
let mdUrl = result.getAttribute("xlink:href")
let params = getParams(mdUrl)
let mdId = ""
let succes = false
if (params["id"] !== undefined) {
mdId = params["id"]
succes = true
} else if (params["uuid"] !== undefined) {
mdId = params["uuid"]
succes = true
}
if (succes) {
copyToClipboard(mdId)
copySucces()
} else {
showCopyError(query)
}
} else {
showCopyError(query)
}
})
}
let menuItem7 = getMenuItem("copy-csw-url", "Copy GetRecordById URL", "Copy CSW GetRecordById URL")
ul.appendChild(menuItem7)
menuItem7.firstChild.addEventListener("click", function () {
let query = "fileIdentifier CharacterString"
let result = queryMetadata(query)
if (result){
let mdId = result.textContent
let prot = window.location.protocol
let host= window.location.host
let path = window.location.pathname.replace("catalog.search", "csw")
// https://ngr.acceptatie.nationaalgeoregister.nl/geonetwork/srv/dut/csw?
let query = `service=CSW&request=GetRecordById&version=2.0.2&outputSchema=http://www.isotc211.org/2005/gmd&elementSetName=full&id=${mdId}#MD_DataIdentification`
let getRecordUrl = `${prot}//${host}${path}?${query}`
copyToClipboard(getRecordUrl)
copySucces()
} else {
showCopyError(query)
}
})
let parent = document.querySelector(".btn-toolbar")
parent.appendChild(btn)
parent.appendChild(groupDiv)
})
} else {
let mdbtn = document.getElementById('copy-metadata')
if (mdbtn){
mdbtn.parentNode.removeChild(mdbtn)
let btnGroup = document.getElementById("mdxmltools-btn-group")
btnGroup.parentNode.removeChild(btnGroup)
}
}
}
var buttonAdded = false
function initLinkButton(){
new Promise(function (resolve, reject) {
setTimeout(resolve,
2000)
}).then(function () {
let anchors = document.querySelectorAll("div.gn-related-resources p.text-muted a")
console.log(anchors)
for (let i = 0; i < anchors.length; i++) {
let anchor = anchors[i]
const myRe = /.*\?.*?service=(wms|wfs)/gi;
let matches = anchor.href.matchAll(myRe)
for (const match of matches) {
console.log('match', match);
console.log('match.index',match.index)
let svcType = match[1]
let btn = createButton(anchor.href, "PDOK Reviewer", "Bekijk deze service in de PDOK Reviewer", true)
let url = `https://super-funicular-1f6dee8a.pages.github.io/#/${svcType.toLowerCase()}/${encodeURIComponent(anchor.href)}`
let exBtn = document.getElementById(anchor.href)
if (exBtn){
return
}
btn.href = url
btn.target = '_blank'
btn.style.margin = '1em'
// anchor.parentNode.parentNode.parentNode.insertBefore(btn, anchor.parentNode.parentNode);
let insertNode = document.querySelector("div.gn-related-resources")
console.log(insertNode)
insertNode.insertBefore(btn, insertNode.firstChild.nextSibling.nextSibling)
buttonAdded = true
}
}
})
}
function initScript() {
let scriptName = GM.info.script.name
console.log(`running ${scriptName} on document-end`)
console.log(customCSS)
GM_addStyle(customCSS)
initCodeBlock()
initLinkButton()
}
window.addEventListener('hashchange', function () {
initScript()
})
initScript()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment