import {send as notify} from './notification'; import * as utils from "./utils"; import {createInstance} from "./src/i18n"; export default class JSONLD { constructor(baseApiUrl, entities) { this.entities = entities; this.baseApiUrl = baseApiUrl; let idToEntityNameMatchList = {}; for (const entityName in entities) { const id = entities[entityName]["@id"]; idToEntityNameMatchList[id] = entityName; } this.idToEntityNameMatchList = idToEntityNameMatchList; } static async getInstance(apiUrl, lang = 'de') { let promise = JSONLD.promises[apiUrl]; if (promise === undefined) { promise = new Promise((resolve, reject) => { JSONLD._initialize( apiUrl, (instance) => resolve(instance), (error) => reject(error), lang ); }); JSONLD.promises[apiUrl] = promise; } return promise; } static initialize(apiUrl, successFnc, failureFnc, lang = 'de') { console.warn('DEPRECATED: JSONLD.initialize(), use JSONLD.getInstance() instead'); JSONLD._initialize(apiUrl, successFnc, failureFnc, lang); } static doInitializationOnce(apiUrl) { // No longer needed, remove any calls console.warn('DEPRECATED: JSONLD.doInitializationOnce() calls can be removed'); } static _initialize(apiUrl, successFnc, failureFnc, lang = 'de') { JSONLD._i18n.changeLanguage(lang); // if init api call was already successfully finished execute the success function if (JSONLD.instances[apiUrl] !== undefined) { if (typeof successFnc == 'function') successFnc(JSONLD.instances[apiUrl]); return; } // init the arrays if (JSONLD.successFunctions[apiUrl] === undefined) JSONLD.successFunctions[apiUrl] = []; if (JSONLD.failureFunctions[apiUrl] === undefined) JSONLD.failureFunctions[apiUrl] = []; // add success and failure functions if (typeof successFnc == 'function') JSONLD.successFunctions[apiUrl].push(successFnc); if (typeof failureFnc == 'function') JSONLD.failureFunctions[apiUrl].push(failureFnc); if (!apiUrl || JSONLD.initStarted[apiUrl] !== undefined) { return; } JSONLD.initStarted[apiUrl] = true; JSONLD._doInitialization(apiUrl); } static _doInitialization(apiUrl) { const xhr = new XMLHttpRequest(); const i18n = JSONLD._i18n; xhr.open("GET", apiUrl, true); xhr.onreadystatechange = function () { if (xhr.readyState !== 4) { return; } if (xhr.status === 200) { const json = JSON.parse(xhr.responseText); let entryPoints = {}; for (let property in json) { // for some reason the properties start with a lower case character if (!property.startsWith("@")) entryPoints[property.toLowerCase()] = json[property]; } // read the link header of the api response // const utils = require("./utils"); const links = utils.parseLinkHeader(this.getResponseHeader("link")); // get the hydra apiDocumentation url const apiDocUrl = links["http://www.w3.org/ns/hydra/core#apiDocumentation"]; if (apiDocUrl !== undefined) { // load the hydra apiDocumentation const docXhr = new XMLHttpRequest(); docXhr.open("GET", apiDocUrl, true); docXhr.setRequestHeader("Content-Type", "application/json"); docXhr.onreadystatechange = function () { if (docXhr.readyState !== 4) { return; } if (docXhr.status === 200) { JSONLD._gatherEntities(docXhr, apiUrl, entryPoints); } else { JSONLD._executeFailureFunctions(apiUrl, i18n.t('jsonld.api-documentation-server', {apiUrl: apiDocUrl})); } }; docXhr.send(); } else { JSONLD._executeFailureFunctions(apiUrl, i18n.t('jsonld.error-hydra-documentation-url-not-set', {apiUrl: apiUrl})); } } else { JSONLD._executeFailureFunctions(apiUrl, i18n.t('jsonld.error-api-server', {apiUrl: apiUrl})); } }; xhr.send(); } /** * Gather the entities * * @param docXhr * @param apiUrl * @param entryPoints */ static _gatherEntities(docXhr, apiUrl, entryPoints) { const json = JSON.parse(docXhr.responseText); const supportedClasses = json["hydra:supportedClass"]; let entities = {}; const baseUrl = utils.parseBaseUrl(apiUrl); // gather the entities supportedClasses.forEach(function (classData) { // add entry point url const entityName = classData["hydra:title"]; let entryPoint = entryPoints[entityName.toLowerCase()]; if (entryPoint !== undefined && !entryPoint.startsWith("http")) entryPoint = baseUrl + entryPoint; classData["@entryPoint"] = entryPoint; entities[entityName] = classData; }); const instance = new JSONLD(baseUrl, entities); JSONLD.instances[apiUrl] = instance; // return the initialized JSONLD object if (JSONLD.successFunctions[apiUrl] !== undefined) { for (const fnc of JSONLD.successFunctions[apiUrl]) { if (typeof fnc == 'function') { fnc(instance); } } } JSONLD.successFunctions[apiUrl] = []; } /** * Execute failure functions and send general notification * * @param apiUrl * @param message */ static _executeFailureFunctions(apiUrl, message = "") { const i18n = JSONLD._i18n; if (JSONLD.failureFunctions[apiUrl] !== undefined) { for (const fnc of JSONLD.failureFunctions[apiUrl]) { if (typeof fnc == 'function') { fnc(new Error(message)); } } } JSONLD.failureFunctions[apiUrl] = []; if (message !== "") { notify({ "summary": i18n.t('error.summary'), "body": message, "type": "danger", }); } } getEntityForIdentifier(identifier) { let entityName = this.getEntityNameForIdentifier(identifier); return this.getEntityForEntityName(entityName); } getEntityForEntityName(entityName) { return this.entities[entityName]; } getApiUrlForIdentifier(identifier) { const entity = this.getEntityForIdentifier(identifier); if (entity === undefined || entity["@entryPoint"] === undefined) { throw new Error(`Entity with identifier "${identifier}" not found!`); } return entity["@entryPoint"]; } getApiUrlForEntityName(entityName) { const entity = this.getEntityForEntityName(entityName); if (entity === undefined || entity["@entryPoint"] === undefined) { throw new Error(`Entity "${entityName}" not found!`); } return entity["@entryPoint"]; } getEntityNameForIdentifier(identifier) { return this.idToEntityNameMatchList[identifier]; } getApiIdentifierList() { let keys = []; for (const property in this.idToEntityNameMatchList) { keys.push(property); } return keys; } /** * Expands a member of a list to a object with schema.org properties * * @param member * @param [context] */ expandMember(member, context) { if (context === undefined) { context = member["@context"]; } let result = {"@id": member["@id"]}; for (const key of Object.keys(context)) { const value = context[key]; if (member[key] !== undefined) result[value] = member[key]; } return result; } /** * Compacts an expanded member of a list to a object with local properties * * @param member * @param localContext */ compactMember(member, localContext) { let result = {}; for (const property in localContext) { const value = member[localContext[property]]; if (value !== undefined) { result[property] = value; } } return result; } /** * Transforms hydra members to a local context * * @param data * @param localContext * @returns {Array} An array of transformed objects */ transformMembers(data, localContext) { const members = data['hydra:member']; if (members === undefined || members.length === 0) { return []; } const otherContext = data['@context']; let results = []; let that = this; members.forEach(function (member) { results.push(that.compactMember(that.expandMember(member, otherContext), localContext)); }); return results; } } JSONLD._i18n = createInstance(); JSONLD.instances = {}; JSONLD.successFunctions = {}; JSONLD.failureFunctions = {}; JSONLD.initStarted = {}; JSONLD.promises = {};