Commits (4)
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -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>
......@@ -53,8 +52,8 @@
<div id="logo-header" >
<div "logo-panel">
<a href="https://nomad-lab.eu/" target="_blank">
<img src="img/nomad-logo.png" style="margin-right: 1rem">
The NOMAD Laboratory
<img src="img/nomad-logo.png" /> <!--style="padding-top:10px"-->
</a>
</div>
<div id="spacer"></div>
......
// 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()
};
......@@ -38,6 +38,8 @@ flaggingFormPopup.innerHTML =`
<div class="form-wrapper">
<div class="popup-title"> Error reporting</div>
<br>
<div> Material: <span id="error-material-id"></span></div>
<select id="flagging-category" name="category">
<option value="">Select a category *</option>
<option value="structure">Structure</option>
......@@ -51,7 +53,7 @@ flaggingFormPopup.innerHTML =`
</select>
<textarea id="subject" name="subject" style="height:200px"
placeholder="Write a short explanation about the error detected" ></textarea>
placeholder="Write a short explanation about the error" ></textarea>
<div id="form-validation-msg"> </div>
......@@ -68,9 +70,10 @@ let categoryField = flaggingFormPopup.querySelector('#flagging-category');
let eStructOption = categoryField.querySelector('option[value="electronicstruct"]');
let thermalOption = categoryField.querySelector('option[value="thermalprops"]');
let subcategoryField = flaggingFormPopup.querySelector('#flagging-subcategory');
let closeButton= flaggingFormPopup.querySelector('img');
let closeButton = flaggingFormPopup.querySelector('img');
let validationMsg = flaggingFormPopup.querySelector('#form-validation-msg');
let sendButton= flaggingFormPopup.querySelector('button');
let sendButton = flaggingFormPopup.querySelector('button');
let materialIdField = flaggingFormPopup.querySelector('#error-material-id');
let treeLeaf = null;
let overviewEStructCalcs = null;
......@@ -79,12 +82,14 @@ let overviewEStructCalcs = null;
function _setCurrentPage(pageId){
subcategoryField.innerHTML = '';
let materialId = DataStore.getMaterialData().material_id;
materialIdField.textContent = materialId;
if (pageId === null){
categoryField.disabled = false;
subcategoryField.style.display = 'none';
}else{
} else {
categoryField.disabled = true;
subcategoryField.style.display = 'block';
subcategoryField.appendChild(createOption('Choose the subcategory *', ''));
......@@ -128,7 +133,6 @@ function _setCurrentPage(pageId){
function show(pageStatus){
//console.log('pageStatus : ',pageStatus);
treeLeaf = pageStatus.markedLeaf;
overviewEStructCalcs = pageStatus.eStructCalcs;
......@@ -180,11 +184,11 @@ sendButton.addEventListener('click', e => {
if (!categoryField.disabled && categoryChosen.value === ''){ // Overview case
validationMsg.innerHTML = 'The category fields must be set';
}else if (categoryField.disabled && subcategoryField.value === '' // Detaisl pages case
} else if (categoryField.disabled && subcategoryField.value === '' // Detaisl pages case
&& categoryChosen.value !== util.MAT_VIEW.methodology){
validationMsg.innerHTML = 'The subcategory fields must be set';
}else{
} else {
validationMsg.innerHTML = 'Sending report...';
let textareaText = flaggingFormPopup.querySelector('textarea').value;
let materialId = DataStore.getMaterialData().material_id;
......@@ -205,7 +209,7 @@ sendButton.addEventListener('click', e => {
(overviewEStructCalcs.bs === null ? '' : 'BS calculation '+overviewEStructCalcs.bs)+
(overviewEStructCalcs.dos === null ? '' : ' DOS calculation '+overviewEStructCalcs.dos);
}else{ // Details pages
} else { // Details pages
descriptionText += '\\n\\n**Category:** '+categoryChosen.text;
if (categoryChosen.value !== util.MAT_VIEW.methodology){
......
......@@ -30,6 +30,9 @@ let loadingPopup = document.querySelector('#loading-popup');
let loadSet = new Set();
function show(id) {
if (!window.allowNewLoadPopup) {
return;
}
loadSet.add(id, true);
let ttRect = loadingPopup.getBoundingClientRect();
let leftPos = (window.innerWidth - ttRect.width)/2;
......@@ -46,5 +49,10 @@ function hide(id) {
}
}
function reset() {
loadSet = new Set();
loadingPopup.style.visibility = 'hidden';
}
// EXPORTS
module.exports = { show, hide };
module.exports = {show, hide, reset};
......@@ -25,6 +25,8 @@
"use strict";
let LoadingPopup = require('../common/LoadingPopup.js');
let routes = new Map();
......@@ -35,7 +37,26 @@ function add(route, func){
window.addEventListener("hashchange", route);
var hashHistory = [window.location.hash];
var historyLength = window.history.length;
function route() {
var hash = window.location.hash, length = window.history.length;
if (hashHistory.length && historyLength == length) {
if (hashHistory[hashHistory.length - 2] == hash) {
hashHistory = hashHistory.slice(0, -1);
LoadingPopup.reset();
window.allowNewLoadPopup = false;
} else {
window.allowNewLoadPopup = true;
hashHistory.push(hash);
}
} else {
window.allowNewLoadPopup = true;
hashHistory.push(hash);
historyLength = length;
}
let hashPath = document.location.hash.substring(2);
let command, param, subparam;
......
......@@ -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;
......
......@@ -40,23 +40,77 @@ let DataStore = require('./material-mod/DataStore.js');
// main DOM elements
let contentElement = document.getElementById('content');
let titleElement = document.querySelector('title');
window.allowNewLoadPopup = true;
// 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());
});
/*********** App Breadcrumb component definition ***************/
class Breadcrumb {
......@@ -188,28 +242,29 @@ 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);
breadcrumb.setState('search', search);
if (search === undefined){
if (search === undefined) {
//LoadingPopup.reset();
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){
......
......@@ -31,7 +31,8 @@ let representatives;
let idealizedStructure;
let calcMap = new Map();
let ready = false;
let hasThermal, hasElecStructure;
let hasThermal;
let hasElecStructure;
function setMaterialData(dataFromAPI){
materialData = dataFromAPI;
......@@ -164,7 +165,7 @@ function getGroupLeafId(calcId){
return leafId;
}
function hasThermalData(bool){
function hasThermalData(bool) {
return hasThermal;
}
......@@ -174,7 +175,26 @@ function hasElecStructureData(bool){
// EXPORTS
module.exports = { getRepresentatives, setMaterialData, getMaterialData, getCalculations, getCalc,
setCalculations, getGroups, getGroupId, setGroups, isGroup, getGroupType,
getReprCalc, isInAnyGroup, isInAnyNotDisabledGroup, getGroupLeafId, isReady, clear, setIdealizedStructure, getIdealizedStructure,
hasThermalData, hasElecStructureData};
module.exports = {
getRepresentatives,
setMaterialData,
getMaterialData,
getCalculations,
setCalculations,
getCalc,
getGroups,
setGroups,
getGroupId,
isGroup,
getGroupType,
getReprCalc,
isInAnyGroup,
isInAnyNotDisabledGroup,
getGroupLeafId,
isReady,
clear,
setIdealizedStructure,
getIdealizedStructure,
hasThermalData,
hasElecStructureData
};
......@@ -175,6 +175,7 @@ class MaterialMod {
// If material is already loaded, nothing fetched.
if (!isReady()) {
DataStore.clear();
LoadingPopup.reset();
this.structureViewer.axisCheckbox.checked = true;
this.structureViewer.bondsCheckbox.checked = true;
document.getElementById('methodology-ov').style.visibility = 'hidden';
......
......@@ -509,7 +509,6 @@ class Overview {
document.getElementById('thermal-props-ov').style.display = 'none';
} else {
document.getElementById('thermal-props-ov').style.display = 'block';
DataStore.hasThermalData = true;
if (this.heatPlotter === null){
this.heatPlotter= new HeatCapPlotter();
......
......@@ -133,6 +133,8 @@ class MaterialList {
this.prevButton.style.visibility = "visible";
}
LoadingPopup.reset();
window.allowNewLoadPopup = true;
LoadingPopup.show();
let oReq = util.serverReqPOST(util.getSearchURL(), postQuery, e => {
let data = JSON.parse(e.target.response);
......
......@@ -172,7 +172,7 @@ class SearchMod {
this.mainButton.addEventListener( "click", (e) => {
if (this.searchQuery.lenght === 0){
util.showUserMsg('No query');
}else{
} else {
let queryObj = {};
let elements = [];
queryObj.search_by = {};
......@@ -203,7 +203,7 @@ class SearchMod {
queryObj.search_by.exclusive = (exclusiveEl === null ? '0' : '1');
this.materialList.setSearch(queryObj);
util.setBrowserHashPath('search','results');
util.setBrowserHashPath('search', 'results');
}
});
......@@ -388,15 +388,12 @@ class SearchMod {
this.searchQueryBox.innerHTML= html;
}
showResultsPage(){
this.searchPage.style.display= 'none';
this.resultsPage.style.display= 'block';
showResultsPage() {
this.searchPage.style.display = 'none';
this.resultsPage.style.display = 'block';
if (this.userGuidance) UserGuidance.show(false);
}
showSearchPage(){
this.searchPage.style.display= 'block';
this.resultsPage.style.display= 'none';
......