Commit 828ebf2c authored by Lauri Himanen's avatar Lauri Himanen
Browse files

Merge branch 'enc-search' into enc-search-logic

parents b6185e8d 5ff199f4
......@@ -485,79 +485,95 @@ div.title span.unfolded::before{
cursor: default;
}
#formula-box, #material-name-box{
/* Formula and Material name boxes */
.FormulaBox, .MaterialNameBox{
display: flex;
justify-content: center;
text-align: left;
background-color: #DDD;
padding: 40px 0;
}
.textfield-composition{
.FormulaBox input, .MaterialNameBox input{
padding: 10px;
border: 0;
font-size: 0.9em;
}
.MaterialNameBox input{
box-sizing: border-box;
width: 100%;
}
.FormulaBox input{
box-sizing: border-box;
width: 450px;
margin-left: 50px;
}
/*
.textfield-composition{
padding: 10px;
border: 0;
font-size: 0.9em;
box-sizing: border-box;
width: 100%;
}*/
.textfield-filter{
padding: 6px;
border: 1px solid #DDD;
width: 200px;
}
.autocomplete-textfield-materialname{
position: relative;
}
.autocomplete-textfield-strukturbericht, .autocomplete-textfield-structuretype {
position: relative;
.material-name-autocomplete-textfield, .material-name-autocomplete-dropdown{
width: 450px;
}
.autocomplete-items{
font-size: 0.9em;
position: absolute;
z-index: 99;
}
.autocomplete-items-materialname{
margin-left: 50px;
width: 470px;
}
.autocomplete-items div {
padding: 2px 10px 2px 10px;
cursor: pointer;
background-color: #DDD;
border: 1px solid transparent;
}
/* Autocomplete component */
.autocomplete-items input {
vertical-align: middle;
.AutocompleteTextField{
display: inline-block;
}
.autocomplete-items-strukturbericht, .autocomplete-items-structuretype{
margin-left: 0px;
width: 220px;
.AutocompleteTextField-dropdown{
font-size: 0.9em;
position: absolute;
z-index: 99;
box-shadow: 1px 1px 4px gray;
}
/*
.autocomplete-items-strukturbericht div {
.AutocompleteTextField-dropdown > div {
padding: 2px 10px 2px 10px;
cursor: pointer;
background-color: #DDD;
border: 1px solid transparent;
}
*/
.autocomplete-active {
border-color: #E56400 !important;
}
/* To remove
.autocomplete-em {
font-weight: bold;
}
.autocomplete-items-strukturbericht, .autocomplete-items-structuretype{
margin-left: 0px;
width: 220px;
} */
.adding-formula-btn, .adding-name-btn{
padding: 9px;
border: 1px solid #999;
......
......@@ -22,201 +22,9 @@
"use strict";
class AutocompleteTextField {
constructor(name = "", allowEmptyInput = false) {
this.classPostfix = name;
this.allowEmptyInput = allowEmptyInput;
this.element = document.createElement('input');
this.element.type = 'text';
this.element.className = 'autocomplete-textfield-' + this.classPostfix;
this.currentFocus = -1;
this.selectListener = undefined;
}
replaceElement(oldElement) {
oldElement.parentElement.replaceChild(this.element, oldElement);
}
setSelectListener(listener) {
this.selectListener = listener;
}
autocomplete(allAcValues) {
/* the autocomplete function takes an array of possible autocomplete values.
in the following we will use 'ac' as abbrevation for 'autocomplete'
*/
/* process input when someone writes in the text field:*/
this.element.addEventListener("input", (e) => {
this._processInput(allAcValues);
});
/* react to keyboard navigation */
this.element.addEventListener("keydown", (e) => {
if (e.keyCode == 40) { // arrow DOWN
this._setActive(this.currentFocus + 1);
} else if (e.keyCode == 38) { // arrow UP
this._setActive(this.currentFocus - 1);
}
});
/* react to enter key */
this.element.addEventListener("keypress", (e) => {
if (e.keyCode == 13) { // ENTER
/* simulate a click on the "active" item:*/
this._clickActive();
}
});
/* react to klicking into the textfield */
this.element.addEventListener("click", (e) => {
this._processInput(allAcValues);
e.stopPropagation();
});
// close lists when someone clicks in the document:*/
document.addEventListener("click", (e) => {
this._closeAllLists();
});
}
_processInput(allAcValues) {
let currentInput = this.element.value;
/*close any already open lists of autocompleted values*/
this._closeAllLists();
// in case of an empty input field
if (!this.allowEmptyInput && !currentInput) {
return false;
}
/*create a DIV element that will contain the items (values):*/
let listContainer = document.createElement("DIV");
listContainer.setAttribute("id", "autocomplete-list");
listContainer.classList.add("autocomplete-items");
listContainer.classList.add("autocomplete-items-"+ this.classPostfix);
/*append the DIV element as a child of the autocomplete container:*/
this.element.parentNode.appendChild(listContainer);
/*for each item in the array...*/
let acItemIndex = 0;
for (var i = 0; i < allAcValues.length; i++) {
/*check if the item contains the same letters as the text field value:*/
let acValue = allAcValues[i];
let pos = 0;
if (currentInput) {
pos = acValue.toUpperCase().search(currentInput.toUpperCase());
}
if (pos >= 0){
let listItem = this._generateListItem(acValue,
currentInput,
acItemIndex)
listContainer.appendChild(listItem);
/* check if a valid option was completely entered.
if so, set the focus to the element corresponding to the input */
if (acValue.toUpperCase() === currentInput.toUpperCase()) {
this._setActive(acItemIndex);
}
acItemIndex++;
}
}
}
_generateListItem(acText, inputText, itemIndex) {
/*create a DIV element for each matching element:*/
let listItem = document.createElement("DIV");
/*make the matching letters bold:*/
if (inputText){
let pos = acText.toUpperCase().search(inputText.toUpperCase());
listItem.innerHTML = acText.substr(0, pos);
listItem.innerHTML += "<strong>";
listItem.innerHTML += acText.substr(pos, inputText.length);
listItem.innerHTML += "</strong>";
listItem.innerHTML += acText.substr(pos + inputText.length);
} else {
listItem.innerHTML = acText;
}
/* clicking on the as list item puts selects the corresponding name for searching */
listItem.addEventListener("click", (e) => {
/*insert the value for the autocomplete text field:*/
this._setText(acText);
});
/* hovering puts the focus on the related list item */
listItem.addEventListener("mouseover", (e) => {
this._setActive(itemIndex);
});
return listItem;
}
_setText(value) {
/*insert the value for the autocomplete text field:*/
this.element.value = value;
/* notify listener */
if (this.selectListener) {
this.selectListener();
}
/*close the list of autocompleted values,
(or any other open lists of autocompleted values)*/
this._closeAllLists();
}
_setActive(index) {
let listItems = document.getElementById("autocomplete-list")
.getElementsByTagName("div");
/* remove the active status from all list items */
Array.from(listItems).forEach(item => {
item.classList.remove("autocomplete-active");
});
/* ensure to stay in the list
out of boundary indices are mapped to the closest border */
let newFocus = Math.max(0, index);
newFocus = Math.min(newFocus, listItems.length-1);
this.currentFocus = newFocus;
/* mark the active status by a style class */
listItems[newFocus].classList.add("autocomplete-active");
}
_clickActive() {
if (this.currentFocus > -1) {
let listItems = document.getElementById("autocomplete-list")
.getElementsByTagName("div");
listItems[this.currentFocus].click();
}
}
_closeAllLists() {
/*close all autocomplete lists in the document */
let allAcLists = document.getElementsByClassName("autocomplete-items");
for (let acList of allAcLists) {
acList.parentNode.removeChild(acList);
}
this.currentFocus = -1;
}
}
class AutocompleteMultiselectList {
class AutocompleteMultiselectTextfield {
constructor(name = "") {
this.classPostfix = name;
......@@ -471,6 +279,4 @@ class AutocompleteMultiselectList {
// EXPORTS
module.exports = { AutocompleteTextField: AutocompleteTextField,
AutocompleteMultiselectList: AutocompleteMultiselectList
};
module.exports = AutocompleteMultiselectTextfield;
/**
* Copyright 2019-2019 Georg Huhs
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
/*
Basic class for extending a text field with autocomplete functionality
*/
"use strict";
class AutocompleteTextfield {
constructor(id = "", placeholder = '', allowEmptyInput = false) {
this.id = id;
this.element = document.createElement('div');
//this.element.style.display = 'inline';
this.element.className = `AutocompleteTextField ${id}-autocomplete-textfield`;
this.element.innerHTML = `
<input type="text" placeholder="${placeholder}" /> <!-- class="autocomplete-textfield-${this.id}" /> -->
<div class="AutocompleteTextField-dropdown ${this.id}-autocomplete-dropdown"></div> <!-- autocomplete-items- -->
`;
this.input = this.element.querySelector('input');
this.listContainer = this.element.querySelector('div');
this.selectListener;
// state
this.valueList; // List of autocomplete (possible) values
this.allowEmptyInput = allowEmptyInput;
// event management
this.input.addEventListener("input", (e) => {
this._processInput();
});
// react to keyboard navigation
this.input.addEventListener("keydown", (e) => {
if (e.keyCode == 40) { // arrow DOWN
if (this._getActiveListItem())
this._setActiveListItem(this._getActiveListItem().nextSibling);
} else if (e.keyCode == 38) { // arrow UP
if (this._getActiveListItem())
this._setActiveListItem(this._getActiveListItem().previousSibling);
}
});
// react to enter key
this.input.addEventListener("keypress", e => {
if (e.keyCode == 13) { // ENTER
// simulate a click on the "active" item
this._clickOnActiveItem();//_clickActive();
}
});
// react to clicking into the textfield
this.input.addEventListener("click", (e) => {
this._processInput();
e.stopPropagation();
});
// close lists when someone clicks in the document
document.addEventListener("click", e => {
this._cleanList();// this._closeAllLists();
});
this.listContainer.addEventListener("click", e => {
let listItem = event.target.closest('div'); // (1)
this.setValue(listItem.textContent);
});
this.listContainer.addEventListener("mouseover", e => {
let listItem = event.target.closest('div'); // (1)
this._setActiveListItem(listItem);
});
}
getValue(){
return this.input.value;
}
resetValue(){
this.input.value = '';
}
disable(bool){
this.input.disabled = bool;
}
setAutocompleteList(valueList){
this.valueList = valueList;
}
setSelectListener(listener) {
this.selectListener = listener;
}
_processInput() {
const currentInput = this.input.value;
// close any already open lists of autocompleted values
this._cleanList();//this._closeAllLists();
// in case of an empty input field
if (!this.allowEmptyInput && !currentInput) {
return false;
}
// for each autocomplete value
let counter = 0;
const matchingValues = this.valueList.filter( value => {
const matching = value.toUpperCase().includes(currentInput.toUpperCase());
if (matching) counter++;
return counter <= 15 && matching;
});
this.listContainer.innerHTML = '';
matchingValues.forEach( value => {
const listItem = generateListItem(value, currentInput);
this.listContainer.append(listItem);
// check if a valid option was completely entered. if so, set the focus to the element corresponding to the input
if (value.toUpperCase() === currentInput.toUpperCase())
this._setActiveListItem(listItem);
function generateListItem(value, inputText, itemIndex) {
const listItem = document.createElement("div");
if (inputText){
const pos = value.toUpperCase().indexOf(inputText.toUpperCase()); // console.log('pos', pos)
listItem.innerHTML +=
`${value.substring(0, pos)}<strong>${value.substring(pos, pos+inputText.length)}</strong>${value.substring(pos + inputText.length)}`;
}else
listItem.innerHTML = acText;
return listItem;
}
});
}
setValue(value) {
// insert the value to the text field
this.input.value = value;
// notify listener
if (this.selectListener) this.selectListener();
// close the dropdown list of autocompleted values
this._cleanList();//this._closeAllLists();
}
_getActiveListItem(){
return this.listContainer.querySelector('.autocomplete-active');
}
_setActiveListItem(element){
const currentActiveItem = this.listContainer.querySelector('.autocomplete-active');
if (currentActiveItem) currentActiveItem.classList.remove('autocomplete-active');
element.classList.add('autocomplete-active');
}
_clickOnActiveItem() {
const activeItem = this.listContainer.querySelector('.autocomplete-active');
if (activeItem) activeItem.click();
}
_cleanList() {
this.listContainer.innerHTML = '';
}
}
// EXPORTS
module.exports = AutocompleteTextfield;
......@@ -27,7 +27,7 @@
let util = require('../common/util.js');
let InfoSys = require('../common/InfoSys.js');
let AutocompleteMultiselectList = require('./Autocomplete.view.js').AutocompleteMultiselectList;
let AutocompleteMultiselectTextfield = require('./AutocompleteMultiselectTextfield.js');
const NOT_SELECTED_OPACITY = 0.2
......@@ -281,7 +281,8 @@ class AutocompleteField{
<span info-sys-data="${id}">${name}</span>
</div>`;
this.autocomplete = new AutocompleteMultiselectList(id);
this.autocomplete = new AutocompleteMultiselectTextfield(id);
this.autocomplete.element.placeholder = "Search and select options";
this.autocomplete.element.classList.add('textfield-filter');
this.element.append(this.autocomplete.element)
......@@ -290,6 +291,7 @@ class AutocompleteField{
let names = JSON.parse(r1.response)[this.fieldId];
this.autocomplete.autocomplete(names);
});
}
getValues(){
......
......@@ -21,29 +21,27 @@
"use strict";
let util = require('../common/util.js');
let AutocompleteTextField = require('./Autocomplete.view.js').AutocompleteTextField;
let AutocompleteTextfield = require('./AutocompleteTextfield.js');
class MaterialNameBox{
constructor() {
this.element = document.createElement('div');
this.element.setAttribute("id",'material-name-box');
this.materialNameField = new AutocompleteTextField('materialname');
this.materialNameField.element.placeholder = 'Start typing a material name';
this.materialNameField.element.classList.add('textfield-composition');
//this.materialNameField.element.classList.add("materialname-text-field");
this.element.innerHTML = ` <div style="padding-bottom: 20px;">
<div class="materialname-placeholder"></div>
<button class="adding-name-btn" disabled>Add to query</button>
</div>
`;
this.element.className = 'MaterialNameBox';
this.element.innerHTML =
` <!-- the autocomplete text field goes here -->
<button class="adding-name-btn" disabled>Add to query</button>
`;
this.materialNameField = new AutocompleteTextfield('material-name', 'Start typing a material name');
this.materialNameField.element.querySelector('input').classList.add('textfield-composition'); // ** Pending to change
this.element.prepend(this.materialNameField.element);
this.button = this.element.querySelector('.adding-name-btn');
this.button.addEventListener( "click", (e) => {
this.listener(this.materialNameField.element.value);
this.materialNameField.element.value = '';
this.listener(this.materialNameField.getValue());