From 9781425602a80f17a11c61bf19a72a6de351cf3e Mon Sep 17 00:00:00 2001 From: Inga Kirschnick <inga.kirschnick@uni-bielefeld.de> Date: Wed, 3 Aug 2022 16:21:11 +0200 Subject: [PATCH] Query Builder New Design --- app/static/js/CorpusAnalysis/QueryBuilder.js | 103 ++++++++++++++++--- app/templates/test/analyse_corpus.html.j2 | 95 ++++++++++------- 2 files changed, 146 insertions(+), 52 deletions(-) diff --git a/app/static/js/CorpusAnalysis/QueryBuilder.js b/app/static/js/CorpusAnalysis/QueryBuilder.js index c8916c38..fb4f6b2e 100644 --- a/app/static/js/CorpusAnalysis/QueryBuilder.js +++ b/app/static/js/CorpusAnalysis/QueryBuilder.js @@ -2,29 +2,27 @@ class ConcordanceQueryBuilder { constructor() { - - this.positionalAttrList = { - "emptyToken": {prettyText: "empty token", cqlOpening: "[", tokenValue:"", cqlClosing: "]"}, - "word": {prettyText: "word", cqlOpening: "[word=", tokenValue: "", cqlClosing: "]"}, - "lemma": {prettyText: "lemma", cqlOpening: "[lemma=", tokenValue:"", cqlClosing: "]"}, - "pos": {prettyText: "pos", cqlOpening: "[pos=", tokenValue:"", cqlClosing: "]"}, - "simplePos": {prettyText: "simple_pos", cqlOpening: "[simple_pos=", tokenValue:"", cqlClosing: "]"} - } this.elements = { counter: 0, yourQueryContent: [], queryContent:[], + closeQueryBuilder: document.querySelector("#close-query-builder"), //#region QueryBuilder Elements concordanceQueryBuilder: document.querySelector("#concordance-query-builder"), concordanceQueryBuilderButton: document.querySelector("#concordance-query-builder-button"), + positionalAttrButton: document.querySelector('#positional-attr-button'), + positionalAttrArea: document.querySelector('#positional-attr'), positionalAttr: document.querySelector("#token-attr"), - structuralAttr: document.querySelector("#structural-attr"), + structuralAttrButton: document.querySelector('#structural-attr-button'), + structuralAttrArea: document.querySelector("#structural-attr"), + queryContainer: document.querySelector('#query-container'), buttonPreparer: document.querySelector("#button-preparer"), yourQuery: document.querySelector("#your-query"), insertQueryButton: document.querySelector("#insert-query-button"), + queryPreview: document.querySelector('#query-preview'), tokenQuery: document.querySelector("#token-query"), tokenBuilderContent: document.querySelector("#token-builder-content"), buildTokenButton: document.querySelector("#build-token-button"), @@ -113,9 +111,14 @@ class ConcordanceQueryBuilder { //#endregion Token Attributes } + this.elements.closeQueryBuilder.addEventListener("click", () => {this.closeQueryBuilderModal();}); + this.elements.concordanceQueryBuilderButton.addEventListener("click", () => {this.clearAll();}); this.elements.insertQueryButton.addEventListener("click", () => {this.insertQuery();}); + this.elements.positionalAttrButton.addEventListener("click", () => {this.showPositionalAttrArea();}); + this.elements.structuralAttrButton.addEventListener("click", () => {this.showStructuralAttrArea();}); + //#region Structural Attribute Event Listeners this.elements.sentence.addEventListener("click", () => {this.addSentence();}); this.elements.entity.addEventListener("click", () => {this.addEntity();}); @@ -492,8 +495,21 @@ class ConcordanceQueryBuilder { } tokenButtonfactory(dataType, prettyText, tokenText) { + let chipColor = 'style="background-color:#'; + if (dataType === 'pos' || dataType === 'word' || dataType === 'lemma' || dataType === 'simplePos'){ + chipColor += 'EF60B4'; + }else if (dataType === "emptyToken"){ + chipColor += '43C6FC'; + }else if (dataType === "and" || dataType === "or"){ + chipColor += 'FFCC00'; + }else if (dataType === "incidenceModifier" || dataType === "betweenNM" || dataType === "exactlyN"){ + chipColor += '2FBBAB'; + }else { + chipColor = ''; + } + tokenText = encodeURI(tokenText); - this.elements.buttonPreparer.innerHTML += '<a class="btn-small waves-effect waves-light" style="margin-left:3px" data-type="' + dataType + '" data-tokentext="' + tokenText + '">' + prettyText + '</a>'; + this.elements.buttonPreparer.innerHTML += '<div class="chip"' + chipColor +'" data-type="' + dataType + '" data-tokentext="' + tokenText + '">' + prettyText + '<i class="material-icons close">close</i></div>'; let tokenDummyButton = this.elements.buttonPreparer.querySelector(':first-child'); tokenDummyButton.addEventListener("click", () => {this.deleteTokenAttr(tokenDummyButton);}); this.elements.tokenQuery.appendChild(tokenDummyButton); @@ -538,7 +554,7 @@ class ConcordanceQueryBuilder { let emptyTokenCheck = false; for (let element of this.elements.tokenQuery.childNodes) { - tokenQueryContent += ' ' + element.text + ' '; + tokenQueryContent += ' ' + element.firstChild.data + ' '; tokenQueryText += ' ' + decodeURI(element.dataset.tokentext); if (element.dataset.type === "emptyToken"){ emptyTokenCheck = true; @@ -547,7 +563,7 @@ class ConcordanceQueryBuilder { if (emptyTokenCheck === false){ tokenQueryText = '[' + tokenQueryText + ']'; - } + } this.buttonfactory('token', tokenQueryContent, tokenQueryText); tokenQueryContent = ''; @@ -564,12 +580,66 @@ class ConcordanceQueryBuilder { //#region General Functions + closeQueryBuilderModal(){ + let instance = M.Modal.getInstance(this.elements.concordanceQueryBuilder); + instance.close(); + } + + showPositionalAttrArea(){ + this.elements.positionalAttrArea.classList.remove('hide'); + this.elements.structuralAttrArea.classList.add('hide'); + } + + showStructuralAttrArea(){ + this.elements.positionalAttrArea.classList.add('hide'); + this.elements.structuralAttrArea.classList.remove('hide'); + } + buttonfactory(dataType, prettyText, queryText) { + let chipColor = 'style="background-color:#'; + if (dataType === 'start-sentence' || dataType === 'end-sentence'){ + chipColor += 'FD9720'; + }else if (dataType === "start-empty-entity" || dataType === "start-entity" || dataType === "end-entity"){ + chipColor += 'A6E22D'; + }else if (dataType === "text-annotation"){ + chipColor += '2FBBAB'; + }else if (dataType === "token"){ + chipColor += '28B3D1'; + }else { + chipColor = ''; + } + queryText = encodeURI(queryText); - this.elements.buttonPreparer.innerHTML += '<a class="btn-small waves-effect waves-light" style="margin-left:3px" data-type="' + dataType + '" data-query="' + queryText + '">' + prettyText + '</a>'; + this.elements.buttonPreparer.innerHTML += '<div class="chip"' + chipColor +'" data-type="' + dataType + '" data-query="' + queryText + '">' + prettyText + '<i class="material-icons close">close</i></div>'; let dummyButton = this.elements.buttonPreparer.querySelector(':first-child'); dummyButton.addEventListener("click", () => {this.deleteAttr(dummyButton);}); this.elements.yourQuery.appendChild(dummyButton); + this.elements.queryContainer.classList.remove("hide"); + + this.queryPreviewBuilder(); + + } + + queryPreviewBuilder(){ + + this.elements.yourQueryContent = []; + + for (let element of this.elements.yourQuery.childNodes) { + + let queryElement = decodeURI(element.dataset.query); + if (queryElement.includes("<")){ + queryElement = queryElement.replace("<", "<"); + } + if (queryElement.includes(">")){ + queryElement = queryElement.replace(">", ">"); + } + this.elements.yourQueryContent.push(queryElement); + } + + + let queryString = this.elements.yourQueryContent.join(' '); + queryString += ";"; + this.elements.queryPreview.innerHTML = queryString; } deleteAttr(attr) { @@ -639,8 +709,10 @@ class ConcordanceQueryBuilder { this.elements.counter -= 1; if(this.elements.counter === 0){ this.elements.insertQueryButton.classList.add("disabled"); - + this.elements.queryContainer.classList.add("hide"); } + + this.queryPreviewBuilder(); } insertQuery() { @@ -666,9 +738,12 @@ class ConcordanceQueryBuilder { this.elements.buildTokenButton.classList.add("disabled"); this.elements.insertQueryButton.classList.add("disabled"); this.elements.concordanceQueryBuilder.classList.remove('modal-close'); + this.elements.positionalAttrArea.classList.add('hide'); + this.elements.structuralAttrArea.classList.add('hide'); this.hideEverything(); this.buttonDisabler('start'); this.elements.yourQuery.innerHTML = ''; + this.elements.queryContainer.classList.add("hide"); } //#endregion General Functions } diff --git a/app/templates/test/analyse_corpus.html.j2 b/app/templates/test/analyse_corpus.html.j2 index 5b95003d..d698cc5c 100644 --- a/app/templates/test/analyse_corpus.html.j2 +++ b/app/templates/test/analyse_corpus.html.j2 @@ -1,6 +1,8 @@ {% extends "base.html.j2" %} {% import "materialize/wtf.html.j2" as wtf %} - +<style> + a {color: #FFFFFF;} +</style> {% block main_attribs %} class="service-scheme" data-service="corpus-analysis" id="corpus-analysis-app-container"{% endblock main_attribs %} @@ -252,17 +254,49 @@ <div class="modal" id="concordance-query-builder" style="width:70%;"> <div class="modal-content"> - <h4>Query-Builder</h4> - <ul class="tabs"> - <li class="tab"><a class="active" href="#structural-attr">Add structural attributes</a></li> - <li class="tab"><a href="#positional-attr">Add new token</a></li> - </ul> + <nav style="background-color:#AA9CC9; margin-top:-25px; margin-left:-25px; width:105%;"> + <div class="nav-wrapper" style="padding-left:15px"> + <a href="#!" class="brand-logo"><i class="material-icons">build</i>Query Builder</a> + <i class="material-icons close right" style="margin-right: 25px; cursor:pointer;" id="close-query-builder">close</i> + </div> + </nav> + <p></p> + + <div id="query-container" class="hide"> + <div class="row"> + <h6 class="col s7">Your Query:</h6> + </div> + <div id="button-preparer"></div> + <div class="row"> + <div class="col s10" id="your-query" style="border-bottom-style: solid; border-bottom-width:1px;"></div> + <a class="btn-small disabled waves-effect waves-teal col s1" id="insert-query-button" style="background-color:#00426f; text-align:center"> + <i class="material-icons">send</i> + </a> + </div> + <p>Preview:</p> + <p id="query-preview"></p> + <p></p> + <br> + </div> + - <div id="structural-attr"> + <h6>Use the following options to build your query:</h6> + <p></p> + <a class="btn-large waves-effect waves-light tooltipped" id="positional-attr-button" data-position="bottom" data-tooltip="Search for any token, for example a word, a lemma or a part-of-speech tag">Add new token to your query</a> + <a class="btn-large waves-effect waves-light tooltipped" id="structural-attr-button" data-position="bottom" data-tooltip="Structure your query with structural attributes, for example sentences, entities or annotate the text">Add structural attributes to your query</a> + + <div id="structural-attr" class="hide"> + <p></p> + <h6 style="margin-left:15px;">Which structural attribute do you want to add to your query?</h6> <p></p> - <a class="btn-small waves-effect waves-light" id="sentence">sentence</a> - <a class="btn-small waves-effect waves-light" id="entity">entity</a> - <a class="btn-small waves-effect waves-light" id="text-annotation">text annotation</a> + <div class="row"> + <div class="col s12"> + <a class="btn-small waves-effect waves-light" id="sentence" style="background-color:#FD9720">sentence</a> + <a class="btn-small waves-effect waves-light" id="entity" style="background-color:#A6E22D">entity</a> + <a class="btn-small waves-effect waves-light" id="text-annotation" style="background-color:#2FBBAB">text annotation</a> + </div> + </div> + <div id="entity-builder" class="hide"> <p></p> @@ -304,7 +338,6 @@ </select> </div> </div> - <div data-inga=""></div> </div> @@ -343,18 +376,20 @@ </div> </div> - <div id="positional-attr"> + <div id="positional-attr" class="hide"> + <p></p> + <h6 style="margin-left:15px;">Which kind of token are you looking for?</h6> <p></p> <div class="row"> <div id="token-attr" class="col s12"> - <a class="btn-small waves-effect waves-light" id="empty-token" style="background-color:#43c6fc">empty token</a> - <a class="btn-small waves-effect waves-light" id="word" style="background-color:#ef60b4">word</a> - <a class="btn-small waves-effect waves-light" id="lemma" style="background-color:#ef60b4">lemma</a> - <a class="btn-small waves-effect waves-light" id="pos" style="background-color:#ef60b4">pos</a> - <a class="btn-small waves-effect waves-light" id="simple-pos-button" style="background-color:#ef60b4">simple_pos</a> - <a class="btn-small waves-effect waves-light disabled" id="or" style="background-color:#fc0">or</a> - <a class="btn-small waves-effect waves-light disabled" id="and" style="background-color:#fc0">and</a> - <a class="dropdown-trigger btn-small disabled waves-effect waves-light" href="#" data-target="incidence-modifiers" style="background-color:#2fbbab">incidence modifiers</a> + <a class="btn-small tooltipped waves-effect waves-light" data-position="bottom" data-tooltip="You can look for an empty token. It is NOT recommended to search for an empty token <br> without an incidence modifier, because each token would matches this pattern." id="empty-token" style="background-color:#43c6fc">empty token</a> + <a class="btn-small tooltipped waves-effect waves-light" id="word" style="background-color:#ef60b4" data-position="bottom" data-tooltip="You can search for a word and modify the corresponding search">word</a> + <a class="btn-small tooltipped waves-effect waves-light" id="lemma" style="background-color:#ef60b4" data-position="bottom" data-tooltip="You can search for a lemma and modify the corresponding search">lemma</a> + <a class="btn-small tooltipped waves-effect waves-light" id="pos" style="background-color:#ef60b4" data-position="bottom" data-tooltip="You can search for a part of speech tag">pos</a> + <a class="btn-small tooltipped waves-effect waves-light" id="simple-pos-button" style="background-color:#ef60b4" data-position="bottom" data-tooltip="You can search for a simple part of speech tag">simple_pos</a> + <a class="btn-small tooltipped waves-effect waves-light disabled" id="or" style="background-color:#fc0" data-position="bottom" data-tooltip="You can add another condition to your token. <br>At least one must be fulfilled">or</a> + <a class="btn-small tooltipped waves-effect waves-light disabled" id="and" style="background-color:#fc0" data-position="bottom" data-tooltip="You can add another condition to your token. <br>Both must be fulfilled">and</a> + <a class="dropdown-trigger tooltipped btn-small disabled waves-effect waves-light" href="#" data-target="incidence-modifiers" data-position="bottom" data-tooltip="Incidence Modifiers are special characters or patterns, <br>which determine how often a character represented previously should occur." style="background-color:#2fbbab">incidence modifiers</a> </div> </div> <div id="token-builder-content"> @@ -525,27 +560,11 @@ <div id="token-query"></div> <p></p> <a class="btn waves-effect disabled waves-light" style="background-color:#00426f" id="build-token-button"> - Add token + Add token to your query <i class="material-icons right">check</i> </a> </div> - - <br><hr> - <div> - <h5>Your Query</h5> - <p><i>Examples: </i></p> - <p> - <ent_type="PERSON"> []* </ent_type> []* - [simple_pos="VERB"] :: match.text_publishing_year="1991"; - </p> - <div id="button-preparer"></div> - <div id="your-query"></div> - <p></p> - <a class="btn disabled waves-effect waves-light" id="insert-query-button" style="background-color:#00426f"> - Insert - <i class="material-icons right">send</i> - </a> - </div> + </div> </div> -- GitLab