Commit 478e0d3e authored by Lauri Himanen's avatar Lauri Himanen
Browse files

Simplified KeyCloak authentication, enabled the error reporting tab in GUI.

parent a8382fd0
Pipeline #79143 skipped with stage
......@@ -166,7 +166,7 @@ eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apac
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n\n /*\n This file implements the app Routing system: the feature that allows\n the page navigation in a single-page environment.\n */\n\n\n\n\nlet routes = new Map();\n\n\nfunction add(route, func){\n routes.set(route, func);\n}\n\n\nwindow.addEventListener(\"hashchange\", route);\n\nfunction route() {\n let hashPath = document.location.hash.substring(2);\n let command, param, subparam;\n\n // Remove the ending /\n if (hashPath.lastIndexOf('/') === (hashPath.length-1))\n hashPath = hashPath.substring(0,hashPath.length-1);\n\n // Remove state parameters from authentication\n let stateIndex = hashPath.indexOf('&state');\n if (stateIndex != -1) {\n hashPath = hashPath.substring(0, stateIndex);\n }\n\n if (hashPath.indexOf('/') > 0){\n let a= hashPath.split('/');\n command= a[0];\n param= a[1];\n subparam= a[2];\n }\n else command = hashPath;\n\n if (routes.has(command)) {\n routes.get(command)(param, subparam);\n }\n};\n\n\nfunction print(){\n console.log('Router data: ');\n routes.forEach(function(func, url) {\n console.log(url + ': ' + func);\n });\n}\n\n\n// EXPORTS\nmodule.exports = { add: add, route: route };\n\n\n//# sourceURL=webpack:///./src/common/Router.js?");
eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n\n /*\n This file implements the app Routing system: the feature that allows\n the page navigation in a single-page environment.\n */\n\n\n\n\nlet routes = new Map();\n\n\nfunction add(route, func){\n routes.set(route, func);\n}\n\n\nwindow.addEventListener(\"hashchange\", route);\n\nfunction route() {\n let hashPath = document.location.hash.substring(2);\n let command, param, subparam;\n\n // Remove the ending /\n if (hashPath.lastIndexOf('/') === (hashPath.length-1))\n hashPath = hashPath.substring(0,hashPath.length-1);\n\n if (hashPath.indexOf('/') > 0){\n let a= hashPath.split('/');\n command= a[0];\n param= a[1];\n subparam= a[2];\n }\n else command = hashPath;\n\n if (routes.has(command)) {\n routes.get(command)(param, subparam);\n }\n};\n\n\nfunction print(){\n console.log('Router data: ');\n routes.forEach(function(func, url) {\n console.log(url + ': ' + func);\n });\n}\n\n\n// EXPORTS\nmodule.exports = { add: add, route: route };\n\n\n//# sourceURL=webpack:///./src/common/Router.js?");
/***/ }),
......@@ -213,7 +213,7 @@ eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apac
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n\n /*\n This is an app-level utility JavaScript file. It holds:\n\n - Environments conf (API URL and user cookie domain configuration)\n * Maybe this conf info can be removed from here to a better place\n - global state variables and app-level constants\n - miscellaneous app-level function\n - local vars\n - app-level util functions\n\n * Maybe this file should be rethought\n */\n\n\n\n\n// global state vars\nlet materialId = null;\nlet searchResults = false;\n\n\n// app-level constants\n\nconst IMAGE_DIR = 'img/';\n\nconst AUTH_REQUEST_HEADER_GUEST_USER = 'Basic '+ btoa(window.nomadEnv.guestUserToken+':');\n\nconst MAT_VIEW = {\n 'structure' : 'structure',\n 'electronicstruct': 'electronicstruct',\n 'methodology': 'methodology',\n 'thermalprops': 'thermalprops',\n 'elasticconst': 'elasticconst'\n};\n\nlet ELEMENTS = [\n 'H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', // Si = 14\n 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', // Nin = 28\n 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', // Nb = 41\n 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', // Xe = 54\n 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', // Ho= 67\n 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', // Hg = 80\n 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', // Np = 93\n 'Pu', 'Am', 'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', 'Rf', 'Ha', 'Sg', // sg = 106\n 'Ns', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', 'Nh', 'Fl', 'Mc', 'Lv', 'Ts', 'Og' // Mt = 109\n];\n\n// API URL and user cookie domain configuration\nconst API_BASE_URL = window.nomadEnv.apiRoot;\n\n// Mockup URLs\n//const FERMI_SURFACE_URL= HOST+'files/fermi/'+\n//'fed3fa9fbc68aa6c5e51845396889666ca37bb2e626e1da53.x3d';\n\n// Local variables\n\nlet authRequestHeaderValue = AUTH_REQUEST_HEADER_GUEST_USER;\n//console.log('user: ANONYMOUS authRequestHeader: ',authRequestHeaderValue);\nlet userData = null;\n\n\n// app-level util functions\n\n// Groups calculations by their functional.\nfunction getCalcMapByFunctional(summaryCalcSet) {\n let functCalcMap = new Map();\n summaryCalcSet.forEach(calc => {\n if (functCalcMap.has(calc.functional_type)) {\n functCalcMap.get(calc.functional_type).add(calc.calc_id);\n\n } else { // New functional, not build if value is unavailable\n if (calc.functional_type !== \"unavailable\") {\n let newFunctionalArray = new Set();\n newFunctionalArray.add(calc.calc_id);\n functCalcMap.set(calc.functional_type, newFunctionalArray);\n }\n }\n });\n return functCalcMap;\n}\n\nfunction getUserData(){\n return userData;\n}\n\n\nfunction getServerLocation(){\n return document.location.hostname;\n}\n\n\nfunction authServerReq(url, callback){\n var oReq = new XMLHttpRequest();\n oReq.addEventListener(\"load\", callback);\n console.log('util.authServerReq: ', API_BASE_URL+url);\n oReq.open(\"GET\", API_BASE_URL+url);\n //console.log('util.authServerReq oReq: ', oReq);\n oReq.send();\n return oReq;\n}\n\n/**\n * Used to create shortened codes from the full 28 character hash string.\n */\nfunction getShortCode(id) {\n if (id.startsWith(\"eos/\") || id.startsWith(\"par/\")) {\n if (id.length == 32) {\n return id.substring(0, 12);\n }\n }\n if (id.length == 28) {\n return id.substring(0, 8);\n }\n throw \"The given identifier could not be shortened as it does not have the right initial length.\";\n}\n\nfunction setAuthRequestHeader(userDataP, value){\n\n if (value === undefined){// default value\n authRequestHeaderValue = AUTH_REQUEST_HEADER_GUEST_USER;\n userData = null;\n //console.log('user: ANONYMOUS authRequestHeader: ',authRequestHeaderValue);\n } else{\n authRequestHeaderValue = 'Basic '+ btoa(value+':');\n userData = userDataP;\n //console.log('user',user,'authRequestHeader: ',authRequestHeaderValue);\n }\n}\n\n\nfunction serverReq(url, callback){\n var oReq = new XMLHttpRequest();\n oReq.addEventListener(\"load\", callback);\n oReq.open(\"GET\", url);\n //console.log('authRequestHeaderValue: ',authRequestHeaderValue);\n oReq.setRequestHeader('Authorization', authRequestHeaderValue);\n oReq.send();\n return oReq;\n}\n\n\nfunction serverReqPOST(url, data, callback){\n var oReq = new XMLHttpRequest();\n oReq.addEventListener('load', callback);\n oReq.open('POST', url);\n oReq.setRequestHeader('Content-Type', 'application/json');\n //console.log('authRequestHeaderValue: ',authRequestHeaderValue);\n oReq.setRequestHeader('Authorization', authRequestHeaderValue);\n oReq.send(data);\n return oReq;\n}\n\n\nfunction getSubscriptedFormula(formula){\n let finalFormula= ''; // 'elementCode' : number\n for (let i = 0; i < formula.length; i++){\n if (formula.charCodeAt(i) >= 47 && formula.charCodeAt(i) < 58 )\n finalFormula += '<sub>'+formula[i]+'</sub>';\n else finalFormula += formula[i];\n //console.log(formula.charCodeAt(i) + \" \"+finalFormula);\n }\n return finalFormula;\n}\n\n\nfunction getSearchURL(){\n return API_BASE_URL+'materials';\n}\n\nfunction getSuggestionURL(quantity){\n return API_BASE_URL+'suggestions?property='+quantity;\n}\n\nfunction getMaterialURL(matId) {\n return API_BASE_URL+'materials/'+matId;//'/materials/matid'; //\n}\n\nfunction getMaterialGroupURL(matId, groupType, groupId){\n return API_BASE_URL + \"materials/\" + matId + \"/groups/\" + groupType + \"/\" + groupId;\n}\n\nfunction getMaterialCalcURL(matId, calcId, property = ''){\n let propertyString = (property === '' ? '' : '?property='+property);\n return API_BASE_URL+'materials/'+matId+'/calculations/'+calcId+propertyString;\n}\n\nfunction getMaterialStatsURL(matId){\n return API_BASE_URL+'materials/'+matId+'/statistics';\n}\n\nfunction getMaterialXsURL(what, matId) {\n return API_BASE_URL+'materials/'+matId+'/'+what;\n}\n\nfunction getCalcEnergiesURL(matId,calcId){\n return API_BASE_URL+'materials/'+matId+'/calculations/'+calcId+'/energies';//'/materials/calculations';//\n}\n\nfunction getFlaggingURL(){\n return API_BASE_URL+'flagme';\n}\n\n\n// Launch an app event\nfunction setBrowserHashPath(modulePath, finalPath){\n if (typeof finalPath === 'undefined') document.location= '#/'+modulePath;\n else document.location= '#/'+modulePath+'/'+finalPath;\n}\n\nfunction loadLib(url){\n let script = document.createElement('script');\n script.setAttribute('type', 'text/javascript');\n script.setAttribute('src', url);\n document.getElementsByTagName('head')[0].appendChild(script);\n}\n\nfunction getNumberArray(string){\n let sArray= string.substring(1,string.length-1).split(',');\n let fArray= [];\n for (var i = 0; i < sArray.length; i++) {\n fArray.push(parseFloat(sArray[i]));\n }\n //console.log('getNumberArray.SPLIT: '+fArray);\n return fArray;\n}\n\n/**\n * Used to convert a 2D array to another scale with the given factor.\n */\nfunction convert2d(data, factor) {\n let converted = [];\n for (var i = 0; i < data.length; i++) {\n let row = data[i];\n let row_converted = [];\n for (var j = 0; j < row.length; j++) {\n row_converted.push(row[j] * factor);\n }\n converted.push(row_converted);\n }\n\n return converted;\n}\n\nfunction J2eV(energy, decimals){\n let result= energy/1.602176565e-19;\n if (decimals === undefined){\n if (result < 0.01) return result.toFixed(6);\n else return result.toFixed(3);\n }else{\n return result.toFixed(decimals);\n }\n}\n\nfunction eV2J(energy){\n return energy*1.602176565e-19;\n}\n\n\n/*\nfunction getBandGapStatsValue(calcs){\n let bandGapSum= 0;\n let bandArray= [];\n let bandGapDirect= calcs[0].band_gap_direct;\n let bandGapType= (bandGapDirect ? \"direct\" : \"indirect\");\n\n for (var i = 0; i < calcs.length; i++) {\n //if (calcs[i].band_gap > 0){\n bandGapSum+= calcs[i].band_gap;\n bandArray.push(calcs[i].band_gap);\n if (calcs[i].band_gap_direct !== bandGapDirect)\n bandGapType= 'various results';\n //}\n //console.log(bandGapSum+' '+calcs[i].band_gap+' '+bandArray.length);\n }\n\n let html= '';//let html= ((bandGapSum / bandArray.length)/1.602176565e-19).toFixed(3)+' eV ('+bandGapType+')';;\n let min= (Math.min.apply(null, bandArray)/1.602176565e-19).toFixed(3);\n let max= (Math.max.apply(null, bandArray)/1.602176565e-19).toFixed(3);\n html+= '&nbsp;('+min+' ... '+max+' eV)';\n //html+= '&nbsp;&nbsp;&nbsp;['+bandArray.length+' / '+calcs.length+']';\n\n return html;\n}*/\n\nfunction m2Angstrom(dist){\n return (dist/1e-10).toFixed(3)+' &#197;';\n}\n\n\nfunction getLatticeAnglesValues(calcs, twoD, bulk){\n let lattParams= [0.0, 0.0, 0.0];\n calcs.forEach( (calc) => {\n if (calc.lattice_parameters !== undefined && calc.lattice_parameters !== null){\n let tempLattParams= getNumberArray(calc.lattice_parameters);\n lattParams[0] += tempLattParams[3];\n lattParams[1] += tempLattParams[4];\n lattParams[2] += tempLattParams[5];\n }\n });\n\n if (bulk)\n return `<div>&alpha; = ${rad2degree(lattParams[0] / calcs.size)}</div>\n <div>&beta; = ${rad2degree(lattParams[1] / calcs.size)}</div>\n <div>&gamma; = ${rad2degree(lattParams[2] / calcs.size)}</div>`;\n else if (twoD)\n return `<div>&alpha; = ${rad2degree(lattParams[0] / calcs.size)}</div>`;\n else return ''; // 1D\n}\n\n\nfunction rad2degree(angle){\n return (angle * (180 / Math.PI)).toFixed(0)+'&deg;';\n}\n\nfunction m3ToAngstrom3(vol){\n return (vol/1e-30).toFixed(3)+' &#197;<sup>3</sup>';\n}\n\n\nfunction getAverage(array){\n let sum = 0;\n for (var i = 0; i < array.length; i++) sum += array[i];\n return sum/array.length;\n}\n\n\n//function getQuantityStatsMap(calcs) {\n\n //// Determine which statistics to build based on system type\n //let quantities;\n //let materialType = \"\";\n //let labelMap = {\n //volume: 'Volume (ų)',\n //atomic_density: 'Atomic density (Å⁻³)',\n //mass_density: 'Mass density (kg/m³)',\n //lattice_a: 'a (Å)',\n //lattice_b: 'b (Å)',\n //lattice_c: 'c (Å)'\n //};\n //if (materialType == \"bulk\") {\n //quantities = ['volume', 'atomic_density', 'mass_density', 'lattice_a', 'lattice_b', 'lattice_c'];\n //} else {\n //quantities = ['lattice_a', 'lattice_b', 'lattice_c'];\n //}\n //let quantitiesMap = new Map();\n\n //// Request quantity statistics from the server. The statistics are calculated\n //// on the server to keep the GUI responsive in case of large number of\n //// calculations.\n //let matId = DataStore.getMaterialData().material_id;\n //let query = JSON.stringify({calculations: calcs});\n //serverReqPOST(getMaterialStatsURL(matId), query, e3 => {\n //let results = JSON.parse(e3.target.response);\n //});\n\n //return quantitiesMap;\n//}\n\n\nfunction toAngstromMinus3(density){\n return (density*1e-30).toFixed(3)+' &#197;<sup>-3</sup>';\n}\n\n\nfunction getMaterialTitle(data, html){\n let title;\n title = getSubscriptedFormula(data.formula_reduced);\n if (html !== undefined && html ===false) title = data.formula_reduced;\n\n if (data.space_group_number !== null && data.space_group_number !== undefined)\n title += ' - space group '+data.space_group_number;\n //return '<span style=\"font-size: 0.9em\">'+title+' </span>';\n return title;\n}\n\nfunction getMinMaxHTML(calcs,prop){\n let propArray= [];\n\n calcs.forEach( (calc) => {\n propArray.push(calc[prop]);\n });\n\n return '('+Math.min.apply(null, propArray)+' ... '+Math.max.apply(null, propArray)+')';\n}\n\n\nfunction generateDiagramSteps(maxVal, d=4){\n\n let exp = -Math.floor(Math.log(maxVal/d) * Math.LOG10E);\n\n let factor = Math.pow(10,exp);//100;\n //console.log('util.generateDiagramSteps ',exp, maxVal/d, factor);\n let ceil = Math.ceil(maxVal*factor/d);\n let stepArray = [];\n for (var i = 0; i <= d; i++) {\n stepArray[i] = ceil*i/factor;\n }\n //console.log('stepArray '+stepArray);\n exp = (exp < 0 ? 0 : exp);\n return [stepArray, exp];\n}\n\nfunction getDefault(value, fallback=\"unavailable\") {\n if (value === undefined || value === null) {\n return fallback;\n }\n return value;\n}\n\n/*\nfunction addBandGapData(calcJson, bsData){\n if (calcJson.band_gap > 0) {\n bsData.bandGapData = {};\n bsData.bandGapData.cbmEnergy = calcJson.band_gap_lower_energy;\n bsData.bandGapData.cbmKpt = getNumberArray(calcJson.band_gap_lower_kpt);\n bsData.bandGapData.vbmEnergy = calcJson.band_gap_upper_energy;\n bsData.bandGapData.vbmKpt = getNumberArray(calcJson.band_gap_upper_kpt);\n }\n}*/\n\nmodule.exports = {\n searchResults,\n materialId,\n MAT_VIEW: MAT_VIEW,\n IMAGE_DIR: IMAGE_DIR,\n ELEMENTS: ELEMENTS,\n setAuthRequestHeader,\n getUserData,\n getServerLocation,\n authServerReq,\n serverReq,\n convert2d,\n serverReqPOST,\n getShortCode,\n getSearchURL: getSearchURL,\n getSuggestionURL,\n getMaterialURL: getMaterialURL,\n getMaterialCalcURL: getMaterialCalcURL,\n getMaterialGroupURL: getMaterialGroupURL,\n getMaterialStatsURL: getMaterialStatsURL,\n getMaterialXsURL: getMaterialXsURL,\n getCalcEnergiesURL: getCalcEnergiesURL,\n getFlaggingURL,\n setBrowserHashPath: setBrowserHashPath,\n loadLib: loadLib,\n getNumberArray: getNumberArray,\n //FERMI_SURFACE_URL: FERMI_SURFACE_URL,\n J2eV: J2eV,\n eV2J,\n //getBandGapStatsValue: getBandGapStatsValue,\n m2Angstrom: m2Angstrom,\n getLatticeAnglesValues: getLatticeAnglesValues,\n rad2degree: rad2degree,\n m3ToAngstrom3: m3ToAngstrom3,\n toAngstromMinus3,\n getMaterialTitle,\n getMinMaxHTML: getMinMaxHTML,\n getSubscriptedFormula: getSubscriptedFormula,\n getAverage,\n generateDiagramSteps,\n getCalcMapByFunctional,\n getDefault,\n //is2DSystem_temporary_patch\n //addBandGapData\n};\n\n\n//# sourceURL=webpack:///./src/common/util.js?");
eval("/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n\n /*\n This is an app-level utility JavaScript file. It holds:\n\n - Environments conf (API URL and user cookie domain configuration)\n * Maybe this conf info can be removed from here to a better place\n - global state variables and app-level constants\n - miscellaneous app-level function\n - local vars\n - app-level util functions\n\n * Maybe this file should be rethought\n */\n\n\n\n\n// global state vars\nlet materialId = null;\nlet searchResults = false;\n\n\n// app-level constants\n\nconst IMAGE_DIR = 'img/';\n\nconst AUTH_REQUEST_HEADER_GUEST_USER = 'Basic '+ btoa(window.nomadEnv.guestUserToken+':');\n\nconst MAT_VIEW = {\n 'structure' : 'structure',\n 'electronicstruct': 'electronicstruct',\n 'methodology': 'methodology',\n 'thermalprops': 'thermalprops',\n 'elasticconst': 'elasticconst'\n};\n\nlet ELEMENTS = [\n 'H', 'He', 'Li', 'Be', 'B', 'C', 'N', 'O', 'F', 'Ne', 'Na', 'Mg', 'Al', 'Si', // Si = 14\n 'P', 'S', 'Cl', 'Ar', 'K', 'Ca', 'Sc', 'Ti', 'V', 'Cr', 'Mn', 'Fe', 'Co', 'Ni', // Nin = 28\n 'Cu', 'Zn', 'Ga', 'Ge', 'As', 'Se', 'Br', 'Kr', 'Rb', 'Sr', 'Y', 'Zr', 'Nb', // Nb = 41\n 'Mo', 'Tc', 'Ru', 'Rh', 'Pd', 'Ag', 'Cd', 'In', 'Sn', 'Sb', 'Te', 'I', 'Xe', // Xe = 54\n 'Cs', 'Ba', 'La', 'Ce', 'Pr', 'Nd', 'Pm', 'Sm', 'Eu', 'Gd', 'Tb', 'Dy', 'Ho', // Ho= 67\n 'Er', 'Tm', 'Yb', 'Lu', 'Hf', 'Ta', 'W', 'Re', 'Os', 'Ir', 'Pt', 'Au', 'Hg', // Hg = 80\n 'Tl', 'Pb', 'Bi', 'Po', 'At', 'Rn', 'Fr', 'Ra', 'Ac', 'Th', 'Pa', 'U', 'Np', // Np = 93\n 'Pu', 'Am', 'Cm', 'Bk', 'Cf', 'Es', 'Fm', 'Md', 'No', 'Lr', 'Rf', 'Ha', 'Sg', // sg = 106\n 'Ns', 'Hs', 'Mt', 'Ds', 'Rg', 'Cn', 'Nh', 'Fl', 'Mc', 'Lv', 'Ts', 'Og' // Mt = 109\n];\n\n// API URL and user cookie domain configuration\nconst API_BASE_URL = window.nomadEnv.apiRoot;\n\n// Mockup URLs\n//const FERMI_SURFACE_URL= HOST+'files/fermi/'+\n//'fed3fa9fbc68aa6c5e51845396889666ca37bb2e626e1da53.x3d';\n\n// Local variables\n\nlet authRequestHeaderValue = AUTH_REQUEST_HEADER_GUEST_USER;\n//console.log('user: ANONYMOUS authRequestHeader: ',authRequestHeaderValue);\nlet userData = null;\n\n\n// app-level util functions\n\n// Groups calculations by their functional.\nfunction getCalcMapByFunctional(summaryCalcSet) {\n let functCalcMap = new Map();\n summaryCalcSet.forEach(calc => {\n if (functCalcMap.has(calc.functional_type)) {\n functCalcMap.get(calc.functional_type).add(calc.calc_id);\n\n } else { // New functional\n let newFunctionalArray = new Set();\n newFunctionalArray.add(calc.calc_id);\n functCalcMap.set(calc.functional_type, newFunctionalArray);\n }\n });\n return functCalcMap;\n}\n\nfunction getUserData(){\n return userData;\n}\n\n\nfunction getServerLocation(){\n return document.location.hostname;\n}\n\n\nfunction authServerReq(url, callback){\n var oReq = new XMLHttpRequest();\n oReq.addEventListener(\"load\", callback);\n console.log('util.authServerReq: ', API_BASE_URL+url);\n oReq.open(\"GET\", API_BASE_URL+url);\n //console.log('util.authServerReq oReq: ', oReq);\n oReq.send();\n return oReq;\n}\n\n/**\n * Used to create shortened codes from the full 28 character hash string.\n */\nfunction getShortCode(id) {\n if (id.startsWith(\"eos/\") || id.startsWith(\"par/\")) {\n if (id.length == 32) {\n return id.substring(0, 12);\n }\n }\n if (id.length == 28) {\n return id.substring(0, 8);\n }\n throw \"The given identifier could not be shortened as it does not have the right initial length.\";\n}\n\nfunction setAuthRequestHeader(userDataP, value){\n\n if (value === undefined){// default value\n authRequestHeaderValue = AUTH_REQUEST_HEADER_GUEST_USER;\n userData = null;\n //console.log('user: ANONYMOUS authRequestHeader: ',authRequestHeaderValue);\n } else{\n authRequestHeaderValue = 'Basic '+ btoa(value+':');\n userData = userDataP;\n //console.log('user',user,'authRequestHeader: ',authRequestHeaderValue);\n }\n}\n\n\nfunction serverReq(url, callback){\n var oReq = new XMLHttpRequest();\n oReq.addEventListener(\"load\", callback);\n oReq.open(\"GET\", url);\n //console.log('authRequestHeaderValue: ',authRequestHeaderValue);\n oReq.setRequestHeader('Authorization', authRequestHeaderValue);\n oReq.send();\n return oReq;\n}\n\n\nfunction serverReqPOST(url, data, callback){\n var oReq = new XMLHttpRequest();\n oReq.addEventListener('load', callback);\n oReq.open('POST', url);\n oReq.setRequestHeader('Content-Type', 'application/json');\n //console.log('authRequestHeaderValue: ',authRequestHeaderValue);\n oReq.setRequestHeader('Authorization', authRequestHeaderValue);\n oReq.send(data);\n return oReq;\n}\n\n\nfunction getSubscriptedFormula(formula){\n let finalFormula= ''; // 'elementCode' : number\n for (let i = 0; i < formula.length; i++){\n if (formula.charCodeAt(i) >= 47 && formula.charCodeAt(i) < 58 )\n finalFormula += '<sub>'+formula[i]+'</sub>';\n else finalFormula += formula[i];\n //console.log(formula.charCodeAt(i) + \" \"+finalFormula);\n }\n return finalFormula;\n}\n\n\nfunction getSearchURL(){\n return API_BASE_URL+'materials';\n}\n\nfunction getSuggestionURL(quantity){\n return API_BASE_URL+'suggestions?property='+quantity;\n}\n\nfunction getMaterialURL(matId) {\n return API_BASE_URL+'materials/'+matId;//'/materials/matid'; //\n}\n\nfunction getMaterialGroupURL(matId, groupType, groupId){\n return API_BASE_URL + \"materials/\" + matId + \"/groups/\" + groupType + \"/\" + groupId;\n}\n\nfunction getMaterialCalcURL(matId, calcId, property = ''){\n let propertyString = (property === '' ? '' : '?property='+property);\n return API_BASE_URL+'materials/'+matId+'/calculations/'+calcId+propertyString;\n}\n\nfunction getMaterialStatsURL(matId){\n return API_BASE_URL+'materials/'+matId+'/statistics';\n}\n\nfunction getMaterialXsURL(what, matId) {\n return API_BASE_URL+'materials/'+matId+'/'+what;\n}\n\nfunction getCalcEnergiesURL(matId,calcId){\n return API_BASE_URL+'materials/'+matId+'/calculations/'+calcId+'/energies';//'/materials/calculations';//\n}\n\nfunction getFlaggingURL(){\n return API_BASE_URL+'flagme';\n}\n\n\n// Launch an app event\nfunction setBrowserHashPath(modulePath, finalPath){\n if (typeof finalPath === 'undefined') document.location= '#/'+modulePath;\n else document.location= '#/'+modulePath+'/'+finalPath;\n}\n\nfunction loadLib(url){\n let script = document.createElement('script');\n script.setAttribute('type', 'text/javascript');\n script.setAttribute('src', url);\n document.getElementsByTagName('head')[0].appendChild(script);\n}\n\nfunction getNumberArray(string){\n let sArray= string.substring(1,string.length-1).split(',');\n let fArray= [];\n for (var i = 0; i < sArray.length; i++) {\n fArray.push(parseFloat(sArray[i]));\n }\n //console.log('getNumberArray.SPLIT: '+fArray);\n return fArray;\n}\n\n/**\n * Used to convert a 2D array to another scale with the given factor.\n */\nfunction convert2d(data, factor) {\n let converted = [];\n for (var i = 0; i < data.length; i++) {\n let row = data[i];\n let row_converted = [];\n for (var j = 0; j < row.length; j++) {\n row_converted.push(row[j] * factor);\n }\n converted.push(row_converted);\n }\n\n return converted;\n}\n\nfunction J2eV(energy, decimals){\n let result= energy/1.602176565e-19;\n if (decimals === undefined){\n if (result < 0.01) return result.toFixed(6);\n else return result.toFixed(3);\n }else{\n return result.toFixed(decimals);\n }\n}\n\nfunction eV2J(energy){\n return energy*1.602176565e-19;\n}\n\n\n/*\nfunction getBandGapStatsValue(calcs){\n let bandGapSum= 0;\n let bandArray= [];\n let bandGapDirect= calcs[0].band_gap_direct;\n let bandGapType= (bandGapDirect ? \"direct\" : \"indirect\");\n\n for (var i = 0; i < calcs.length; i++) {\n //if (calcs[i].band_gap > 0){\n bandGapSum+= calcs[i].band_gap;\n bandArray.push(calcs[i].band_gap);\n if (calcs[i].band_gap_direct !== bandGapDirect)\n bandGapType= 'various results';\n //}\n //console.log(bandGapSum+' '+calcs[i].band_gap+' '+bandArray.length);\n }\n\n let html= '';//let html= ((bandGapSum / bandArray.length)/1.602176565e-19).toFixed(3)+' eV ('+bandGapType+')';;\n let min= (Math.min.apply(null, bandArray)/1.602176565e-19).toFixed(3);\n let max= (Math.max.apply(null, bandArray)/1.602176565e-19).toFixed(3);\n html+= '&nbsp;('+min+' ... '+max+' eV)';\n //html+= '&nbsp;&nbsp;&nbsp;['+bandArray.length+' / '+calcs.length+']';\n\n return html;\n}*/\n\nfunction m2Angstrom(dist){\n return (dist/1e-10).toFixed(3)+' &#197;';\n}\n\n\nfunction getLatticeAnglesValues(calcs, twoD, bulk){\n let lattParams= [0.0, 0.0, 0.0];\n calcs.forEach( (calc) => {\n if (calc.lattice_parameters !== undefined && calc.lattice_parameters !== null){\n let tempLattParams= getNumberArray(calc.lattice_parameters);\n lattParams[0] += tempLattParams[3];\n lattParams[1] += tempLattParams[4];\n lattParams[2] += tempLattParams[5];\n }\n });\n\n if (bulk)\n return `<div>&alpha; = ${rad2degree(lattParams[0] / calcs.size)}</div>\n <div>&beta; = ${rad2degree(lattParams[1] / calcs.size)}</div>\n <div>&gamma; = ${rad2degree(lattParams[2] / calcs.size)}</div>`;\n else if (twoD)\n return `<div>&alpha; = ${rad2degree(lattParams[0] / calcs.size)}</div>`;\n else return ''; // 1D\n}\n\n\nfunction rad2degree(angle){\n return (angle * (180 / Math.PI)).toFixed(0)+'&deg;';\n}\n\nfunction m3ToAngstrom3(vol){\n return (vol/1e-30).toFixed(3)+' &#197;<sup>3</sup>';\n}\n\n\nfunction getAverage(array){\n let sum = 0;\n for (var i = 0; i < array.length; i++) sum += array[i];\n return sum/array.length;\n}\n\n\n//function getQuantityStatsMap(calcs) {\n\n //// Determine which statistics to build based on system type\n //let quantities;\n //let materialType = \"\";\n //let labelMap = {\n //volume: 'Volume (ų)',\n //atomic_density: 'Atomic density (Å⁻³)',\n //mass_density: 'Mass density (kg/m³)',\n //lattice_a: 'a (Å)',\n //lattice_b: 'b (Å)',\n //lattice_c: 'c (Å)'\n //};\n //if (materialType == \"bulk\") {\n //quantities = ['volume', 'atomic_density', 'mass_density', 'lattice_a', 'lattice_b', 'lattice_c'];\n //} else {\n //quantities = ['lattice_a', 'lattice_b', 'lattice_c'];\n //}\n //let quantitiesMap = new Map();\n\n //// Request quantity statistics from the server. The statistics are calculated\n //// on the server to keep the GUI responsive in case of large number of\n //// calculations.\n //let matId = DataStore.getMaterialData().material_id;\n //let query = JSON.stringify({calculations: calcs});\n //serverReqPOST(getMaterialStatsURL(matId), query, e3 => {\n //let results = JSON.parse(e3.target.response);\n //});\n\n //return quantitiesMap;\n//}\n\n\nfunction toAngstromMinus3(density){\n return (density*1e-30).toFixed(3)+' &#197;<sup>-3</sup>';\n}\n\n\nfunction getMaterialTitle(data, html){\n let title;\n title = getSubscriptedFormula(data.formula_reduced);\n if (html !== undefined && html ===false) title = data.formula_reduced;\n\n if (data.space_group_number !== null && data.space_group_number !== undefined)\n title += ' - space group '+data.space_group_number;\n //return '<span style=\"font-size: 0.9em\">'+title+' </span>';\n return title;\n}\n\nfunction getMinMaxHTML(calcs,prop){\n let propArray= [];\n\n calcs.forEach( (calc) => {\n propArray.push(calc[prop]);\n });\n\n return '('+Math.min.apply(null, propArray)+' ... '+Math.max.apply(null, propArray)+')';\n}\n\n\nfunction generateDiagramSteps(maxVal, d=4){\n\n let exp = -Math.floor(Math.log(maxVal/d) * Math.LOG10E);\n\n let factor = Math.pow(10,exp);//100;\n //console.log('util.generateDiagramSteps ',exp, maxVal/d, factor);\n let ceil = Math.ceil(maxVal*factor/d);\n let stepArray = [];\n for (var i = 0; i <= d; i++) {\n stepArray[i] = ceil*i/factor;\n }\n //console.log('stepArray '+stepArray);\n exp = (exp < 0 ? 0 : exp);\n return [stepArray, exp];\n}\n\nfunction getDefault(value, fallback=\"unavailable\") {\n if (value === undefined || value === null) {\n return fallback;\n }\n return value;\n}\n\n/*\nfunction addBandGapData(calcJson, bsData){\n if (calcJson.band_gap > 0) {\n bsData.bandGapData = {};\n bsData.bandGapData.cbmEnergy = calcJson.band_gap_lower_energy;\n bsData.bandGapData.cbmKpt = getNumberArray(calcJson.band_gap_lower_kpt);\n bsData.bandGapData.vbmEnergy = calcJson.band_gap_upper_energy;\n bsData.bandGapData.vbmKpt = getNumberArray(calcJson.band_gap_upper_kpt);\n }\n}*/\n\nmodule.exports = {\n searchResults,\n materialId,\n MAT_VIEW: MAT_VIEW,\n IMAGE_DIR: IMAGE_DIR,\n ELEMENTS: ELEMENTS,\n setAuthRequestHeader,\n getUserData,\n getServerLocation,\n authServerReq,\n serverReq,\n convert2d,\n serverReqPOST,\n getShortCode,\n getSearchURL: getSearchURL,\n getSuggestionURL,\n getMaterialURL: getMaterialURL,\n getMaterialCalcURL: getMaterialCalcURL,\n getMaterialGroupURL: getMaterialGroupURL,\n getMaterialStatsURL: getMaterialStatsURL,\n getMaterialXsURL: getMaterialXsURL,\n getCalcEnergiesURL: getCalcEnergiesURL,\n getFlaggingURL,\n setBrowserHashPath: setBrowserHashPath,\n loadLib: loadLib,\n getNumberArray: getNumberArray,\n //FERMI_SURFACE_URL: FERMI_SURFACE_URL,\n J2eV: J2eV,\n eV2J,\n //getBandGapStatsValue: getBandGapStatsValue,\n m2Angstrom: m2Angstrom,\n getLatticeAnglesValues: getLatticeAnglesValues,\n rad2degree: rad2degree,\n m3ToAngstrom3: m3ToAngstrom3,\n toAngstromMinus3,\n getMaterialTitle,\n getMinMaxHTML: getMinMaxHTML,\n getSubscriptedFormula: getSubscriptedFormula,\n getAverage,\n generateDiagramSteps,\n getCalcMapByFunctional,\n getDefault,\n //is2DSystem_temporary_patch\n //addBandGapData\n};\n\n\n//# sourceURL=webpack:///./src/common/util.js?");
/***/ }),
......@@ -225,7 +225,7 @@ eval("/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apache
/***/ (function(module, exports, __webpack_require__) {
"use strict";
eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n\n /*\n This file is the application entry point.\n It defines some app level components (Breadcrumb) and\n initializes several more (app level events, app routing, authentication)\n */\n\n\n\n\nlet util = __webpack_require__(/*! ./common/util.js */ \"./src/common/util.js\");\nlet LoadingPopup = __webpack_require__(/*! ./common/LoadingPopup.js */ \"./src/common/LoadingPopup.js\");\nlet FlaggingFormPopup = __webpack_require__(/*! ./common/FlaggingFormPopup.js */ \"./src/common/FlaggingFormPopup.js\");\nlet PubSub = __webpack_require__(/*! ./common/PubSub.js */ \"./src/common/PubSub.js\");\nlet Router = __webpack_require__(/*! ./common/Router.js */ \"./src/common/Router.js\");\nlet MaterialMod = __webpack_require__(/*! ./material-mod/MaterialMod.js */ \"./src/material-mod/MaterialMod.js\");\nlet SearchModule = __webpack_require__(/*! ./search-mod/SearchMod.js */ \"./src/search-mod/SearchMod.js\");\nlet UserGuidance = __webpack_require__(/*! ./common/UserGuidance.js */ \"./src/common/UserGuidance.js\");\nlet DataStore = __webpack_require__(/*! ./material-mod/DataStore.js */ \"./src/material-mod/DataStore.js\");\n\n\n// main DOM elements\nlet contentElement = document.getElementById('content');\nlet titleElement = document.querySelector('title');\n\n\n\n/********* User flagging side tab ****************/\n\n/* This side vertical tab is hidden initially\n but it has to be set up when the app starts */\n\nlet flaggingTab = document.getElementById('calc-flagging-tab');\nflaggingTab.style.top = (window.innerHeight/2)+'px';\n\nflaggingTab.addEventListener('click',e => {\n FlaggingFormPopup.show(MaterialModule.getCurrentPageStatus());\n});\n\n\n\n/*********** App Breadcrumb component definition ***************/\n\nclass Breadcrumb {\n\n constructor() {\n\n this.element = document.querySelector('#breadcrumb-placeholder');\n this.element.innerHTML = `\n <span class=\"goto-page Search\">Search</span>\n <span class=\"goto-page Results\">&nbsp; > &nbsp; <span>Results</span></span>\n <span class=\"goto-page Overview\">&nbsp; > &nbsp; <span>Overview</span></span>\n <span class=\"Details\">\n &nbsp; > &nbsp;\n <select class=\"details-dropdown\" >\n <option value=\"structure\">Structure</option>\n <option value=\"electronicstruct\">Electronic structure</option>\n <option value=\"methodology\">Methodology</option>\n <option value=\"thermalprops\">Thermal Properties</option>\n <!-- elasticconst-->\n </select>\n </span>\n `;\n this.resultsSel = this.element.querySelector('.Results');\n this.overviewSel = this.element.querySelector('.Overview');\n this.detailsSel = this.element.querySelector('.Details');\n this.detailsDropDown = this.element.querySelector('.details-dropdown');\n\n // Events\n this.element.querySelector('.Search').addEventListener( \"click\", e => {\n util.setBrowserHashPath('search');\n });\n this.resultsSel.addEventListener( \"click\", e => {\n util.setBrowserHashPath('search/results');\n });\n\n this.overviewSel.addEventListener('click', () => {\n util.setBrowserHashPath('material', util.materialId);\n });\n\n this.detailsDropDown.addEventListener('change', e => {\n util.setBrowserHashPath('material',\n DataStore.getMaterialData().material_id+'/'+e.target.value);\n });\n\n let self = this;\n function adjustDropdownOptions() {\n let esOption = self.detailsDropDown.querySelector('option[value=\"electronicstruct\"]');\n if (!DataStore.hasElecStructureData()) self.detailsDropDown.removeChild(esOption);\n\n let thOption = self.detailsDropDown.querySelector('option[value=\"thermalprops\"]');\n if (!DataStore.hasThermalData()) self.detailsDropDown.removeChild(thOption);\n // Remove because we want it's executed once\n self.detailsDropDown.removeEventListener('focus', adjustDropdownOptions);\n }\n\n this.detailsDropDown.addEventListener('focus', adjustDropdownOptions);\n }\n\n\n setState(appModule, param){\n let resultsSetLabel = this.resultsSel.querySelector('span');\n resultsSetLabel.style.fontWeight = 'normal';\n let overviewSelLabel = this.overviewSel.querySelector('span');\n overviewSelLabel.style.fontWeight = 'normal';\n\n if (appModule === 'search'){\n this.overviewSel.style.display = 'none';\n this.detailsSel.style.display = 'none';\n\n if (param === 'results'){\n this.resultsSel.style.display = 'inline';\n this.resultsSel.querySelector('span').style.fontWeight = 'bold';\n this.element.style.visibility = 'visible';\n }else\n this.element.style.visibility = 'hidden';\n\n }else if (appModule === 'material'){\n this.element.style.visibility = 'visible';\n this.resultsSel.style.display = (util.searchResults ? 'inline' : 'none');\n this.overviewSel.style.display = 'inline';\n\n if (param === undefined){ // Overview page\n this.detailsSel.style.display = 'none';\n overviewSelLabel.style.fontWeight = 'bold';\n }else{ // Details page\n this.detailsSel.style.display = 'inline';\n this.detailsDropDown.value = param;\n }\n }\n } // setState\n\n} // class Breadcrumb\n\n\n/***************************\n App setup\n***************************/\n\nlet breadcrumb = new Breadcrumb();\n\nlet searchMod;\nlet MaterialModule;\nlet materialModDOM;\nlet currentModule; // current module DOM being shown\n\n\nfunction showModuleDOM(module){\n if (currentModule) contentElement.removeChild(currentModule);\n currentModule = module;\n contentElement.appendChild(currentModule);\n}\n\n\n/****** App level events setup ********/\n\nPubSub.subscribe('show-material', data => {\n console.log('Handling event show-material: ' + data.material_id + ' view: '+data.view);\n\n //titleElement.innerHTML = 'NOMAD Encyclopedia - Material '+data.id;\n breadcrumb.setState('material', data.view);\n\n if (typeof materialModDOM === 'undefined'){\n MaterialModule = new MaterialMod();\n materialModDOM = MaterialModule.element;\n }\n showModuleDOM(materialModDOM);\n MaterialModule.setMaterialView(data);\n\n // In case the app comes from the search module through the url (back button)\n UserGuidance.show(false);\n\n //console.log('User data:',util.getUserData());\n if (util.getUserData() !== null) flaggingTab.style.visibility = 'visible';\n});\n\n\nPubSub.subscribe('show-search', search => {\n console.log('Handling event show-search: '+search);\n\n titleElement.innerHTML = 'NOMAD Encyclopedia - Search';\n breadcrumb.setState('search',search);\n\n if (search === undefined){\n searchMod.showSearchPage();\n LoadingPopup.hide(); // In case it comes from the result page\n\n }else if (search === 'results')\n searchMod.showResultsPage();\n\n showModuleDOM(searchMod.element);\n\n if (flaggingTab.style.visibility !== 'hidden')\n flaggingTab.style.visibility = 'hidden';\n});\n\n\n/****** App routing config ******/\nRouter.add('search', search => PubSub.publish('show-search', search));\nRouter.add('material', (matId, view) => PubSub.publish('show-material', {'material_id': matId, 'view': view}));\n\n/****** init ******/\nsearchMod = new SearchModule();\nif (document.location.hash === '') document.location += \"#/search\";\nRouter.route();\n\n/********* User authentication ***********/\n\nlet userNameElement = document.querySelector('#user-name');\n\n//function setAppAuthenticated(data){\n //if (data.status === 'Authenticated'){\n //userNameElement.innerHTML = data.user.username;\n //document.querySelector('#guest-user').style.display = 'none';\n //document.querySelector('#auth-user').style.display = 'inline';\n //util.setAuthRequestHeader(data.user, data.token.data);\n //if (currentModule === materialModDOM) flaggingTab.style.visibility = 'visible';\n //}\n//}\n\n\n//function logout(){\n //userNameElement.innerHTML = '';\n //util.setAuthRequestHeader();\n\n //if (flaggingTab.style.visibility !== 'hidden')\n //flaggingTab.style.visibility = 'hidden';\n//}\n\n\nfunction getCookie(name) {\n let value = \"; \" + document.cookie;\n let parts = value.split(\"; \" + name + \"=\");\n if (parts.length === 2) return parts.pop().split(\";\").shift();\n}\n\n\nfunction parseCookie(userData) {\n return userData.substring(1, userData.length-1).replace(/\\\\054/g,',').replace(/\\\\/g,'');\n}\n\n\nlet userInfoCookie = getCookie('user_info');\n\nif (userInfoCookie !== undefined){\n let userInfoData = JSON.parse(parseCookie(userInfoCookie));\n //console.log('userInfoData: ', userInfoData);\n setAppAuthenticated(userInfoData);\n}\n\n\n//# sourceURL=webpack:///./src/main.js?");
eval("\n/**\n * Copyright 2016-2018 Iker Hurtado\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n *\n */\n\n\n /*\n This file is the application entry point.\n It defines some app level components (Breadcrumb) and\n initializes several more (app level events, app routing, authentication)\n */\n\n\n\n\nlet util = __webpack_require__(/*! ./common/util.js */ \"./src/common/util.js\");\nlet LoadingPopup = __webpack_require__(/*! ./common/LoadingPopup.js */ \"./src/common/LoadingPopup.js\");\nlet FlaggingFormPopup = __webpack_require__(/*! ./common/FlaggingFormPopup.js */ \"./src/common/FlaggingFormPopup.js\");\nlet PubSub = __webpack_require__(/*! ./common/PubSub.js */ \"./src/common/PubSub.js\");\nlet Router = __webpack_require__(/*! ./common/Router.js */ \"./src/common/Router.js\");\nlet MaterialMod = __webpack_require__(/*! ./material-mod/MaterialMod.js */ \"./src/material-mod/MaterialMod.js\");\nlet SearchModule = __webpack_require__(/*! ./search-mod/SearchMod.js */ \"./src/search-mod/SearchMod.js\");\nlet UserGuidance = __webpack_require__(/*! ./common/UserGuidance.js */ \"./src/common/UserGuidance.js\");\nlet DataStore = __webpack_require__(/*! ./material-mod/DataStore.js */ \"./src/material-mod/DataStore.js\");\n\n\n// main DOM elements\nlet contentElement = document.getElementById('content');\nlet titleElement = document.querySelector('title');\n\n// As of 0.8.3 nomad-FAIR is using KeyCloak 7.0.0, which does\n// not support the \"silentCheckSsoRedirectUri\" option. This option enables a\n// silent login check that does not enforce reloads. In order to do such silent\n// login, the Javascript adapter for KeyCloak 8.0.0 is used instead. This is\n// against the best practice of directly downloading the Javascript adapter\n// from the authentication server (window.nomadEnv.keycloakBase +\n// \"js/keycloak.min.js\"), but is in this case acceptable as it result is a much\n// smoother user experience.\nPubSub.subscribe('authenticated', data => {\n let hashPath = document.location.hash.substring(2);\n if (hashPath.lastIndexOf('/') === (hashPath.length-1))\n hashPath = hashPath.substring(0,hashPath.length-1);\n if (hashPath.indexOf('/') > 0){\n let command = hashPath.split('/')[0];\n if (command === \"material\") {\n flaggingTab.style.visibility = 'visible';\n }\n }\n});\nvar keycloak = new Keycloak({\n url: window.nomadEnv.keycloakBase,\n realm: window.nomadEnv.keycloakRealm,\n clientId: window.nomadEnv.keycloakClientId\n});\nlet loginButton = document.querySelector('#login-button');\nlet logoutButton = document.querySelector('#logout-button');\nlet userName = document.querySelector('#user-name');\nkeycloak.init({\n onLoad: \"check-sso\",\n silentCheckSsoRedirectUri: `${window.nomadEnv.guiRoot}silent-check-sso.html`,\n promiseType: \"native\",\n}).then((authenticated) => {\n if (authenticated) {\n keycloak.loadUserProfile()\n .then(function(profile) {\n userName.textContent = `${profile.firstName} ${profile.lastName}`;\n loginButton.style.display = 'none';\n logoutButton.style.display = 'inline';\n PubSub.publish('authenticated');\n }).catch(function() {\n console.log('Failed to load user profile.');\n });\n //util.setAuthRequestHeader(data.user, data.token.data);\n } else {\n loginButton.style.display = 'inline';\n logoutButton.style.display = 'none';\n userName.textContent = \"Guest\";\n }\n});\nloginButton.onclick = () => {\n keycloak.login({redirectUri: `${window.nomadEnv.guiRoot}#/search`})\n .catch(() => {console.log(\"Authentication error.\");});\n};\nlogoutButton.onclick = () => {\n keycloak.logout();\n};\n\n\n/********* User flagging side tab ****************/\n\n/* This side vertical tab is hidden initially\n but it has to be set up when the app starts */\nlet flaggingTab = document.getElementById('calc-flagging-tab');\nflaggingTab.style.top = (window.innerHeight/2)+'px';\nflaggingTab.addEventListener('click',e => {\n FlaggingFormPopup.show(MaterialModule.getCurrentPageStatus());\n});\n\n\n\n/*********** App Breadcrumb component definition ***************/\n\nclass Breadcrumb {\n\n constructor() {\n\n this.element = document.querySelector('#breadcrumb-placeholder');\n this.element.innerHTML = `\n <span class=\"goto-page Search\">Search</span>\n <span class=\"goto-page Results\">&nbsp; > &nbsp; <span>Results</span></span>\n <span class=\"goto-page Overview\">&nbsp; > &nbsp; <span>Overview</span></span>\n <span class=\"Details\">\n &nbsp; > &nbsp;\n <select class=\"details-dropdown\" >\n <option value=\"structure\">Structure</option>\n <option value=\"electronicstruct\">Electronic structure</option>\n <option value=\"methodology\">Methodology</option>\n <option value=\"thermalprops\">Thermal Properties</option>\n <!-- elasticconst-->\n </select>\n </span>\n `;\n this.resultsSel = this.element.querySelector('.Results');\n this.overviewSel = this.element.querySelector('.Overview');\n this.detailsSel = this.element.querySelector('.Details');\n this.detailsDropDown = this.element.querySelector('.details-dropdown');\n\n // Events\n this.element.querySelector('.Search').addEventListener( \"click\", e => {\n util.setBrowserHashPath('search');\n });\n this.resultsSel.addEventListener( \"click\", e => {\n util.setBrowserHashPath('search/results');\n });\n\n this.overviewSel.addEventListener('click', () => {\n util.setBrowserHashPath('material', util.materialId);\n });\n\n this.detailsDropDown.addEventListener('change', e => {\n util.setBrowserHashPath('material',\n DataStore.getMaterialData().material_id+'/'+e.target.value);\n });\n\n let self = this;\n function adjustDropdownOptions() {\n let esOption = self.detailsDropDown.querySelector('option[value=\"electronicstruct\"]');\n if (!DataStore.hasElecStructureData()) self.detailsDropDown.removeChild(esOption);\n\n let thOption = self.detailsDropDown.querySelector('option[value=\"thermalprops\"]');\n if (!DataStore.hasThermalData()) self.detailsDropDown.removeChild(thOption);\n // Remove because we want it's executed once\n self.detailsDropDown.removeEventListener('focus', adjustDropdownOptions);\n }\n\n this.detailsDropDown.addEventListener('focus', adjustDropdownOptions);\n }\n\n\n setState(appModule, param){\n let resultsSetLabel = this.resultsSel.querySelector('span');\n resultsSetLabel.style.fontWeight = 'normal';\n let overviewSelLabel = this.overviewSel.querySelector('span');\n overviewSelLabel.style.fontWeight = 'normal';\n\n if (appModule === 'search'){\n this.overviewSel.style.display = 'none';\n this.detailsSel.style.display = 'none';\n\n if (param === 'results'){\n this.resultsSel.style.display = 'inline';\n this.resultsSel.querySelector('span').style.fontWeight = 'bold';\n this.element.style.visibility = 'visible';\n }else\n this.element.style.visibility = 'hidden';\n\n }else if (appModule === 'material'){\n this.element.style.visibility = 'visible';\n this.resultsSel.style.display = (util.searchResults ? 'inline' : 'none');\n this.overviewSel.style.display = 'inline';\n\n if (param === undefined){ // Overview page\n this.detailsSel.style.display = 'none';\n overviewSelLabel.style.fontWeight = 'bold';\n }else{ // Details page\n this.detailsSel.style.display = 'inline';\n this.detailsDropDown.value = param;\n }\n }\n } // setState\n\n} // class Breadcrumb\n\n\n/***************************\n App setup\n***************************/\n\nlet breadcrumb = new Breadcrumb();\n\nlet searchMod;\nlet MaterialModule;\nlet materialModDOM;\nlet currentModule; // current module DOM being shown\n\n\nfunction showModuleDOM(module){\n if (currentModule) contentElement.removeChild(currentModule);\n currentModule = module;\n contentElement.appendChild(currentModule);\n}\n\n\n/****** App level events setup ********/\n\nPubSub.subscribe('show-material', data => {\n console.log('Handling event show-material: ' + data.material_id + ' view: '+data.view);\n\n //titleElement.innerHTML = 'NOMAD Encyclopedia - Material '+data.id;\n breadcrumb.setState('material', data.view);\n\n if (typeof materialModDOM === 'undefined'){\n MaterialModule = new MaterialMod();\n materialModDOM = MaterialModule.element;\n }\n showModuleDOM(materialModDOM);\n MaterialModule.setMaterialView(data);\n\n // In case the app comes from the search module through the url (back button)\n UserGuidance.show(false);\n\n // When a logged user comes to a material page, the error reporting tab is shown.\n if (keycloak.authenticated) {\n flaggingTab.style.visibility = 'visible';\n }\n});\n\nPubSub.subscribe('show-search', search => {\n console.log('Handling event show-search: '+search);\n\n // When a logged user comes to a material page, the error reporting tab is shown.\n flaggingTab.style.visibility = 'hidden';\n\n titleElement.innerHTML = 'NOMAD Encyclopedia - Search';\n breadcrumb.setState('search',search);\n\n if (search === undefined){\n searchMod.showSearchPage();\n LoadingPopup.hide(); // In case it comes from the result page\n\n } else if (search === 'results')\n searchMod.showResultsPage();\n\n showModuleDOM(searchMod.element);\n});\n\n\n/****** App routing config ******/\nRouter.add('search', search => PubSub.publish('show-search', search));\nRouter.add('material', (matId, view) => PubSub.publish('show-material', {'material_id': matId, 'view': view}));\n\n/****** init ******/\nsearchMod = new SearchModule();\nif (document.location.hash === '') document.location += \"#/search\";\nRouter.route();\n\n/********* User authentication ***********/\n\nlet userNameElement = document.querySelector('#user-name');\n\nfunction getCookie(name) {\n let value = \"; \" + document.cookie;\n let parts = value.split(\"; \" + name + \"=\");\n if (parts.length === 2) return parts.pop().split(\";\").shift();\n}\n\nfunction parseCookie(userData) {\n return userData.substring(1, userData.length-1).replace(/\\\\054/g,',').replace(/\\\\/g,'');\n}\n\nlet userInfoCookie = getCookie('user_info');\n\nif (userInfoCookie !== undefined){\n let userInfoData = JSON.parse(parseCookie(userInfoCookie));\n //console.log('userInfoData: ', userInfoData);\n setAppAuthenticated(userInfoData);\n}\n\n\n//# sourceURL=webpack:///./src/main.js?");
/***/ }),
......
......@@ -12,7 +12,6 @@
<script defer src="conf.js"></script>
<script defer src="keycloak.min.js"></script>
<script defer src="loadkeycloak.js"></script>
<script defer src="lib/3d-viewers/three.min.js"></script>
<script defer src="lib/3d-viewers/orthographiccontrols.js"></script>
<script defer src="lib/3d-viewers/matviewer.min.js"></script>
......
// This separate script is used to handle the login procedure before loading
// the application. As of 0.8.3 nomad-FAIR is using KeyCloak 7.0.0, which does
// not support the "silentCheckSsoRedirectUri" option. This option enables a
// silent login check that does not enforce reloads. In order to do such silent
// login, the Javascript adapter for KeyCloak 8.0.0 is used instead. This is
// against the best practice of directly downloading the Javascript adapter
// from the authentication server (window.nomadEnv.keycloakBase +
// "js/keycloak.min.js"), but is in this case acceptable as it result is a much
// smoother user experience.
var keycloak = new Keycloak({
url: window.nomadEnv.keycloakBase,
realm: window.nomadEnv.keycloakRealm,
clientId: window.nomadEnv.keycloakClientId
});
let loginButton = document.querySelector('#login-button');
let logoutButton = document.querySelector('#logout-button');
let userName = document.querySelector('#user-name');
keycloak.init({
onLoad: "check-sso",
silentCheckSsoRedirectUri: `${window.nomadEnv.guiRoot}silent-check-sso.html`,
promiseType: "native",
}).then((authenticated) => {
if (authenticated) {
keycloak.loadUserProfile()
.then(function(profile) {
userName.textContent = `${profile.firstName} ${profile.lastName}`;
loginButton.style.display = 'none';
logoutButton.style.display = 'inline';
}).catch(function() {
console.log('Failed to load user profile.');
});
} else {
loginButton.style.display = 'inline';
logoutButton.style.display = 'none';
userName.textContent = "Guest";
}
});
loginButton.onclick = () => {
keycloak.login({redirectUri: `${window.nomadEnv.guiRoot}#/search`})
.catch(() => {console.log("Authentication error.")})
};
logoutButton.onclick = () => {
keycloak.logout()
};
......@@ -43,12 +43,6 @@ function route() {
if (hashPath.lastIndexOf('/') === (hashPath.length-1))
hashPath = hashPath.substring(0,hashPath.length-1);
// Remove state parameters from authentication
let stateIndex = hashPath.indexOf('&state');
if (stateIndex != -1) {
hashPath = hashPath.substring(0, stateIndex);
}
if (hashPath.indexOf('/') > 0){
let a= hashPath.split('/');
command= a[0];
......
......@@ -86,12 +86,10 @@ function getCalcMapByFunctional(summaryCalcSet) {
if (functCalcMap.has(calc.functional_type)) {
functCalcMap.get(calc.functional_type).add(calc.calc_id);
} else { // New functional, not build if value is unavailable
if (calc.functional_type !== "unavailable") {
let newFunctionalArray = new Set();
newFunctionalArray.add(calc.calc_id);
functCalcMap.set(calc.functional_type, newFunctionalArray);
}
} else { // New functional
let newFunctionalArray = new Set();
newFunctionalArray.add(calc.calc_id);
functCalcMap.set(calc.functional_type, newFunctionalArray);
}
});
return functCalcMap;
......
......@@ -41,16 +41,70 @@ let DataStore = require('./material-mod/DataStore.js');
let contentElement = document.getElementById('content');
let titleElement = document.querySelector('title');
// As of 0.8.3 nomad-FAIR is using KeyCloak 7.0.0, which does
// not support the "silentCheckSsoRedirectUri" option. This option enables a
// silent login check that does not enforce reloads. In order to do such silent
// login, the Javascript adapter for KeyCloak 8.0.0 is used instead. This is
// against the best practice of directly downloading the Javascript adapter
// from the authentication server (window.nomadEnv.keycloakBase +
// "js/keycloak.min.js"), but is in this case acceptable as it result is a much
// smoother user experience.
PubSub.subscribe('authenticated', data => {
let hashPath = document.location.hash.substring(2);
if (hashPath.lastIndexOf('/') === (hashPath.length-1))
hashPath = hashPath.substring(0,hashPath.length-1);
if (hashPath.indexOf('/') > 0){
let command = hashPath.split('/')[0];
if (command === "material") {
flaggingTab.style.visibility = 'visible';
}
}
});
var keycloak = new Keycloak({
url: window.nomadEnv.keycloakBase,
realm: window.nomadEnv.keycloakRealm,
clientId: window.nomadEnv.keycloakClientId
});
let loginButton = document.querySelector('#login-button');
let logoutButton = document.querySelector('#logout-button');
let userName = document.querySelector('#user-name');
keycloak.init({
onLoad: "check-sso",
silentCheckSsoRedirectUri: `${window.nomadEnv.guiRoot}silent-check-sso.html`,
promiseType: "native",
}).then((authenticated) => {
if (authenticated) {
keycloak.loadUserProfile()
.then(function(profile) {
userName.textContent = `${profile.firstName} ${profile.lastName}`;
loginButton.style.display = 'none';
logoutButton.style.display = 'inline';
PubSub.publish('authenticated');
}).catch(function() {
console.log('Failed to load user profile.');
});
//util.setAuthRequestHeader(data.user, data.token.data);
} else {
loginButton.style.display = 'inline';
logoutButton.style.display = 'none';
userName.textContent = "Guest";
}
});
loginButton.onclick = () => {
keycloak.login({redirectUri: `${window.nomadEnv.guiRoot}#/search`})
.catch(() => {console.log("Authentication error.");});
};
logoutButton.onclick = () => {
keycloak.logout();
};
/********* User flagging side tab ****************/
/* This side vertical tab is hidden initially
but it has to be set up when the app starts */
let flaggingTab = document.getElementById('calc-flagging-tab');
flaggingTab.style.top = (window.innerHeight/2)+'px';
flaggingTab.addEventListener('click',e => {
FlaggingFormPopup.show(MaterialModule.getCurrentPageStatus());
});
......@@ -188,14 +242,18 @@ PubSub.subscribe('show-material', data => {
// In case the app comes from the search module through the url (back button)
UserGuidance.show(false);
//console.log('User data:',util.getUserData());
if (util.getUserData() !== null) flaggingTab.style.visibility = 'visible';
// When a logged user comes to a material page, the error reporting tab is shown.
if (keycloak.authenticated) {
flaggingTab.style.visibility = 'visible';
}
});
PubSub.subscribe('show-search', search => {
console.log('Handling event show-search: '+search);
// When a logged user comes to a material page, the error reporting tab is shown.
flaggingTab.style.visibility = 'hidden';
titleElement.innerHTML = 'NOMAD Encyclopedia - Search';
breadcrumb.setState('search',search);
......@@ -203,13 +261,10 @@ PubSub.subscribe('show-search', search => {
searchMod.showSearchPage();
LoadingPopup.hide(); // In case it comes from the result page
}else if (search === 'results')
} else if (search === 'results')
searchMod.showResultsPage();
showModuleDOM(searchMod.element);
if (flaggingTab.style.visibility !== 'hidden')
flaggingTab.style.visibility = 'hidden';
});
......@@ -226,38 +281,16 @@ Router.route();
let userNameElement = document.querySelector('#user-name');
//function setAppAuthenticated(data){
//if (data.status === 'Authenticated'){
//userNameElement.innerHTML = data.user.username;
//document.querySelector('#guest-user').style.display = 'none';
//document.querySelector('#auth-user').style.display = 'inline';
//util.setAuthRequestHeader(data.user, data.token.data);
//if (currentModule === materialModDOM) flaggingTab.style.visibility = 'visible';
//}
//}
//function logout(){
//userNameElement.innerHTML = '';
//util.setAuthRequestHeader();
//if (flaggingTab.style.visibility !== 'hidden')
//flaggingTab.style.visibility = 'hidden';
//}
function getCookie(name) {
let value = "; " + document.cookie;
let parts = value.split("; " + name + "=");
if (parts.length === 2) return parts.pop().split(";").shift();
}
function parseCookie(userData) {
return userData.substring(1, userData.length-1).replace(/\\054/g,',').replace(/\\/g,'');
}
let userInfoCookie = getCookie('user_info');
if (userInfoCookie !== undefined){
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment