Last active
October 30, 2025 05:54
-
-
Save wragge/5680daaec4b4b34ed5537e6ff79559a2 to your computer and use it in GitHub Desktop.
Displays buttons to open SLV digitised maps in AllMaps for viewing and/or georeferencing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // ==UserScript== | |
| // @name Link SLV maps to AllMaps for georeferencing | |
| // @namespace wraggelabs.com/link-slv-allmaps | |
| // @match *://viewer.slv.vic.gov.au/?entity=IE* | |
| // @grant GM.xmlHttpRequest | |
| // @connect viewerapi.slv.vic.gov.au | |
| // @connect annotations.allmaps.org | |
| // @version 1.0 | |
| // @author Tim Sherratt (tim@timsherratt.au) | |
| // @description Displays buttons to open SLV digitised maps in AllMaps for viewing and/or georeferencing. | |
| // @require https://cdn.jsdelivr.net/gh/CoeJoder/waitForKeyElements.js@v1.3/waitForKeyElements.js | |
| // ==/UserScript== | |
| const DEFAULT_LENGTH = 16; | |
| // These two functions are from the AllMaps id module. | |
| // https://github.com/allmaps/allmaps/tree/main/packages/id | |
| /** | |
| * Computes SHA-1 hash of input string. | |
| * | |
| * @param Input string. | |
| * @returns SHA-1 hash of `str`. | |
| */ | |
| async function generateHash(str) { | |
| const hashBuffer = await crypto.subtle.digest('SHA-1', new TextEncoder().encode(str)); | |
| const hashArray = Array.from(new Uint8Array(hashBuffer)); | |
| const hashHex = hashArray | |
| .map((byte) => byte.toString(16).padStart(2, '0')) | |
| .join(''); | |
| return hashHex; | |
| } | |
| /** | |
| * Generates an ID from a string using the SHA-1 algorithm. Given the same input, the ID will always be the same. | |
| * | |
| * @param str - Input string | |
| * @param length - Length of returned hash. The maximum length of the hash is 40 characters. The default length is 16. | |
| * @returns First `length` characters of the SHA-1 hash of `str`. | |
| */ | |
| async function generateId(str, length = DEFAULT_LENGTH) { | |
| const hash = await generateHash(String(str)); | |
| return hash.slice(0, length); | |
| } | |
| // Adds links to Allmaps in the summary information section | |
| function addButtons(ieID, hashId, status) { | |
| let summary = document.querySelector("div.cell.summaryCell.small-12.medium-8"); | |
| let geoHeader = document.createElement("h3"); | |
| geoHeader.innerText = "Georeferencing"; | |
| geoHeader.style.marginTop = "2rem"; | |
| summary.appendChild(geoHeader); | |
| let geoMessage = document.createElement("p"); | |
| // Create button to georeference in AllMaps editor | |
| // Text of button will change depending on whether item is already georeferenced. | |
| let editButton = document.createElement("a"); | |
| editButton.className = "button viewCatalogueEntry"; | |
| editButton.href = "https://editor.allmaps.org/images?url=" + encodeURIComponent("https://wraggelabs.com/slv_iiif/" + ieID); | |
| if (status == 200) { | |
| // Item has been georeferenced | |
| geoMessage.innerHTML = "This item has been georeferenced using <a href='https://allmaps.org'>AllMaps</a>." | |
| summary.appendChild(geoMessage); | |
| editButton.textContent = "Edit georeferencing using AllMaps"; | |
| summary.appendChild(editButton); | |
| // Add button to open in AllMaps viewer | |
| let viewButton = document.createElement("a"); | |
| viewButton.className = "button viewCatalogueEntry"; | |
| viewButton.href = "https://viewer.allmaps.org?url=" + encodeURIComponent("https://annotations.allmaps.org/manifests/" + hashId); | |
| viewButton.textContent = "View georeferenced item using AllMaps"; | |
| viewButton.style.marginLeft = "2rem"; | |
| summary.appendChild(viewButton); | |
| // Add iframe showing Allmaps viewer | |
| let embed = document.createElement("iframe"); | |
| embed.src = "https://viewer.allmaps.org?url=" + encodeURIComponent("https://annotations.allmaps.org/manifests/" + hashId); | |
| embed.width = "100%"; | |
| embed.height = "500px"; | |
| embed.style.marginTop = "1rem"; | |
| embed.style.border = "0"; | |
| summary.appendChild(embed); | |
| } else { | |
| // Item has not been georeferenced | |
| geoMessage.innerHTML = "This item can be georeferenced using <a href='https://allmaps.org'>AllMaps</a>." | |
| summary.appendChild(geoMessage); | |
| editButton.textContent = "Georeference using AllMaps"; | |
| summary.appendChild(editButton); | |
| } | |
| } | |
| // Checks to see if a manifest has already been georeferenced using Allmaps | |
| async function checkAllmaps(ieID) { | |
| // Create a SLV manifest url | |
| let manifestUrl = "https://rosetta.slv.vic.gov.au/delivery/iiif/presentation/2.1/" + ieID + "/manifest"; | |
| // Generate an AllMaps id from the manifest url | |
| let hashId = await generateId(manifestUrl); | |
| console.log(hashId); | |
| // Fire off a HEAD request to see if the id exists on AllMaps | |
| GM.xmlHttpRequest({ | |
| method: 'HEAD', | |
| url: "https://annotations.allmaps.org/manifests/" + hashId, | |
| onload: function(response) { | |
| addButtons(ieID, hashId, response.status); | |
| } | |
| }); | |
| } | |
| // Look at the item metadata to see if it is a map (or contains maps) | |
| function getMetadata(ieID) { | |
| // Get item metadata from the JSON API | |
| GM.xmlHttpRequest({ | |
| method: 'GET', | |
| url: "https://viewerapi.slv.vic.gov.au/?entity=" + ieID + "&dc_arrays=1", | |
| onload: function(response) { | |
| const data = JSON.parse(response.responseText); | |
| const md = data["viewer_md"]; | |
| // Look for the word map or maps | |
| let regexp = /\b(?:map|maps)\b/i; | |
| // Fields that might contain useful information | |
| const summary = md.summary || []; | |
| const genre = md.genre || []; | |
| const subject = md.subject || []; | |
| const description = md.description || md.group_md.description || []; | |
| // Check each field for map or maps | |
| for (let field of [summary, genre, subject, description]) { | |
| for (let value of field) { | |
| if (regexp.test(value)) { | |
| console.log("It's a map!"); | |
| isMap = true; | |
| break; | |
| } | |
| } | |
| if (isMap === true) { | |
| break; | |
| } | |
| } | |
| if (isMap === true) { | |
| checkAllmaps(ieID); | |
| } | |
| } | |
| }); | |
| } | |
| // Get the IE identifier from the url | |
| const ieID = location.href.match(/entity=(IE\d+)/)[1]; | |
| let isMap = false; | |
| // Wait for the page to load | |
| waitForKeyElements("div.cell.summaryCell.small-12.medium-8", (summaryDiv) => { | |
| getMetadata(ieID); | |
| }); |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
SLV/AllMaps
Installation
If you haven't already, add a userscript manager such as ViolentMonkey or TamperMonkey to your browser. These are browser extensions or add-ons that are installed from standard web stores – just follow the instructions for your preferred browser. Note that if you're using TamperMonkey with Chrome you might need to explicitly give it permission to run userscripts.
Once your userscript manager is installed, click on the Raw button at the top of the code box. Your userscript manager will display a window with details of the userscript, and ask you to confirm that you want to proceed. Click 'install' to complete the installation.
More information
See this page for full documentation.