eval("/**\n * Copyright 2016-2020 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 the UI component implementing the search box.\n It represents the search query for the user and enables its edition.\n */\n\n\n\nlet util = __webpack_require__(/*! ../common/util.js */ \"./src/common/util.js\");\nlet OptimadeTranslator = __webpack_require__(/*! ./OptimadeTranslator.js */ \"./src/search-mod/OptimadeTranslator.js\");\nlet Formula = __webpack_require__(/*! ./Formula.js */ \"./src/search-mod/Formula.js\");\n//\n//\n//// local utility functions\nfunction getTagHtml(tag, isFormula){\n return `<span class=\"search-label\" data-el=\"${tag}\" >\n <img src=\"img/tag.svg\" height=\"16px\" class=\"remove-label\"\n style=\"vertical-align: bottom\"/>\n${isFormula ? util.getSubscriptedFormula(tag) : tag}\n <img src=\"img/cross.svg\" height=\"6px\" class=\"remove-label\"\n style=\"vertical-align: middle; padding: 4px 3px 6px 5px;\" />\n </span>`;\n}\n\n\nclass SearchBox{\n\n constructor() {\n\n //this.searchQuery = [];\n // this.queryTypes = []; //**** Types associated to query elements\n // Types: element (E), formula (F), symbol (S) and prop names\n // \n // \n this.currentConnector;\n this.notItem; // It signals next item is preceding for a NOT\n this.inSubquery; // the current query pointer is in a subquery, paretheses open \n this.rootQuery; // Root query representation. Root item object (type=\"query\")\n this._resetState();\n /* Two type of object representing the expresions:\n - item (node): {type: 'element'|'formula'|'query', value: \"ElementName\"|\"Formula\"| Another (sub)query structure, not: true|false }\n - boolean connector: { type: 'connector', value: 'AND'|'OR'}\n\n */\n\n this.element = document.createElement('div');\n this.element.className = 'search-box';\n\n this.element.innerHTML = ` \n <div class=\"search-query-wrapper\" >\n <div id=\"syntax-error\">\n <div>Invalid query syntax</div>\n </div>\n <div class=\"search-query-box\" style=\"float: left;\"></div>\n <button class=\"clean-btn\" style=\"float: right;\">Clear all</button>\n </div>\n\n <!-- this button should be out of the search box because its functionality\n is not part of the search box, it's general for the search module\n and it's probably being removed eventually --> \n <button class=\"search-btn\" >Search</button>\n `;\n\n this.cleanButton = this.element.querySelector('.clean-btn');\n this.cleanButton.addEventListener( \"click\", (e) => {\n // init search query\n this._resetState();\n this.renderQuery();\n this.cleanSearchQueryListener();\n });\n\n this.searchQueryBox = this.element.querySelector('.search-query-box');\n this.searchQueryBox.addEventListener( \"click\", e => {\n let className = e.target.className;\n if (className === 'remove-label'){\n let elSymbol = e.target.parentElement.getAttribute('data-el');\n this.removeElementORFormulaInSearchQuery(elSymbol);\n }\n });\n\n }\n\n _resetState(){\n this.notItem = false;\n this.inSubquery = false;\n this.rootQuery = { type: 'query', value: [], not: false }; // no prop open indicates that is the first\n }\n\n getOldQueryFormat(){\n const oldFormat = [];\n this.rootQuery.value.forEach( item => {\n oldFormat.push(...getItemInOldFormat(item));\n })\n\n const searchQuery = [];\n const queryTypes = [];\n oldFormat.forEach( item => {\n searchQuery.push(item.split(':')[0]);\n queryTypes.push(item.split(':')[1]);\n })\n console.log('OLD F:', oldFormat, searchQuery, queryTypes);\n\n return [searchQuery, queryTypes]\n\n function getItemInOldFormat(item){\n const oldFormat = [];\n if (item.not){\n oldFormat.push('NOT:S');\n }\n if (item.type === 'query'){\n oldFormat.push('(:S');\n item.value.forEach( i => {\n oldFormat.push(...getItemInOldFormat(i));\n })\n oldFormat.push('):S');\n }else{ // types: element, formula, material and connector\n let itemValue = item.value+':';\n if (item.type === 'element') itemValue += 'E';\n else if (item.type === 'formula') itemValue += 'F';\n else if (item.type === 'material') itemValue += 'MN';\n else itemValue += 'S'; // connector\n oldFormat.push(itemValue);\n }\n return oldFormat;\n }\n\n }\n\n getOptimadeQuery(allowOtherElements) {\n // Empty query\n if (this.rootQuery.value.length === 0) {\n return '';\n }\n\n // Translate element/formula queries into OptimadeSyntax\n const translator = new OptimadeTranslator();\n const [searchQuery, queryTypes] = this.getOldQueryFormat();\n return translator.translate(searchQuery, queryTypes, allowOtherElements);\n }\n\n setBoolOperator(operator){\n this.currentConnector = operator;\n }\n\n renderQuery() {\n document.querySelector('#syntax-error').style.visibility = 'hidden';\n this.searchQueryBox.innerHTML = getQueryStructHTML(this.rootQuery);\n\n if (this.searchQueryChangeListener) this.searchQueryChangeListener();\n\n function getQueryStructHTML(queryObj){\n\n if (queryObj.type === 'connector')\n return getSymbolHTML(queryObj.value);\n\n else if (!queryObj.type && queryObj.not) // NOT item wrapper, the item is not defined yet\n return getSymbolHTML(' NOT');\n\n else if (queryObj.type === 'element' || queryObj.type === 'formula' || queryObj.type === 'material') // element and formula\n return (queryObj.not ? getSymbolHTML(' NOT') : '')+\n getTagHtml(queryObj.value, (queryObj.type === 'formula' ? true : false));\n else{ // the object represents a query\n let html= '';\n queryObj.value.forEach( subqueryObj => {\n html += getQueryStructHTML(subqueryObj);\n });\n //console.log('getQueryStructHTML', queryObj, queryObj.value[queryObj.length-1])\n const notHTML = (queryObj.not ? getSymbolHTML(' NOT') : '')\n const isOpen = queryObj.open;\n return notHTML+(isOpen === undefined ? html : \n getSymbolHTML(' (')+html+( isOpen ? '' : getSymbolHTML(') ')));\n } \n }\n\n function getSymbolHTML(s){\n return `<span class=\"search-query-symbol\">${s}</span>`;\n }\n }\n\n\n // Add an item (with a preceding connector if needed) to the query \n // The item could be an NOT wrapper for a tag or subquery\n _addItem(item){ // It can be a tag item or a NOT (wrapping an item, added later) \n const queryContent = this.rootQuery.value;\n const tempQueryContent = this.inSubquery ?\n queryContent[queryContent.length-1].value : queryContent;\n\n // If the item is not at the beginning of the query (or subquery) and\n if ( tempQueryContent.length > 0 && \n // the last item is not a connector (AND|OR)\n tempQueryContent[tempQueryContent.length-1].type !== 'connector'){ \n // Add a connector (before the item)\n tempQueryContent.push( {type: 'connector', value: this.currentConnector} );\n }\n\n if (item === 'NOT') // Add an item wrapper with the NOT prop to true \n tempQueryContent.push({ not: true }); // type and value props are undefined\n else if (item === 'SUBQUERY')\n queryContent.push({ type: 'query', value: [], open: true, not: false}); \n else{ // Regular tags: element|formula|material\n const [type, tag] = item.split(':');\n tempQueryContent.push({type: type, value: tag, not: false});\n }\n console.log('ROOT QUERY ', this.rootQuery)\n this.renderQuery();\n }\n\n\n // Public method - type = element|formula|material \n addTag(tag, type){ // add an element, formula or material\n\n if (this.notItem){ // The tag to add is preceded for a NOT, the item object is already created\n const queryContent = this.rootQuery.value;\n const tempQueryContent = this.inSubquery ?\n queryContent[queryContent.length-1].value : queryContent;\n tempQueryContent[tempQueryContent.length-1].type = type;\n tempQueryContent[tempQueryContent.length-1].value = tag;\n this.notItem = false;\n this.renderQuery();\n }else\n this._addItem(type+':'+tag);\n }\n\n\n addElements(elementArray){\n let index = elementArray.length;\n while (index--) {\n this.addTag(elementArray[index], 'element');\n }\n return true;\n }\n\n\n addParentheses(isOpen){\n const queryContent = this.rootQuery.value; // ** Not checking if the it's inside a subquery\n\n if (isOpen){\n if (this.notItem){\n queryContent[queryContent.length-1].type = 'query';\n queryContent[queryContent.length-1].value = [];\n this.notItem = false;\n }else\n this._addItem('SUBQUERY');\n }\n queryContent[queryContent.length-1].open = isOpen;\n this.renderQuery();\n this.inSubquery = isOpen;\n }\n\n\n addNOT(){\n this._addItem('NOT');\n this.notItem = true; // The next item will be in a not expression\n }\n\n\n removeElementORFormulaInSearchQuery(item){\n // spot the item and remove the item and the bool operator(s) related\n removeItem(this.rootQuery, item);\n\n function removeItem(queryObj, item){\n const queryContent = queryObj.value;\n for (let i = 0; i < queryContent.length; i++) {\n if (queryContent[i].value === item) {\n if (queryContent[i+1] && queryContent[i+1].type === 'connector'){\n queryContent.splice(i, 2);\n }else\n queryContent.splice(i, 1);\n break;\n\n }else if (queryContent[i].type === 'query'){\n removeItem(queryContent[i], item);\n if (queryContent[i].value.length == 0){\n if (queryContent[i+1] && queryContent[i+1].type === 'connector'){\n queryContent.splice(i, 2);\n }else\n queryContent.splice(i, 1);\n }\n }\n }\n }\n\n this.renderQuery();\n\n console.log('ROOT QUERY REMOVING ', this.rootQuery)\n\n if (util.ELEMENTS.indexOf(item) >= 0){ // It's an element (being removed)\n this.removeElementListener(item);\n }\n\n if (this.rootQuery.value.length === 0){ // The search query gets blank\n this.cleanSearchQueryListener();\n }\n\n return true;\n }\n\n\n setCleanSearchQueryListener(listener){\n this.cleanSearchQueryListener = listener;\n }\n\n\n setRemoveElementListener(listener) {\n this.removeElementListener = listener;\n }\n\n setSearchQueryChangeListener(listener) {\n this.searchQueryChangeListener = listener;\n }\n\n getSearchButtonElement(){\n return this.element.querySelector('.search-btn');\n }\n}\n\n// EXPORTS\nmodule.exports = SearchBox;\n\n\n//# sourceURL=webpack:///./src/search-mod/SearchBox.view.js?");
eval("/**\n * Copyright 2016-2020 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 the UI component implementing the search box.\n It represents the search query for the user and enables its edition.\n */\n\n\n\nlet util = __webpack_require__(/*! ../common/util.js */ \"./src/common/util.js\");\nlet OptimadeTranslator = __webpack_require__(/*! ./OptimadeTranslator.js */ \"./src/search-mod/OptimadeTranslator.js\");\nlet Formula = __webpack_require__(/*! ./Formula.js */ \"./src/search-mod/Formula.js\");\n//\n//\n//// local utility functions\nfunction getTagHtml(tag, isFormula){\n return `<span class=\"search-label\" data-el=\"${tag}\" >\n ${isFormula ? util.getSubscriptedFormula(tag) : tag}\n <img src=\"img/cross.svg\" height=\"6px\" class=\"remove-label\"\n style=\"vertical-align: middle; padding: 4px 3px 6px 5px;\" />\n </span>`;\n}\n\n\nclass SearchBox{\n\n constructor() {\n\n //this.searchQuery = [];\n // this.queryTypes = []; //**** Types associated to query elements\n // Types: element (E), formula (F), symbol (S) and prop names\n // \n // \n this.currentConnector;\n this.notItem; // It signals next item is preceding for a NOT\n this.inSubquery; // the current query pointer is in a subquery, paretheses open \n this.rootQuery; // Root query representation. Root item object (type=\"query\")\n this._resetState();\n /* Two type of object representing the expresions:\n - item (node): {type: 'element'|'formula'|'query', value: \"ElementName\"|\"Formula\"| Another (sub)query structure, not: true|false }\n - boolean connector: { type: 'connector', value: 'AND'|'OR'}\n\n */\n\n this.element = document.createElement('div');\n this.element.className = 'search-box';\n\n this.element.innerHTML = ` \n <div id=\"composition-title\" class=\"filter-section-title\" style>\n <div>Composition</div>\n </div>\n <div class=\"search-query-wrapper\" >\n <div id=\"syntax-error\">\n <div>Invalid query syntax</div>\n </div>\n <div class=\"search-query-box\" style=\"float: left;\"></div>\n <button class=\"clean-btn\" style=\"float: right;\">Clear</button>\n </div>\n <!-- this button should be out of the search box because its functionality\n is not part of the search box, it's general for the search module\n and it's probably being removed eventually --> \n <button class=\"search-btn\" >Search</button>\n `;\n\n this.cleanButton = this.element.querySelector('.clean-btn');\n this.cleanButton.addEventListener( \"click\", (e) => {\n // init search query\n this._resetState();\n this.renderQuery();\n this.cleanSearchQueryListener();\n });\n\n this.searchQueryBox = this.element.querySelector('.search-query-box');\n this.searchQueryBox.addEventListener( \"click\", e => {\n let className = e.target.className;\n if (className === 'remove-label'){\n let elSymbol = e.target.parentElement.getAttribute('data-el');\n this.removeElementORFormulaInSearchQuery(elSymbol);\n }\n });\n\n }\n\n _resetState(){\n this.notItem = false;\n this.inSubquery = false;\n this.rootQuery = { type: 'query', value: [], not: false }; // no prop open indicates that is the first\n }\n\n getOldQueryFormat(){\n const oldFormat = [];\n this.rootQuery.value.forEach( item => {\n oldFormat.push(...getItemInOldFormat(item));\n })\n\n const searchQuery = [];\n const queryTypes = [];\n oldFormat.forEach( item => {\n searchQuery.push(item.split(':')[0]);\n queryTypes.push(item.split(':')[1]);\n })\n console.log('OLD F:', oldFormat, searchQuery, queryTypes);\n\n return [searchQuery, queryTypes]\n\n function getItemInOldFormat(item){\n const oldFormat = [];\n if (item.not){\n oldFormat.push('NOT:S');\n }\n if (item.type === 'query'){\n oldFormat.push('(:S');\n item.value.forEach( i => {\n oldFormat.push(...getItemInOldFormat(i));\n })\n oldFormat.push('):S');\n }else{ // types: element, formula, material and connector\n let itemValue = item.value+':';\n if (item.type === 'element') itemValue += 'E';\n else if (item.type === 'formula') itemValue += 'F';\n else if (item.type === 'material') itemValue += 'MN';\n else itemValue += 'S'; // connector\n oldFormat.push(itemValue);\n }\n return oldFormat;\n }\n\n }\n\n getOptimadeQuery(allowOtherElements) {\n // Empty query\n if (this.rootQuery.value.length === 0) {\n return '';\n }\n\n // Translate element/formula queries into OptimadeSyntax\n const translator = new OptimadeTranslator();\n const [searchQuery, queryTypes] = this.getOldQueryFormat();\n return translator.translate(searchQuery, queryTypes, allowOtherElements);\n }\n\n setBoolOperator(operator){\n this.currentConnector = operator;\n }\n\n renderQuery() {\n document.querySelector('#syntax-error').style.visibility = 'hidden';\n this.searchQueryBox.innerHTML = getQueryStructHTML(this.rootQuery);\n\n if (this.searchQueryChangeListener) this.searchQueryChangeListener();\n\n function getQueryStructHTML(queryObj){\n\n if (queryObj.type === 'connector')\n return getSymbolHTML(queryObj.value);\n\n else if (!queryObj.type && queryObj.not) // NOT item wrapper, the item is not defined yet\n return getSymbolHTML(' NOT');\n\n else if (queryObj.type === 'element' || queryObj.type === 'formula' || queryObj.type === 'material') // element and formula\n return (queryObj.not ? getSymbolHTML(' NOT') : '')+\n getTagHtml(queryObj.value, (queryObj.type === 'formula' ? true : false));\n else{ // the object represents a query\n let html= '';\n queryObj.value.forEach( subqueryObj => {\n html += getQueryStructHTML(subqueryObj);\n });\n //console.log('getQueryStructHTML', queryObj, queryObj.value[queryObj.length-1])\n const notHTML = (queryObj.not ? getSymbolHTML(' NOT') : '')\n const isOpen = queryObj.open;\n return notHTML+(isOpen === undefined ? html : \n getSymbolHTML(' (')+html+( isOpen ? '' : getSymbolHTML(') ')));\n } \n }\n\n function getSymbolHTML(s){\n return `<span class=\"search-query-symbol\">${s}</span>`;\n }\n }\n\n\n // Add an item (with a preceding connector if needed) to the query \n // The item could be an NOT wrapper for a tag or subquery\n _addItem(item){ // It can be a tag item or a NOT (wrapping an item, added later) \n const queryContent = this.rootQuery.value;\n const tempQueryContent = this.inSubquery ?\n queryContent[queryContent.length-1].value : queryContent;\n\n // If the item is not at the beginning of the query (or subquery) and\n if ( tempQueryContent.length > 0 && \n // the last item is not a connector (AND|OR)\n tempQueryContent[tempQueryContent.length-1].type !== 'connector'){ \n // Add a connector (before the item)\n tempQueryContent.push( {type: 'connector', value: this.currentConnector} );\n }\n\n if (item === 'NOT') // Add an item wrapper with the NOT prop to true \n tempQueryContent.push({ not: true }); // type and value props are undefined\n else if (item === 'SUBQUERY')\n queryContent.push({ type: 'query', value: [], open: true, not: false}); \n else{ // Regular tags: element|formula|material\n const [type, tag] = item.split(':');\n tempQueryContent.push({type: type, value: tag, not: false});\n }\n console.log('ROOT QUERY ', this.rootQuery)\n this.renderQuery();\n }\n\n\n // Public method - type = element|formula|material \n addTag(tag, type){ // add an element, formula or material\n\n if (this.notItem){ // The tag to add is preceded for a NOT, the item object is already created\n const queryContent = this.rootQuery.value;\n const tempQueryContent = this.inSubquery ?\n queryContent[queryContent.length-1].value : queryContent;\n tempQueryContent[tempQueryContent.length-1].type = type;\n tempQueryContent[tempQueryContent.length-1].value = tag;\n this.notItem = false;\n this.renderQuery();\n }else\n this._addItem(type+':'+tag);\n }\n\n\n addElements(elementArray){\n let index = elementArray.length;\n while (index--) {\n this.addTag(elementArray[index], 'element');\n }\n return true;\n }\n\n\n addParentheses(isOpen){\n const queryContent = this.rootQuery.value; // ** Not checking if the it's inside a subquery\n\n if (isOpen){\n if (this.notItem){\n queryContent[queryContent.length-1].type = 'query';\n queryContent[queryContent.length-1].value = [];\n this.notItem = false;\n }else\n this._addItem('SUBQUERY');\n }\n queryContent[queryContent.length-1].open = isOpen;\n this.renderQuery();\n this.inSubquery = isOpen;\n }\n\n\n addNOT(){\n this._addItem('NOT');\n this.notItem = true; // The next item will be in a not expression\n }\n\n\n removeElementORFormulaInSearchQuery(item){\n // spot the item and remove the item and the bool operator(s) related\n removeItem(this.rootQuery, item);\n\n function removeItem(queryObj, item){\n const queryContent = queryObj.value;\n for (let i = 0; i < queryContent.length; i++) {\n if (queryContent[i].value === item) {\n if (queryContent[i+1] && queryContent[i+1].type === 'connector'){\n queryContent.splice(i, 2);\n }else\n queryContent.splice(i, 1);\n break;\n\n }else if (queryContent[i].type === 'query'){\n removeItem(queryContent[i], item);\n if (queryContent[i].value.length == 0){\n if (queryContent[i+1] && queryContent[i+1].type === 'connector'){\n queryContent.splice(i, 2);\n }else\n queryContent.splice(i, 1);\n }\n }\n }\n }\n\n this.renderQuery();\n\n console.log('ROOT QUERY REMOVING ', this.rootQuery)\n\n if (util.ELEMENTS.indexOf(item) >= 0){ // It's an element (being removed)\n this.removeElementListener(item);\n }\n\n if (this.rootQuery.value.length === 0){ // The search query gets blank\n this.cleanSearchQueryListener();\n }\n\n return true;\n }\n\n\n setCleanSearchQueryListener(listener){\n this.cleanSearchQueryListener = listener;\n }\n\n\n setRemoveElementListener(listener) {\n this.removeElementListener = listener;\n }\n\n setSearchQueryChangeListener(listener) {\n this.searchQueryChangeListener = listener;\n }\n\n getSearchButtonElement(){\n return this.element.querySelector('.search-btn');\n }\n}\n\n// EXPORTS\nmodule.exports = SearchBox;\n\n\n//# sourceURL=webpack:///./src/search-mod/SearchBox.view.js?");
c.textContent="Restrict to individual calculations";
constd=document.createElement('span');
d.className="tooltiptext";
d.textContent="If selected, the query will return materials that have individual calculations simultaneously matching your methodology and properties criteria."
a.append(b);
a.append(c);
a.append(d);
container.append(a);
this.element.append(container);
InfoSys.addToInfoSystem(this.element);
// The value change event in fields is handled at container level (event delegation pattern)