'use strict'; const MAPBOX_API_KEY = 'pk.eyJ1IjoiZ2VyYW5nMSIsImEiOiJjbDg5MHZxcG8wMmo3M3BudnphMWhnN2ZrIn0.SsFGVF-EMHwRYTp7njmb_Q'; /** * @namespace DataSpace */ const DataSpace = {}; DataSpace.BASE_URL = 'http://dataspace.ispc.cnr.it'; DataSpace.RES_ENDPOINT = '/resources/'; DataSpace.FILES_URI = `${DataSpace.BASE_URL}/files/uploadedfiles/`; DataSpace.OBJECT_ORDER = { "Object Type" : null, "Object ID" : null, "Object Excavation code" : null, "Object Chronology" : null, "Object Era" : null, "Object Geographical Context of Discovery" : null, "Object Dimensions" : null, "Object Material" : null, "Object Description" : null, "Object Conservation State" : null, "Object Reused?" : null, "Object Project" : null, "Object Compiler" : null, "Object Bibliography" : null, }; /* export const SAMPLE_ORDER = { }; */ const OBJECT_REPORT = new Map(); OBJECT_REPORT.set( 'before-gallery', { "Object Type" : null, "Object ID" : null, "Object Excavation code" : null, "Object Chronology" : null, "Object Era" : null, "Object Geographical Context of Discovery" : null, "Object Dimensions" : null, "Object Material" : null, } ); OBJECT_REPORT.set( 'after-gallery-1-col', { "Object Description" : null, "Object Conservation State" : null, } ); OBJECT_REPORT.set( 'after-gallery-2-col', { "Object Reused?" : null, "Object Project" : null, "Object Compiler" : null, "Object Bibliography" : null, } ); DataSpace.OBJECT_REPORT = OBJECT_REPORT; /** * Populate partial objects from * resource object based on Map * @todo * @param {object} resource * * @return {Map} */ DataSpace.createObjectShape = function (resource) { const shape = this.OBJECT_REPORT; let beforeGallery = shape.get('before-gallery'), afterGalleryCol1 = shape.get('after-gallery-1-col'), afterGalleryCol2 = shape.get('after-gallery-2-col'); // TODO export to private function for (const key in shape.get('before-gallery')) { if (resource[key]) { beforeGallery[key] = resource[key]; } else { delete beforeGallery[key]; } } for (const key in shape.get('after-gallery-1-col')) { if (resource[key]) { afterGalleryCol1[key] = resource[key]; } else { delete afterGalleryCol1[key]; } } for (const key in shape.get('after-gallery-2-col')) { if (resource[key]) { afterGalleryCol2[key] = resource[key]; } else { delete afterGalleryCol2[key]; } } shape.set('before-gallery', beforeGallery); shape.set('after-gallery-1-col', afterGalleryCol1); shape.set('after-gallery-2-col', afterGalleryCol2); return shape; } /** * @todo Refactor!! * * @param {object} report The report's JSON object * @param {string[]} images Filenames of images * * @return {void} */ DataSpace.renderObjectReport = function (report, images) { // TODO const resource = Object.assign(this.OBJECT_ORDER, report.resource); const shape = this.createObjectShape(resource); let resKeys = Object.keys(resource); // Default value... let resType = 'Object'; // TODO if (!resKeys.length) { location.href = '/404.html'; return; } resType = resKeys[0].split(' ')[0]; // TODO use match... // TODO check if coordinates exists... const coordinates = resource['Object Coordinates'] ?.replace(/^.*coordinates\':\s?\[(\d+\.\d+,\s?\d+\.\d+)\].*$/, "$1") ?.split(', '); let lat, long; [long, lat] = coordinates; this.createMap([lat, long]); // Write coordinates below map document.querySelector('#coord').innerHTML = ` Latitude: ${lat} Longitude: ${long} `; resKeys = resKeys.filter(e => !e.includes('Coordinates')); document.querySelector('#rep-tit') .innerText = `${resType} ${report.displayname}`; _createObjectTable(resType, shape, resource); if (images.length) { _createImgGallery(images, 'gallery'); } // Create after-gallery... _createObjectTail(resType, shape, resource); } /** * Fetch JSON report... * @param {string} uuid The resource's UUID in Arches * @param {string} format Either 'json' or 'arches-json' * * @return {object} */ DataSpace.fetchReport = async function (uuid, format='json') { return await fetch( `${this.BASE_URL}${this.RES_ENDPOINT}${uuid}?format=${format}&indent=2` ) .then(res => res.json()) .catch(excep => { _fetchError(excep, 'error'); document.querySelector('.modal') .classList.remove('active'); }); } /** * Add window.print to link in navbar * * @return {void} */ DataSpace.printReport = function () { document.querySelector('#print') .addEventListener('click', () => { window.print(); }); } /** * @todo Use OpenLayers? * Attach Leaflet.js map to HTML element * * @param {string[]} coordinates * @param {string} htmlId * * @return {void} */ DataSpace.createMap = function (coordinates, htmlId = 'map') { const mapboxAttribution = `© Mapbox`; const mapboxSat = `https://api.mapbox.com/v4/mapbox.satellite/18/152278/101181.webp?access_token=${MAPBOX_API_KEY}`; const streets = L.tileLayer('https://tile.openstreetmap.org/{z}/{x}/{y}.png', { maxZoom: 18, attribution: '© OpenStreetMap' }); const satellite = L.tileLayer( mapboxSat, { id: 'mapbox/satellite-v9', tileSize: 512, zoomOffset: -1, attribution: mapboxAttribution } ); const baseMaps = { "OpenStreetMap": streets, "Mapbox Satellite": satellite }; const map = L.map(htmlId, { center: coordinates, zoom: 18, layers: [streets, satellite] }); L.control.layers(baseMaps).addTo(map); L.marker(coordinates).addTo(map) .bindPopup(`lat.: ${coordinates[0]}, long. : ${coordinates[1]}`); } /** * @todo Use TS to define object shape * @param {object} resource The resource object (Arches JSON!) * * @return {string[]} */ DataSpace.getImagesSrc = function (resource) { // TODO don't filter this array, populate another one let arr = resource.tiles .filter(tile => { let key = Object.keys(tile.data)[0]; return Array.isArray(tile.data[key]); }).filter(o => { let key = Object.keys(o.data)[0]; return Object.keys(o.data[key][0]).includes('file_id'); }); let fileNames = [], dataObjects = []; arr.forEach(d => dataObjects.push(d.data)); dataObjects.forEach(e => { e[Object.keys(e)[0]].forEach(o => { fileNames.push(this.FILES_URI + o.name) }); }); return fileNames; } /** * @todo The order of elements in the tiles array * in arches-json is the same as that of * objects in the JSON resource (report) * * @param {object} resource The resource object (Arches JSON!) * * @return {string[]} DataSpace.getLinkedData = function (resource) { } */ function _fetchError(message, htmlId) { const error = document.createElement('div'); const clear = document.createElement('button'); error.className = 'toast toast-error'; clear.className = 'btn btn-clear float-right'; error.appendChild(clear); error.textContent = message; document.querySelector(`#${htmlId}`).appendChild(error); } function _createImgGallery(images, htmlId) { let gallery = document.querySelector(`#${htmlId}`); gallery.parentElement .classList.remove('d-hide'); for (const src of images) { const img = document.createElement('img'); img.className = 'img-responsive img-fit-cover'; img.src = src; const col = document.createElement('div'); col.className = 'column col-3 c-hand spotlight'; col.setAttribute('data-src', src); col.setAttribute('data-download', true); col.appendChild(img); gallery.appendChild(col); } } function _createObjectTable(resType, shape, resource) { const tableElement = document.querySelector('#res-before tbody'); for (const key in shape.get('before-gallery')) { const row = document.createElement('tr'); let innerList = null; // TODO refactor if (typeof resource[key] == 'object') { innerList = document.createElement('ul'); for (const innerKey in resource[key]) { const li = document.createElement('li'); li.innerHTML = innerKey === '@value' ? resource[key]['@value'] : `${innerKey.replace(key,'')}: ${resource[key][innerKey]}`; if (resource[key][innerKey] !== null) { innerList.appendChild(li); } } } let value = innerList !== null ? innerList.outerHTML : resource[key]; row.innerHTML = ` ${key.replace(resType, '')} ${value} `; if (!key.includes('Images') && !key.includes('Photos')) { tableElement.appendChild(row); } } } function _createObjectTail(resType, shape, resource) { let after = document.querySelector('#res-after'); for (const key in shape.get('after-gallery-1-col')) { const col = document.createElement('div'); col.className = 'column col-12'; col.innerHTML = `

${key.replace(resType, '')}

${resource[key]}

`; after.appendChild(col); } for (const key in shape.get('after-gallery-2-col')) { const col = document.createElement('div'); col.className = 'column col-6'; let displayValue = resource[key]; const isNested = typeof resource[key] === 'object'; if (isNested) { for (const innerKey in resource[key]) { if (resource[key][innerKey] !== "") { const innerCol = document.createElement('div'); innerCol.className = 'column col-6'; innerCol.innerHTML = innerKey === '@value' ? `

${key.replace(resType, '')}

${displayValue['@value'].replace('False', 'No') .replace('True', 'Yes')}

` : `

${innerKey.replace(resType, '')}

${displayValue[innerKey]}

` ; after.appendChild(innerCol); } } } else { col.innerHTML = `

${key.replace(resType, '')}

${displayValue}

`; after.appendChild(col); } } } export default DataSpace;