Commit c401f678 authored by Lauri Himanen's avatar Lauri Himanen
Browse files

Refactored the invalid syntax visuals, added possibility to collapse the...

Refactored the invalid syntax visuals, added possibility to collapse the currently shown tab, restyled the seach filter selected with AutoCompleteMultiselectTextfield, disabled panel fading based on hover, made the filter panel on the left update the search automatically, now the initial view loads all results by default.
parent 196bffa4
Pipeline #97356 skipped with stage
This diff is collapsed.
......@@ -151,7 +151,6 @@
}
#flagging-form-popup button{
/*width: 200px;*/
margin: 20px 0 10px;
background-color: #EEE;
color: #777;
......@@ -393,8 +392,10 @@ div.title span.unfolded::before{
justify-content: center; /*space-between;*/
}
.search-query-wrapper{
position: relative;
flex-grow: 14;
background-color: white; border: 2px solid #E56400;
background-color: white;
border: 2px solid #E56400;
padding: 8px 6px;
}
......@@ -426,13 +427,7 @@ div.title span.unfolded::before{
.add-buttons{
display: inline-block;
width: 100%;
/*background-color: #DDD;
padding: 20px 0;
*/
margin: 20px 0 0;
}
.bool-buttons button{
......@@ -444,30 +439,33 @@ div.title span.unfolded::before{
.tab-buttons button{
display: inline-block;
background-color: #DDD;/*EEE;*/
width: 115px;
padding: 10px 30px;
margin: 0 10px;
display: inline-flex;
align-items: center;
justify-content: space-between;
border-right: 1px solid #BBB;
background-color: #CFCFCF;
width: 140px;
padding: 15px 20px;
font-size: .9em;
color: #777;
border: 1px solid #777;
color: #666;
text-align: center;
}
.tab-buttons button:last-child {
border-right: none;
}
.tab-buttons button#add-tab-selected{
background-color: #DDD;
color: #E56400;
border-color: #E56400;
font-weight: bold;
}
.tab-buttons button:disabled{
color: #BBB;
border-color: #BBB;
color: #AAA;
cursor: default;
}
.triangle-container{
width: 115px;
display: inline-block;
......@@ -500,12 +498,12 @@ div.title span.unfolded::before{
/* Formula and Material name boxes */
.FormulaBox, .MaterialNameBox{
.FormulaBox,.MaterialNameBox{
display: flex;
justify-content: center;
text-align: left;
background-color: #DDD;
padding: 40px 0;
padding: 20px 0;
}
.FormulaBox input, .MaterialNameBox input{
......@@ -521,7 +519,7 @@ div.title span.unfolded::before{
.FormulaBox input{
box-sizing: border-box;
width: 450px;
width: 580px;
}
/*
......@@ -553,6 +551,8 @@ div.title span.unfolded::before{
}
.AutocompleteTextField-dropdown > div, .AutocompleteMultiselectTextfield-dropdown > div {
display: flex;
align-items: center;
padding: 2px 10px 2px 10px;
cursor: pointer;
border: 1px solid transparent;
......@@ -564,24 +564,29 @@ div.title span.unfolded::before{
.AutocompleteMultiselectTextfield-selected-box{
padding: 3px;
padding-top: 5px;
}
.selectedItemLabel{
display: inline-block;
border-left: 1px solid #E56400;border-right: 1px solid #E56400;
color: #E56400;
/*box-shadow: 1px 1px 2px #BBB;*/
border-radius: 3px;
padding: 1px 4px;
margin-right: 8px; margin-top: 3px;
display: inline-flex;
align-items: center;
border-radius: 10px;
border: 1px solid #E56400;
height: 1.2rem;
padding: 4px 8px;
margin-right: 8px;
margin-top: 8px;
cursor: pointer;
}
.selectedItemLabel>img{
margin-left: 0.5rem;
}
/* Material name autocomplete */
.material-name-autocomplete-textfield{
width: 450px;
width: 580px;
}
.material-name-autocomplete-dropdown{
......@@ -592,7 +597,7 @@ div.title span.unfolded::before{
/* Autocomplete multiselect */
.AutocompleteMultiselectTextfield-dropdown {
width: 210px;
width: 200px;
background-color: white;
box-shadow: 0 1px 2px #E56400;
}
......@@ -626,6 +631,7 @@ div.title span.unfolded::before{
/*background-color: white;*/
}
.filter-section-box input[type="text"]{
box-sizing: border-box;
width: 200px;
padding: 6px;
border: 1px solid #DDD;
......@@ -771,7 +777,7 @@ img.remove-label{ cursor: pointer; }
}
#elementable table#pt-main{
padding-top: 25px;
padding-top: 20px;
color: #333; border: 0;
}
......@@ -847,10 +853,15 @@ img.remove-label{ cursor: pointer; }
div#specialRows{margin: 20px 40px;}
.legend{ text-align: center; padding: 16px 0;}
.legend {
text-align: center;
padding-top: 16px;
padding-bottom: 20px;
}
.legend div{
display: inline-block; color: black;
padding: 2px 12px; margin: 4px 0;
padding: 2px 12px;
margin: 4px 0;
}
.MaterialList{ /*width: 690px; margin: 0 auto 80px;*/
......@@ -1373,6 +1384,35 @@ text.structure-viewer-legend-labels{
font-size: 16px;
}
#syntax-error{
visibility: hidden;
display: flex;
align-items: center;
position: absolute;
height: 1.5rem;
color: white;
background-color: #E56400;
left: -2px;
bottom: 100%;
padding: 0.1rem 0.5rem;
}
.value-checkbox {
margin-right: 0.5rem;
}
.tab-buttons>button>img.search-fold-icon {
display: inline-block;
width: 15px;
height: 15px;
visibility: hidden;
pointer-events: none;
}
.tab-buttons>button#add-tab-selected>img.search-fold-icon {
visibility: visible;
}
/*
.tooltip {
visibility: hidden;
......
......@@ -260,15 +260,9 @@ PubSub.subscribe('show-search', search => {
titleElement.innerHTML = 'NOMAD Encyclopedia - Search';
breadcrumb.setState('search', search);
if (search === undefined) {
//LoadingPopup.reset();
searchMod.showSearchPage();
} else if (search === 'results') {
searchMod.showResultsPage();
}
showModuleDOM(searchMod.element);
searchMod.sendQuery();
});
......
......@@ -34,8 +34,8 @@ class AutocompleteMultiselectTextfield {
this.element.innerHTML = `
<input type="text" placeholder="${placeholder}" />
<div class="AutocompleteMultiselectTextfield-selected-box"></div>
<div class="AutocompleteMultiselectTextfield-dropdown ${this.id}-autocomplete-multiselect-dropdown"></div>
<div class="AutocompleteMultiselectTextfield-selected-box"></div>
`;
this.input = this.element.querySelector('input');
......@@ -144,7 +144,7 @@ class AutocompleteMultiselectTextfield {
function generateListItem(value, inputText, present) {
const listItem = document.createElement("div");
let innerHTML = `<input type="checkbox" data-value="${value}" ${present ? 'checked' : ''}>`;
let innerHTML = `<input class="value-checkbox" type="checkbox" data-value="${value}" ${present ? 'checked' : ''}>`;
if (inputText){
const pos = value.toUpperCase().indexOf(inputText.toUpperCase()); // console.log('pos', pos)
innerHTML +=
......@@ -197,7 +197,14 @@ class AutocompleteMultiselectTextfield {
const label = document.createElement('span');
label.className = 'selectedItemLabel';
label.dataset.value = value;
label.innerHTML = `${value} ❌`;
const labelText = document.createElement('div');
labelText.textContent = `${value}`;
const labelImage = document.createElement('img');
labelImage.src = 'img/cross-maroon.svg'
labelImage.width = 10
labelImage.height = 10
label.appendChild(labelText);
label.appendChild(labelImage);
return label;
}
}
......
......@@ -99,6 +99,7 @@ class MaterialList {
reqJson.search_by.restricted = (restrictedEl.checked ? '1' : '0');
console.log('SEARCHING: ', reqJson );
document.querySelector('#syntax-error').style.visibility = 'hidden';
fetch(util.getSearchURL(), {
method: 'POST',
headers: {'Content-Type': 'application/json;charset=utf-8'},
......@@ -115,17 +116,12 @@ class MaterialList {
this.visible = true;
this._render();
/* Go to the material page straightaway - Not wanted fro now
if (result.results.length === 1){
const onlyMat = this.matMap.values().next().value[0];
util.setBrowserHashPath('material', onlyMat.material_id);
} */
LoadingPopup.hide();
})
.catch(error => {
document.querySelector('.user-msg-box').innerHTML = 'Query expression NOT valid';
document.querySelector('#syntax-error').style.visibility = 'visible';
})
.finally(() => {
LoadingPopup.hide();
});
......@@ -144,16 +140,14 @@ class MaterialList {
_render(){
this.element.style.display = this.visible ? '' : 'none';
if (this.visible){
if (this.visible) {
this.noResultsBox.style.display = this.noResults ? '' : 'none';
this.matListWrapper.style.display = this.noResults ? 'none' : '';
this.matListContainer.updateList(this.matMap);
document.querySelector('.user-msg-box').innerHTML = this.noResults ? 'No search results' : 'See result list below';
}else
document.querySelector('.user-msg-box').innerHTML = '';
//document.querySelector('.user-msg-box').innerHTML = this.noResults ? 'No search results' : 'See result list below';
} else {
//document.querySelector('.user-msg-box').innerHTML = '';
}
}
......
......@@ -35,7 +35,9 @@ let FilterPanel = require('./FilterPanel.view.js');
let SwitchComponent = require('../common/SwitchComponent.js');
const REACTIVE_SEARCH = false;
const REACTIVE_SEARCH_RIGHT = false; // Whether the right panel uses reactive search
const REACTIVE_SEARCH_LEFT = true; // Whether the left panel uses reactive search
const INVALIDATE_RESULTS = false; // Whether the search results are invalidated upon changing search criteria
function replaceDashes(s){
return s.split('-').join('_');
......@@ -46,9 +48,8 @@ class NewSearchMod {
constructor() {
this.userGuidance = true; // can enabled/disabled
this.searchFilters = [];
this.isVisible = true;
this.element = document.createElement('div');
this.element.setAttribute("id",'search-module');
this.element.innerHTML=
......@@ -85,13 +86,9 @@ class NewSearchMod {
<span class="tooltiptext">If selected, the query will return materials that have individual calculations matching all your search criteria.</span>
</div>
</div>
<div class="add-buttons" >
<div class="tab-buttons" style="width: 70%; display: inline-block">
<button class="element-add-btn" id="add-tab-selected" style="margin-left: 50px">Element</button>
<button class="formula-add-btn" style="padding: 10px 20px;" >Formula</button>
<button class="name-add-btn" >Name</button>
<div class="tab-buttons" style="width: 70%; display: inline-block">
<button class="element-add-btn" id="add-tab-selected">Element<img class="search-fold-icon" src="img/unfolded.png"></button><button class="formula-add-btn">Formula<img class="search-fold-icon" src="img/unfolded.png"></button><button class="name-add-btn">Name<img class="search-fold-icon" src="img/unfolded.png"></button>
</div>
<div class="bool-buttons" style="width: 28%; display: inline-block" >
OR <span id="and-or-switch" ></span> AND
......@@ -101,32 +98,17 @@ class NewSearchMod {
<!--<input type="checkbox" name="and-or" class="not-symbol-btn" />NOT-->
</div>
</div>
<div class="add-box">
<div style="width: 70%; display: inline-block;">
<div class="triangle-container" style="margin-left: 50px;">
<div class="triangle element-tri" style="visibility: visible"></div>
</div>
<div class="triangle-container" >
<div class="triangle formula-tri" style="visibility: hidden"></div>
</div>
<div class="triangle-container" >
<div class="triangle name-tri" style="visibility: hidden"></div>
</div>
</div>
<div class="add-panel">
</div>
</div>
<div class="results-panel"> <!-- style="display: none"-->
</div>
</div> <!-- search-main-side -->
`;
this.filterSidePanel = this.element.querySelector('.search-filter-side');
this.addBox = this.element.querySelector('.add-box');
this.searchBox = new SearchBox();
this.searchBox.setBoolOperator('AND');
......@@ -147,16 +129,18 @@ class NewSearchMod {
this.searchBox.setSearchQueryChangeListener( () => {
REACTIVE_SEARCH ? this.sendQuery() : this.materialList.invalidateSearch();
REACTIVE_SEARCH_RIGHT ? this.sendQuery() : null;
//REACTIVE_SEARCH_RIGHT ? this.sendQuery() : INVALIDATE_RESULTS && this.materialList.invalidateSearch();
});
this.allowOtherElementsCheckbox = this.element.querySelector('#allow-other-elements');
this.allowOtherElementsCheckbox.addEventListener( 'change', e => {
REACTIVE_SEARCH ? this.sendQuery() : this.materialList.invalidateSearch();
REACTIVE_SEARCH_RIGHT ? this.sendQuery() : null;
//REACTIVE_SEARCH_RIGHT ? this.sendQuery() : this.materialList.invalidateSearch();
});
this.restrictedCheckbox = this.element.querySelector('#restricted-search');
this.restrictedCheckbox.addEventListener( 'change', e => {
REACTIVE_SEARCH ? this.sendQuery() : this.materialList.invalidateSearch();
REACTIVE_SEARCH_RIGHT ? this.sendQuery() : null;
//REACTIVE_SEARCH_RIGHT ? this.sendQuery() : this.materialList.invalidateSearch();
});
/* This button could be out of the search box because its functionality
......@@ -164,12 +148,18 @@ class NewSearchMod {
this.searchButton = this.searchBox.getSearchButtonElement();
this.searchButton.addEventListener( 'click', e => {
this.sendQuery();
this.addBox.style.display = 'none';
this.isVisible = false;
const icon = this.currentTabElement.querySelector('.search-fold-icon')
icon.src = "img/folded.png";
});
this.addButtonsBox= this.element.querySelector('.add-buttons');
this.addElementButton = this.addButtonsBox.querySelector('.element-add-btn');
this.addFormulaButton = this.addButtonsBox.querySelector('.formula-add-btn');
this.addMatNameButton = this.addButtonsBox.querySelector('.name-add-btn');
this.currentTabElement = this.addElementButton;
this.currentTab = 'element';
this.addPanel= this.element.querySelector('.add-panel');
......@@ -229,14 +219,14 @@ class NewSearchMod {
this.filterSidePanel.appendChild(this.filterPanel.element);
this.filterPanel.setPropsChangeListener( propsMap => {
REACTIVE_SEARCH ? this.sendQuery() : this.materialList.invalidateSearch();
REACTIVE_SEARCH_LEFT ? this.sendQuery() : null;
//REACTIVE_SEARCH_LEFT ? this.sendQuery() : this.materialList.invalidateSearch();
})
this.materialList= new MaterialList();
this.resultsPage = this.element.querySelector('.results-panel');
this.materialList.attachAndSetEvents(this.resultsPage);
this.currentTab = 'element';
this.addPanel.appendChild(this.elementTable.element);
this._events();
......@@ -244,56 +234,6 @@ class NewSearchMod {
_events() {
/*
// External event - Search button press
this.mainButton.addEventListener( "click", (e) => {
//console.log("this.labels: "+JSON.stringify(this.labels));
if (this.searchQuery.lenght === 0){
util.showUserMsg('No query');
}else{
let searchExpressionQuery;
// Search by Material name
if (this.queryTypes[0] === 'MN'){
//queryObj.push(this._getESSimpleMatch('material_name', item));
let rootQueryObj = { 'bool' : {} };
rootQueryObj.bool.must = [];
rootQueryObj.bool.must.push( this._getESSimpleMatch('material_name', this.searchQuery[0]) );
this.materialList.initSearch( rootQueryObj );
}else{ // Search by complex search expression
searchExpressionQuery = this.getOptimadeQueryFromSearchQuery(this.searchQuery, this.queryTypes);
this.materialList.initSearch(searchExpressionQuery);//this._addFiltersInSearchQuery( this.filterPanel.getValues(), searchExpressionQuery));
if (this.element.querySelector('#allow-other-elements').checked)
searchExpressionQuery = this._getESQueryFromSearchQuery_otherElements(
this.searchQuery, this.queryTypes);
// Regular case: search containing only the elements in the search expression
else searchExpressionQuery =
this._getESQueryFromSearchQuery(this.searchQuery, this.queryTypes);
this.materialList.initSearch(
this._addFiltersInSearchQuery( this.filterPanel.getValues(),
searchExpressionQuery));
//util.setBrowserHashPath('search','results');
//TODO: why not identifying by ID???
this.element.querySelector('.add-box').style.display = 'none';
}
}
});
*/
this.addButtonsBox.addEventListener( "click", (e) => {
if (e.target !== e.currentTarget) { // When the event source is a child
let className = e.target.className;
......@@ -315,18 +255,32 @@ class NewSearchMod {
this.addPanel.replaceChild(selectingElement, this.addPanel.lastChild);
this.element.querySelector('.add-box').style.display = 'block';
console.log("CLICK!");
// Hide or show the current tab
const icon = e.target.querySelector('.search-fold-icon')
if (this.currentTab == selectingTab) {
if (this.isVisible) {
this.addBox.style.display = 'none';
icon.src = "img/folded.png";
} else {
this.addBox.style.display = 'block';
icon.src = "img/unfolded.png";
}
this.isVisible = !this.isVisible;
} else {
this.addBox.style.display = 'block';
icon.src = "img/unfolded.png";
this.isVisible = true;
}
// Change the styles of the buttons
let selEl = this.element.querySelector('.'+this.currentTab+'-add-btn');
this._setTabSelectedStyles(selEl, false);
this._setTabSelectedStyles(e.target, true);
// Change the triangle
this.element.querySelector('.'+this.currentTab+'-tri').style.visibility = 'hidden';
this.element.querySelector('.'+selectingTab+'-tri').style.visibility = 'visible';
this.currentTab = selectingTab;
this.currentTabElement = selEl;
// Disable/enable bool operation buttons
this.element.querySelectorAll('.bool-buttons button').forEach( button => {
......@@ -351,45 +305,24 @@ class NewSearchMod {
}
}
});
// gray-out events for the Properties panel and Composition panel
let mainSideElem = this.element.querySelector('.search-main-side');
this.filterSidePanel.addEventListener( "mouseenter", event => {
mainSideElem.style.opacity = 0.3
});
this.filterSidePanel.addEventListener( "mouseleave", event => {
mainSideElem.style.opacity = ''
});
mainSideElem.addEventListener( "mouseenter", event => {
// console.log('filters:', this.filterPanel.getValues())
this.filterPanel.showSelectedProps(true)
});
mainSideElem.addEventListener( "mouseleave", event => {
this.filterPanel.showSelectedProps(false)
});
}
sendQuery(){
sendQuery() {
//**** The optimade query must be formed from the search box and the properties selected
const searchBoxOptimadeQuery = this.searchBox.getOptimadeQuery2(this.allowOtherElementsCheckbox.checked);
//const searchBoxOptimadeQuery = this.searchBox.getOptimadeQuery(this.allowOtherElementsCheckbox.checked);
const searchBoxOptimadeQuery = this.searchBox.getOptimadeQuery(this.allowOtherElementsCheckbox.checked);
const propsOptimadeQuery = getOptimadeQueryFromProps(this.filterPanel.getValues());
const sep = (searchBoxOptimadeQuery !== '' && propsOptimadeQuery !== '' ? ' AND ' : '');
//console.log(searchBoxOptimadeQuery)
//console.log(sep)
//console.log(propsOptimadeQuery)
// If one of them is empty, it and sep variable are ''
this.materialList.initSearch(searchBoxOptimadeQuery+sep+propsOptimadeQuery);
// this.materialList.invalidateSearch();
function getOptimadeQueryFromProps(propsValuesMap){
let query = '';
propsValuesMap.forEach( (values, prop) => {
let subquery = '';
......@@ -401,164 +334,8 @@ class NewSearchMod {
})
return query
}
}
_getESQueryFromSearchQuery(searchQuery, queryTypes){
let formulas = [];
let parFormulas = [];
let parOperator = null; // operator just before the opening parenthesis
let openIndex = -1;