From fe7f69d5965090f9a5540b2dcee95bfb46c4aa15 Mon Sep 17 00:00:00 2001 From: Inga Kirschnick Date: Mon, 21 Aug 2023 07:26:54 +0200 Subject: [PATCH] QB form update + incidence modifier --- app/static/css/queryBuilder.css | 45 +++----- .../CorpusAnalysisConcordance.js | 31 +++-- app/static/js/CorpusAnalysis/QueryBuilder.js | 45 -------- .../ElementReferencesQueryBuilder.js | 8 +- .../GeneralFunctionsQueryBuilder.js | 68 ++++++----- ...alAttributeBuilderFunctionsQueryBuilder.js | 22 ++++ ...enAttributeBuilderFunctionsQueryBuilder.js | 37 +++++- .../query_builder/_expert_mode.html.j2 | 2 +- .../query_builder/_query_builder.html.j2 | 107 +++++++++++------- 9 files changed, 197 insertions(+), 168 deletions(-) diff --git a/app/static/css/queryBuilder.css b/app/static/css/queryBuilder.css index 6cc4a5a1..08bbb778 100644 --- a/app/static/css/queryBuilder.css +++ b/app/static/css/queryBuilder.css @@ -1,3 +1,12 @@ +#corpus-analysis-concordance-query-builder-input-field-container { + border-bottom: #9E9E9E 1px solid; + height: 60px; +} + +#corpus-analysis-concordance-query-builder-input-field { + margin-top: 23px; +} + .modal-content { overflow-x: hidden; } @@ -79,40 +88,20 @@ margin-right: 10px; } -#corpus-analysis-concordance-ignore-case-checkbox { - margin-left: 5px; +[data-target="corpus-analysis-concordance-character-incidence-modifiers-dropdown"], [data-target="corpus-analysis-concordance-token-incidence-modifiers-dropdown"] { + background-color: #2FBBAB !important; } -#corpus-analysis-concordance-incidence-modifiers-dropdown a{ - background-color: white; +#corpus-analysis-concordance-exactly-n-token-modal, #corpus-analysis-concordance-between-nm-token-modal { + width: 30%; } -[data-target="corpus-analysis-concordance-incidence-modifiers-dropdown"] { - background-color: #2FBBAB; +[data-modal-id="corpus-analysis-concordance-exactly-n-token-modal"], [data-modal-id="corpus-analysis-concordance-between-nm-token-modal"] { + margin-top: 15px !important; } -#corpus-analysis-concordance-or, #corpus-analysis-concordance-and { - background-color: #fc0; -} - -#corpus-analysis-concordance-betweenNM { - width: 60%; -} - -#corpus-analysis-concordance-query-builder-tutorial-modal { - width: 60%; -} - -#corpus-analysis-concordance-query-builder-tutorial-modal ul { - margin-top: 10px; -} - -#corpus-analysis-concordance-query-builder-tutorial { - padding:15px; -} - -#corpus-analysis-concordance-scroll-up-button-query-builder-tutorial { - background-color: #28B3D1; +[data-options-action="and"], [data-options-action="or"] { + background-color: #fc0 !important; } [data-type="start-sentence"], [data-type="end-sentence"] { diff --git a/app/static/js/CorpusAnalysis/CorpusAnalysisConcordance.js b/app/static/js/CorpusAnalysis/CorpusAnalysisConcordance.js index 891e12f7..91ce0f68 100644 --- a/app/static/js/CorpusAnalysis/CorpusAnalysisConcordance.js +++ b/app/static/js/CorpusAnalysis/CorpusAnalysisConcordance.js @@ -10,7 +10,8 @@ class CorpusAnalysisConcordance { container: document.querySelector(`#corpus-analysis-concordance-container`), error: document.querySelector(`#corpus-analysis-concordance-error`), userInterfaceForm: document.querySelector(`#corpus-analysis-concordance-user-interface-form`), - form: document.querySelector(`#corpus-analysis-concordance-form`), + expertModeForm: document.querySelector(`#corpus-analysis-concordance-expert-mode-form`), + queryBuilderForm: document.querySelector(`#corpus-analysis-concordance-query-builder-form`), progress: document.querySelector(`#corpus-analysis-concordance-progress`), subcorpusInfo: document.querySelector(`#corpus-analysis-concordance-subcorpus-info`), subcorpusActions: document.querySelector(`#corpus-analysis-concordance-subcorpus-actions`), @@ -30,12 +31,14 @@ class CorpusAnalysisConcordance { this.app.registerExtension(this); } - async submitForm() { + async submitForm(queryModeId) { this.app.disableActionElements(); - // let query = this.elements.form.query.value.trim(); - let query = this.checkQueryInput(); - console.log(query); - let subcorpusName = this.elements.form['subcorpus-name'].value; + let queryBuilderQuery = document.querySelector('#corpus-analysis-concordance-query-preview').innerHTML.trim(); + let expertModeQuery = this.elements.expertModeForm.query.value.trim(); + let query = queryModeId === 'corpus-analysis-concordance-expert-mode-form' ? expertModeQuery : queryBuilderQuery; + let form = queryModeId === 'corpus-analysis-concordance-expert-mode-form' ? this.elements.expertModeForm : this.elements.queryBuilderForm; + + let subcorpusName = form['subcorpus-name'].value; this.elements.error.innerText = ''; this.elements.error.classList.add('hide'); this.elements.progress.classList.remove('hide'); @@ -74,9 +77,13 @@ class CorpusAnalysisConcordance { this.data.corpus = this.app.data.corpus; this.data.subcorpora = {}; // Add event listeners - this.elements.form.addEventListener('submit', (event) => { + this.elements.expertModeForm.addEventListener('submit', (event) => { event.preventDefault(); - this.submitForm(); + this.submitForm(this.elements.expertModeForm.id); + }); + this.elements.queryBuilderForm.addEventListener('submit', (event) => { + event.preventDefault(); + this.submitForm(this.elements.queryBuilderForm.id); }); this.elements.userInterfaceForm.addEventListener('change', (event) => { if (event.target === this.elements.userInterfaceForm['context']) { @@ -98,14 +105,6 @@ class CorpusAnalysisConcordance { }); } - checkQueryInput() { - if (document.querySelector('#corpus-analysis-concordance-expert-mode-display').classList.contains('hide')) { - return document.querySelector('#corpus-analysis-concordance-query-preview').innerHTML.trim(); - } else { - return this.elements.form.query.value.trim(); - } - } - clearSubcorpusList() { this.elements.subcorpusList.innerHTML = ''; this.elements.subcorpusList.classList.add('hide'); diff --git a/app/static/js/CorpusAnalysis/QueryBuilder.js b/app/static/js/CorpusAnalysis/QueryBuilder.js index 00388622..ad097048 100644 --- a/app/static/js/CorpusAnalysis/QueryBuilder.js +++ b/app/static/js/CorpusAnalysis/QueryBuilder.js @@ -7,51 +7,6 @@ class ConcordanceQueryBuilder { this.tokenAttributeBuilderFunctions = new TokenAttributeBuilderFunctionsQueryBuilder(this.elements); this.structuralAttributeBuilderFunctions = new StructuralAttributeBuilderFunctionsQueryBuilder(this.elements); - // Event listener for structural attribute modal - document.querySelectorAll('[data-structural-attr-modal-action-button]').forEach(button => { - button.addEventListener('click', () => { - this.structuralAttributeBuilderFunctions.actionButtonInStrucAttrModalHandler(button.dataset.structuralAttrModalActionButton); - }); - }); - - // Event listener for token attribute modal - this.elements.positionalAttrSelection.addEventListener('change', (event) => { - this.generalFunctions.toggleClass(['word', 'lemma', 'english-pos', 'german-pos', 'simple-pos'], 'hide', 'add'); - if (event.target.value !== 'empty-token') { - this.generalFunctions.toggleClass([event.target.value], 'hide', 'remove'); - this.generalFunctions.toggleClass(['incidence-modifiers', 'or', 'and'], 'disabled', 'add'); - this.tokenAttributeBuilderFunctions.resetMaterializeSelection([this.elements.englishPosSelection, this.elements.germanPosSelection, this.elements.simplePosSelection]); - } - if (event.target.value === 'word' || event.target.value === 'lemma') { - this.generalFunctions.toggleClass(['input-field-options'], 'hide', 'remove'); - } else if (event.target.value === 'empty-token'){ - this.tokenAttributeBuilderFunctions.addTokenToQuery(); - } else { - this.generalFunctions.toggleClass(['input-field-options'], 'hide', 'add'); - } - }); - // Options for positional attribute selection - document.querySelectorAll('.positional-attr-options-action-button[data-options-action]').forEach(button => { - button.addEventListener('click', () => {this.tokenAttributeBuilderFunctions.actionButtonInOptionSectionHandler(button.dataset.optionsAction);}); - }); - document.querySelectorAll('.incidence-modifier-selection[data-incidence-modifier]').forEach(button => { - button.addEventListener('click', () => {this.tokenAttributeBuilderFunctions.incidenceModifierHandler(button);}); - }); - document.querySelectorAll('.n-m-submit-button').forEach(button => { - button.addEventListener('click', () => { - this.tokenAttributeBuilderFunctions.nmSubmitHandler(button.dataset.modalId); - }); - }); - - // Initializing and styling the Materialize Chip components - M.Chips.init( - this.elements.queryInputField, - { - placeholder: 'Add your query here' - } - ); - document.querySelector('#corpus-analysis-concordance-form-query-builder input').style.setProperty('width', '150px', 'important'); - this.elements.positionalAttrModal = M.Modal.init( document.querySelector('#corpus-analysis-concordance-positional-attr-modal'), { diff --git a/app/static/js/CorpusAnalysis/QueryBuilder/ElementReferencesQueryBuilder.js b/app/static/js/CorpusAnalysis/QueryBuilder/ElementReferencesQueryBuilder.js index f75c3a99..c6dcd257 100644 --- a/app/static/js/CorpusAnalysis/QueryBuilder/ElementReferencesQueryBuilder.js +++ b/app/static/js/CorpusAnalysis/QueryBuilder/ElementReferencesQueryBuilder.js @@ -1,13 +1,11 @@ class ElementReferencesQueryBuilder { constructor() { // General Elements - this.counter = 0; - this.queryInputField = document.querySelector('#corpus-analysis-concordance-form-query-builder'); - this.queryInputFieldInstance = M.Chips.getInstance(this.queryInputField); - this.queryInputFieldContent = []; + this.queryInputField = document.querySelector('#corpus-analysis-concordance-query-builder-input-field'); + this.queryChipElements = []; // Structural Attribute Builder Elements - this.structuralAttrModalInstance = document.querySelector('#corpus-analysis-concordance-structural-attr-modal'); + this.structuralAttrModal = M.Modal.getInstance(document.querySelector('#corpus-analysis-concordance-structural-attr-modal')); this.sentenceElement = document.querySelector('[data-structural-attr-modal-action-button="sentence"]'); this.entityElement = document.querySelector('[data-structural-attr-modal-action-button="entity"]'); this.textAnnotationElement = document.querySelector('[data-structural-attr-modal-action-button="text-annotation"]'); diff --git a/app/static/js/CorpusAnalysis/QueryBuilder/GeneralFunctionsQueryBuilder.js b/app/static/js/CorpusAnalysis/QueryBuilder/GeneralFunctionsQueryBuilder.js index 0208442e..70b6115d 100644 --- a/app/static/js/CorpusAnalysis/QueryBuilder/GeneralFunctionsQueryBuilder.js +++ b/app/static/js/CorpusAnalysis/QueryBuilder/GeneralFunctionsQueryBuilder.js @@ -9,23 +9,29 @@ class GeneralFunctionsQueryBuilder { }); } + updateChipList() { + this.elements.queryChipElements = this.elements.queryInputField.querySelectorAll('.chip'); + } + queryChipFactory(dataType, prettyQueryText, queryText) { - this.elements.counter++; - this.elements.queryInputFieldInstance.addChip({ - tag: prettyQueryText - }); + queryText = Utils.escape(queryText); + prettyQueryText = Utils.escape(prettyQueryText); + let queryChipElement = Utils.HTMLToElement( + ` + + ${prettyQueryText} + close + + ` + ); - let queryChipElementIndex = this.elements.queryInputFieldInstance.$chips.length - 1; - let queryChipElement = this.elements.queryInputFieldInstance.$chips[queryChipElementIndex]; - queryChipElement.classList.add('query-component'); - queryChipElement.setAttribute('data-type', dataType); - queryChipElement.setAttribute('data-query', queryText); - queryChipElement.setAttribute('draggable', 'true'); - - queryChipElement.addEventListener('click', () => this.deleteAttr(queryChipElement)); + queryChipElement.addEventListener('click', () => this.selectChipElement(queryChipElement)); + queryChipElement.querySelector('i').addEventListener('click', () => this.deleteChipElement(queryChipElement)); + queryChipElement.addEventListener('dragstart', this.handleDragStart.bind(this, queryChipElement)); queryChipElement.addEventListener('dragend', this.handleDragEnd); - + this.elements.queryInputField.appendChild(queryChipElement); + this.updateChipList(); this.queryPreviewBuilder(); } @@ -65,45 +71,51 @@ class GeneralFunctionsQueryBuilder { targetChipClone.addEventListener('drop', (event) => { let dropzone = event.target; dropzone.parentElement.replaceChild(queryChipElement, dropzone); - this.elements.queryInputFieldInstance.$chips = Array.from(this.elements.queryInputField.querySelectorAll('.chip')); + this.updateChipList(); this.queryPreviewBuilder(); }); } queryPreviewBuilder() { let queryPreview = document.querySelector('#corpus-analysis-concordance-query-preview'); - let queryChipElements = Array.from(Object.values(this.elements.queryInputFieldInstance.$chips)); - if (!isNaN(queryChipElements[queryChipElements.length - 1])) { - queryChipElements.pop(); - } - this.elements.queryInputFieldContent = []; - queryChipElements.forEach(element => { - + let queryInputFieldContent = []; + this.elements.queryChipElements.forEach(element => { let queryElement = element.dataset.query; if (queryElement !== undefined) { queryElement = Utils.escape(queryElement); - this.elements.queryInputFieldContent.push(queryElement); } + queryInputFieldContent.push(queryElement); }); - let queryString = this.elements.queryInputFieldContent.join(' '); + let queryString = queryInputFieldContent.join(' '); queryString += ';'; queryPreview.innerHTML = queryString; queryPreview.parentNode.classList.toggle('hide', queryString === ';'); } - deleteAttr(attr) { + deleteChipElement(attr) { if (attr.dataset.type === "start-sentence") { this.elements.sentenceElement.innerHTML = 'Sentence'; } else if (attr.dataset.type === "start-entity" || attr.dataset.type === "start-empty-entity") { this.elements.entityElement.innerHTML = 'Entity'; } - let queryChipElements = Array.from(Object.values(this.elements.queryInputFieldInstance.$chips)); - queryChipElements.pop(); - this.elements.counter -= 1; - this.elements.queryInputFieldInstance.deleteChip(queryChipElements.indexOf(attr)); + this.elements.queryInputField.removeChild(attr); + this.updateChipList(); this.queryPreviewBuilder(); } + + selectChipElement(attr) { + document.querySelectorAll('.chip.teal').forEach(element => { + if (element !== attr) { + element.classList.remove('teal', 'lighten-2'); + this.toggleClass(['token-incidence-modifiers'], 'disabled', 'add'); + } + }); + + this.toggleClass(['token-incidence-modifiers'], 'disabled', 'toggle'); + attr.classList.toggle('teal'); + attr.classList.toggle('lighten-2'); +} } diff --git a/app/static/js/CorpusAnalysis/QueryBuilder/StructuralAttributeBuilderFunctionsQueryBuilder.js b/app/static/js/CorpusAnalysis/QueryBuilder/StructuralAttributeBuilderFunctionsQueryBuilder.js index 8b65619f..742533de 100644 --- a/app/static/js/CorpusAnalysis/QueryBuilder/StructuralAttributeBuilderFunctionsQueryBuilder.js +++ b/app/static/js/CorpusAnalysis/QueryBuilder/StructuralAttributeBuilderFunctionsQueryBuilder.js @@ -2,11 +2,32 @@ class StructuralAttributeBuilderFunctionsQueryBuilder extends GeneralFunctionsQu constructor(elements) { super(elements); this.elements = elements; + + document.querySelectorAll('[data-structural-attr-modal-action-button]').forEach(button => { + button.addEventListener('click', () => { + this.actionButtonInStrucAttrModalHandler(button.dataset.structuralAttrModalActionButton); + }); + }); + document.querySelector('.ent-type-selection-action[data-ent-type="any"]').addEventListener('click', () => { + this.queryChipFactory('start-empty-entity', 'Entity Start', ''); + this.queryChipFactory('end-entity', 'Entity End', ''); + this.elements.structuralAttrModal.close(); + }); + document.querySelector('.ent-type-selection-action[data-ent-type="english"]').addEventListener('change', (event) => { + this.queryChipFactory('start-entity', `Entity Type=${event.target.value}`, ``); + this.queryChipFactory('end-entity', 'Entity End', ''); + this.elements.structuralAttrModal.close(); + }); + + } actionButtonInStrucAttrModalHandler(action) { switch (action) { case 'sentence': + this.queryChipFactory('start-sentence', 'Sentence Start', ''); + this.queryChipFactory('end-sentence', 'Sentence End', ''); + this.elements.structuralAttrModal.close(); break; case 'entity': this.toggleClass(['entity-builder'], 'hide', 'toggle'); @@ -20,4 +41,5 @@ class StructuralAttributeBuilderFunctionsQueryBuilder extends GeneralFunctionsQu break; } } + } diff --git a/app/static/js/CorpusAnalysis/QueryBuilder/TokenAttributeBuilderFunctionsQueryBuilder.js b/app/static/js/CorpusAnalysis/QueryBuilder/TokenAttributeBuilderFunctionsQueryBuilder.js index bef06116..d887f341 100644 --- a/app/static/js/CorpusAnalysis/QueryBuilder/TokenAttributeBuilderFunctionsQueryBuilder.js +++ b/app/static/js/CorpusAnalysis/QueryBuilder/TokenAttributeBuilderFunctionsQueryBuilder.js @@ -3,6 +3,36 @@ class TokenAttributeBuilderFunctionsQueryBuilder extends GeneralFunctionsQueryBu super(elements); this.elements = elements; + this.elements.positionalAttrSelection.addEventListener('change', (event) => { + this.toggleClass(['word', 'lemma', 'english-pos', 'german-pos', 'simple-pos'], 'hide', 'add'); + if (event.target.value !== 'empty-token') { + this.toggleClass([event.target.value], 'hide', 'remove'); + this.toggleClass(['incidence-modifiers', 'or', 'and'], 'disabled', 'add'); + this.resetMaterializeSelection([this.elements.englishPosSelection, this.elements.germanPosSelection, this.elements.simplePosSelection]); + } + if (event.target.value === 'word' || event.target.value === 'lemma') { + this.toggleClass(['input-field-options'], 'hide', 'remove'); + } else if (event.target.value === 'empty-token'){ + this.addTokenToQuery(); + } else { + this.toggleClass(['input-field-options'], 'hide', 'add'); + } + }); + + // Options for positional attribute selection + document.querySelectorAll('.positional-attr-options-action-button[data-options-action]').forEach(button => { + button.addEventListener('click', () => {this.actionButtonInOptionSectionHandler(button.dataset.optionsAction);}); + }); + document.querySelectorAll('.incidence-modifier-selection[data-incidence-modifier]').forEach(button => { + button.addEventListener('click', () => {this.incidenceModifierHandler(button);}); + }); + document.querySelectorAll('.n-m-submit-button').forEach(button => { + button.addEventListener('click', () => { + this.nmSubmitHandler(button.dataset.modalId); + }); + }); + + // Eventlistener for kind of token this.elements.tokenSubmitButton.addEventListener('click', () => {this.addTokenToQuery();}); this.elements.wordInput.addEventListener('input', () => {this.optionToggleHandler();}); this.elements.lemmaInput.addEventListener('input', () => {this.optionToggleHandler();}); @@ -119,7 +149,7 @@ class TokenAttributeBuilderFunctionsQueryBuilder extends GeneralFunctionsQueryBu this.disableTokenSubmit(); } else { tokenQueryPrettyText += `simple_pos=${this.elements.simplePosSelection.value}`; - tokenQueryCQLText += `simple_pos="${this.elements.simplePosSelection.value}"`; + tokenQueryCQLText += `simple_pos='${this.elements.simplePosSelection.value}'`; this.elements.simplePosSelection.value = ''; } break; @@ -149,7 +179,7 @@ class TokenAttributeBuilderFunctionsQueryBuilder extends GeneralFunctionsQueryBu input.setSelectionRange(firstIndex, lastIndex); break; case 'wildcard-char': - input.value += '.'; + input.value += '.'; break; case 'and': this.conditionHandler('and', " & "); @@ -195,7 +225,8 @@ class TokenAttributeBuilderFunctionsQueryBuilder extends GeneralFunctionsQueryBu nmSubmitHandler(modalId) { let modal = document.querySelector(`#${modalId}`); let input_n = modal.querySelector('.n-m-input[data-value-type="n"]').value; - let input_m = modalId === 'corpus-analysis-concordance-between-nm-modal' ? ',' + modal.querySelector('.n-m-input[data-value-type="m"]').value : ''; + let input_m = modal.querySelector('.n-m-input[data-value-type="m"]') || undefined; + input_m = input_m !== undefined ? ',' + input_m.value : ''; let input = `${input_n}${input_m}`; let instance = M.Modal.getInstance(modal); diff --git a/app/templates/corpora/_analysis/query_builder/_expert_mode.html.j2 b/app/templates/corpora/_analysis/query_builder/_expert_mode.html.j2 index d6b112eb..f0a1133e 100644 --- a/app/templates/corpora/_analysis/query_builder/_expert_mode.html.j2 +++ b/app/templates/corpora/_analysis/query_builder/_expert_mode.html.j2 @@ -1,6 +1,6 @@ {% macro card_content(id_prefix) %}
-
+
search diff --git a/app/templates/corpora/_analysis/query_builder/_query_builder.html.j2 b/app/templates/corpora/_analysis/query_builder/_query_builder.html.j2 index 21a13f0d..d6452358 100644 --- a/app/templates/corpora/_analysis/query_builder/_query_builder.html.j2 +++ b/app/templates/corpora/_analysis/query_builder/_query_builder.html.j2 @@ -1,8 +1,8 @@ {% macro card_content(id_prefix) %} - +
-
@@ -42,6 +43,14 @@
+ + + +{{ exactly_n_modal_content("token") }} +{{ exactly_nm_modal_content("token") }} + {% endmacro %} {% macro structural_attribute_modal(id_prefix) %} @@ -63,10 +72,10 @@


- Add Entity of any type + Add Entity of any type

- @@ -90,7 +99,7 @@
- @@ -347,10 +356,10 @@

-
+ -
- +
+
+{% endmacro %} -