diff --git a/app/static/js/corpus-analysis/query-builder/query-builder.js b/app/static/js/corpus-analysis/query-builder/query-builder.js index 702037f7..300ed8d4 100644 --- a/app/static/js/corpus-analysis/query-builder/query-builder.js +++ b/app/static/js/corpus-analysis/query-builder/query-builder.js @@ -7,13 +7,21 @@ nopaque.corpus_analysis.query_builder.QueryBuilder = class QueryBuilder { this.addEventListenersToNAndMInputSubmit(); this.elements.deleteQueryButton.addEventListener('click', () => {this.resetQueryInputField()}); - this.expertModeQueryBuilderSwitchHandler(); this.extensions = { structuralAttributeBuilderFunctions: new nopaque.corpus_analysis.query_builder.StructuralAttributeBuilderFunctions(this), tokenAttributeBuilderFunctions: new nopaque.corpus_analysis.query_builder.TokenAttributeBuilderFunctions(this), }; + + this.dropdown = M.Dropdown.init( + document.querySelector('.dropdown-trigger[data-toggle-area="token-incidence-modifiers"]'), + { + onCloseStart: () => { + this.unselectChipElement(this.elements.queryInputField.querySelector('.chip.teal')); + } + } + ) } addEventListenersToQueryElementTarget() { @@ -108,7 +116,7 @@ nopaque.corpus_analysis.query_builder.QueryBuilder = class QueryBuilder { prettyQueryText = nopaque.Utils.escape(prettyQueryText); let queryChipElement = nopaque.Utils.HTMLToElement( ` - + ${prettyQueryText}${isEditable ? 'edit': ''} ${isClosingTag ? '' : 'close'} @@ -152,8 +160,6 @@ nopaque.corpus_analysis.query_builder.QueryBuilder = class QueryBuilder { this.deleteChipElement(queryChipElement); } else if (event.target.dataset.chipAction === 'edit') { this.editChipElement(queryChipElement); - } else if (event.target.dataset.chipAction === 'lock') { - this.lockClosingChipElement(queryChipElement); } }); }); @@ -292,24 +298,36 @@ nopaque.corpus_analysis.query_builder.QueryBuilder = class QueryBuilder { } selectChipElement(attr) { - document.querySelectorAll('.chip.teal').forEach(element => { - if (element !== attr) { - element.classList.remove('teal', 'lighten-2'); - this.toggleClass(['token-incidence-modifiers'], 'disabled', 'add'); - } - }); + if (attr.classList.contains('teal')) { + return; + } this.toggleClass(['token-incidence-modifiers'], 'disabled', 'toggle'); attr.classList.toggle('teal'); attr.classList.toggle('lighten-5'); + + M.Dropdown.getInstance(document.querySelector('.dropdown-trigger[data-toggle-area="token-incidence-modifiers"]')).open(); + } - tokenIncidenceModifierHandler(incidenceModifier, incidenceModifierPretty) { + unselectChipElement(attr) { + let nModalInstance = M.Modal.getInstance(document.querySelector('#corpus-analysis-concordance-exactly-n-token-modal')); + let nmModalInstance = M.Modal.getInstance(document.querySelector('#corpus-analysis-concordance-between-nm-token-modal')); + if (nModalInstance.isOpen || nmModalInstance.isOpen) { + return; + } + attr.classList.remove('teal', 'lighten-5'); + this.toggleClass(['token-incidence-modifiers'], 'disabled', 'add'); + } + + tokenIncidenceModifierHandler(incidenceModifier, incidenceModifierPretty, nOrNM = false) { // Adds a token incidence modifier to the query input field. let selectedChip = this.elements.queryInputField.querySelector('.chip.teal'); let selectedChipIndex = Array.from(this.elements.queryChipElements).indexOf(selectedChip); + if (nOrNM) { + this.unselectChipElement(selectedChip); + } this.submitQueryChipElement('token-incidence-modifier', incidenceModifierPretty, incidenceModifier, selectedChipIndex); - this.selectChipElement(selectedChip); } tokenNMSubmitHandler(modalId) { @@ -327,7 +345,7 @@ nopaque.corpus_analysis.query_builder.QueryBuilder = class QueryBuilder { let instance = M.Modal.getInstance(modal); instance.close(); - this.tokenIncidenceModifierHandler(input, pretty_input); + this.tokenIncidenceModifierHandler(input, pretty_input, true); } expertModeQueryBuilderSwitchHandler() { @@ -368,15 +386,13 @@ nopaque.corpus_analysis.query_builder.QueryBuilder = class QueryBuilder { this.resetQueryInputField(); let expertModeInputFieldValue = document.querySelector('#corpus-analysis-concordance-form-query').value; let chipElements = this.parseTextToChip(expertModeInputFieldValue); - let closingTagElements = ['end-sentence', 'end-entity']; let editableElements = ['start-entity', 'token']; for (let chipElement of chipElements) { - let isClosingTag = closingTagElements.includes(chipElement['type']); let isEditable = editableElements.includes(chipElement['type']); if (chipElement['query'] === '[]'){ isEditable = false; } - this.submitQueryChipElement(chipElement['type'], chipElement['pretty'], chipElement['query'], null, isClosingTag, isEditable); + this.submitQueryChipElement(chipElement['type'], chipElement['pretty'], chipElement['query'], null, false, isEditable); } } diff --git a/app/static/js/corpus-analysis/query-builder/token-attribute-builder-functions.js b/app/static/js/corpus-analysis/query-builder/token-attribute-builder-functions.js index 02a23f0e..1d813bca 100644 --- a/app/static/js/corpus-analysis/query-builder/token-attribute-builder-functions.js +++ b/app/static/js/corpus-analysis/query-builder/token-attribute-builder-functions.js @@ -52,14 +52,14 @@ nopaque.corpus_analysis.query_builder.TokenAttributeBuilderFunctions = class Tok let input = this.tokenInputCheck(this.elements.tokenBuilderContent); switch (elem) { case 'option-group': - input.value += '(option1|option2)'; + this.cursorPositionInputfieldHandler(input, '(option1|option2)'); let firstIndex = input.value.indexOf('option1'); let lastIndex = firstIndex + 'option1'.length; - input.focus(); input.setSelectionRange(firstIndex, lastIndex); break; case 'wildcard-char': - input.value += '.'; + this.cursorPositionInputfieldHandler(input, '.'); + input.focus(); break; case 'and': this.conditionHandler('and'); @@ -73,9 +73,19 @@ nopaque.corpus_analysis.query_builder.TokenAttributeBuilderFunctions = class Tok this.optionToggleHandler(); } + cursorPositionInputfieldHandler(input, addedInput) { + let cursorPosition = input.selectionStart; + let textBeforeCursor = input.value.substring(0, cursorPosition); + let textAfterCursor = input.value.substring(cursorPosition); + let newInputValue = textBeforeCursor + addedInput + textAfterCursor; + input.value = newInputValue; + let newCursorPosition = cursorPosition + addedInput.length; + input.setSelectionRange(newCursorPosition, newCursorPosition); + } + characterIncidenceModifierHandler(elem) { let input = this.tokenInputCheck(this.elements.tokenBuilderContent); - input.value += elem.dataset.token; + this.cursorPositionInputfieldHandler(input, elem.dataset.token); } characterNMSubmitHandler(modalId) { @@ -83,12 +93,12 @@ nopaque.corpus_analysis.query_builder.TokenAttributeBuilderFunctions = class Tok let input_n = modal.querySelector('.n-m-input[data-value-type="n"]').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 addedInput = `${input_n}${input_m}`; let instance = M.Modal.getInstance(modal); instance.close(); - let tokenInput = this.tokenInputCheck(this.elements.tokenBuilderContent); - tokenInput.value += '{' + input + '}'; + let input = this.tokenInputCheck(this.elements.tokenBuilderContent); + this.cursorPositionInputfieldHandler(input, `{${addedInput}}`); } conditionHandler(conditionText) {